3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 from __future__ import print_function
18 from cmframework.apis import cmerror
19 from cmframework.utils.cmpluginloader import CMPluginLoader
20 from cmdatahandlers.api import configmanager
21 from cmdatahandlers.api import utils
22 from serviceprofiles import profiles
25 class AnsibleInventory(object):
27 def __init__(self, properties, plugin_path):
28 self.pluginloader = AnsibleInventoryPluginLoader(plugin_path)
29 self.props = properties
31 for name, value in properties.iteritems():
33 propsjson[name] = json.loads(value)
34 except Exception: # pylint: disable=broad-except
36 self.confman = configmanager.ConfigManager(propsjson)
38 # pylint: disable=no-self-use
40 if 'CONFIG_PHASE' in os.environ and os.environ['CONFIG_PHASE'] == 'setup':
44 def _is_bootstrapping(self):
45 if 'CONFIG_PHASE' in os.environ and os.environ['CONFIG_PHASE'] == 'bootstrapping':
49 def _is_provisioning(self):
50 if 'CONFIG_PHASE' in os.environ and os.environ['CONFIG_PHASE'] == 'provisioning':
54 def _is_postconfig(self):
55 if not self._is_bootstrapping() and not self._is_provisioning():
59 def _get_own_host(self):
61 hostsconf = self.confman.get_hosts_config_handler()
63 if utils.is_virtualized():
64 return hostsconf.get_installation_host()
66 hwmgmtip = utils.get_own_hwmgmt_ip()
68 return hostsconf.get_host_having_hwmgmt_address(hwmgmtip)
70 def set_default_route(self, hostvars, node, infra_internal_name):
71 routes = hostvars[node]['networking'][infra_internal_name].get('routes', [])
72 infra_int_ip = hostvars[node]['networking'][infra_internal_name]['ip']
73 caasconf = self.confman.get_caas_config_handler()
74 cidr_to_set = caasconf.get_caas_parameter("service_cluster_ip_cidr")
75 routes.append({"to": cidr_to_set, "via": infra_int_ip})
76 hostvars[node]['networking'][infra_internal_name]['routes'] = routes
78 def set_common_caas(self, hostvars, node, hostsconf):
79 hostvars[node]['nodetype'] = hostsconf.get_nodetype(node)
80 hostvars[node]['nodeindex'] = hostsconf.get_nodeindex(node)
81 hostvars[node]['nodename'] = hostsconf.get_nodename(node)
83 host_labels = hostsconf.get_labels(node)
85 hostvars[node]['labels'] = host_labels
87 hostvars[node]['ssl_alt_name'] = {}
89 hostvars[node]['ssl_alt_name']['dns'] = dns
91 ips.append(hostvars[node]['ansible_host'])
92 hostvars[node]['ssl_alt_name']['ip'] = ips
94 caasconf = self.confman.get_caas_config_handler()
95 hostvars[node]['system_reserved_memory'] = hostsconf.get_system_reserved_memory(node)
96 hostvars[node]['caas_soft_eviction_threshold'] = caasconf.get_caas_soft_eviction_threshold()
97 hostvars[node]['caas_hard_eviction_threshold'] = caasconf.get_caas_hard_eviction_threshold()
99 def set_caas_master_data(self, hostvars, node, caasconf, hostsconf):
100 dns = hostvars[node]['ssl_alt_name']['dns']
101 dns.append(caasconf.get_kubernetes_domain())
102 dns.append(caasconf.get_apiserver_in_hosts())
103 dns.append(caasconf.get_registry_url())
104 dns.append(caasconf.get_update_registry_url())
105 dns.append(caasconf.get_swift_url())
106 dns.append(caasconf.get_swift_update_url())
107 dns.append(caasconf.get_ldap_master_url())
108 dns.append(caasconf.get_ldap_slave_url())
109 dns.append(caasconf.get_chart_repo_url())
110 dns.append(caasconf.get_caas_parameter('prometheus_url'))
111 dns.append(caasconf.get_tiller_url())
113 hosts = hostsconf.get_hosts()
115 if 'caas_master' in hostsconf.get_service_profiles(host):
118 hostvars[node]['ssl_alt_name']['dns'] = dns
119 ips = hostvars[node]['ssl_alt_name']['ip']
120 ips.append(caasconf.get_apiserver_svc_ip())
121 hostvars[node]['ssl_alt_name']['ip'] = ips
123 def generate_inventory(self):
127 # convert properties to inventory using the following rules:
128 # 1. cloud scoped configuration is mapped to "all" group's "vars" section
129 # 2. The host level domain configuration will be mapped to "_meta" section
130 # under "hostvars" group. Under this there will be a dictionary per host.
131 # 3. The mapping between hosts and profiles is created.
132 # This is used to allow ansible to automatically identify in which hosts
133 # the playbooks are to be run.
134 # This mapping is done as follows:
135 # - A mapping is created for each service profile.
136 # - A mapping is created for the network_profiles type.
137 # - A mapping is created for the storage_profiles type.
138 # - A mapping is created for the performance_profiles type.
140 # Get the host variables and all variables
144 netconf = self.confman.get_networking_config_handler()
145 hostsconf = self.confman.get_hosts_config_handler()
146 infra_internal_name = netconf.get_infra_internal_network_name()
147 hosts = hostsconf.get_hosts()
149 ownhost = self._get_own_host()
150 if self._is_bootstrapping():
153 hostsconf.disable_host(host)
155 hosts = hostsconf.get_enabled_hosts()
156 for name, value in self.props.iteritems():
165 if node not in hostvars:
167 hostip = netconf.get_host_ip(node, infra_internal_name)
168 hostvars[node]['ansible_host'] = hostip
171 hostvars[node][domain] = json.loads(value)
172 except Exception: # pylint: disable=broad-except
173 hostvars[node][domain] = value
175 if 'caas_master' in hostsconf.get_service_profiles(node):
176 self.set_common_caas(hostvars, node, hostsconf)
177 caasconf = self.confman.get_caas_config_handler()
178 self.set_caas_master_data(hostvars, node, caasconf, hostsconf)
179 self.set_default_route(hostvars, node, infra_internal_name)
181 if 'caas_worker' in hostsconf.get_service_profiles(node):
182 self.set_common_caas(hostvars, node, hostsconf)
183 self.set_default_route(hostvars, node, infra_internal_name)
186 allvars[domain] = json.loads(value)
187 except Exception: # pylint: disable=broad-except
188 allvars[domain] = value
190 except Exception: # pylint: disable=broad-except
193 inventory['_meta'] = {}
194 inventory['_meta']['hostvars'] = hostvars
195 inventory['all'] = {'vars': allvars}
197 # add hosts to service profiles mapping
198 serviceprofiles = profiles.Profiles().get_service_profiles()
199 for profile in serviceprofiles:
201 servicehosts = hostsconf.get_service_profile_hosts(profile)
203 for host in servicehosts:
206 inventory[profile] = tmp
207 except Exception: # pylint: disable=broad-except
210 # add mapping between profile types and hosts
211 inventory['network_profiles'] = []
212 inventory['storage_profiles'] = []
213 inventory['performance_profiles'] = []
215 # check for network profiles
217 _ = hostsconf.get_network_profiles(host)
218 inventory['network_profiles'].append(host)
219 except Exception: # pylint: disable=broad-except
222 # check for storage profiles
224 _ = hostsconf.get_storage_profiles(host)
225 inventory['storage_profiles'].append(host)
226 except Exception: # pylint: disable=broad-except
229 # check for perfromance profiles
231 _ = hostsconf.get_performance_profiles(host)
232 inventory['performance_profiles'].append(host)
233 except Exception: # pylint: disable=broad-except
236 self.pluginloader.load()
237 plugins = self.pluginloader.get_plugin_instances(self.confman, inventory, ownhost)
240 for name, plugin in sorted(plugins.iteritems()):
241 if self._is_bootstrapping():
242 plugin.handle_bootstrapping()
243 elif self._is_provisioning():
244 plugin.handle_provisioning()
245 elif self._is_setup():
246 plugin.handle_setup()
248 plugin.handle_postconfig()
252 except Exception as exp: # pylint: disable=broad-except
253 raise cmerror.CMError(str(exp))
256 class AnsibleInventoryPluginLoader(CMPluginLoader):
257 def __init__(self, plugin_location, plugin_filter=None):
258 super(AnsibleInventoryPluginLoader, self).__init__(plugin_location, plugin_filter)
260 def build_filter_dict(self):
263 def get_plugin_instances(self, confman, inventory, ownhost):
265 for plugin, module in self.loaded_plugin.iteritems():
266 class_name = getattr(module, plugin)
267 instance = class_name(confman, inventory, ownhost)
268 plugs[plugin] = instance
277 parser = argparse.ArgumentParser(description='Test ansible inventory handler', prog=sys.argv[0])
279 parser.add_argument('--properties',
282 metavar='PROPERTIES',
283 help='The file containing the properties',
287 parser.add_argument('--plugins',
291 help='The path to ansible inventory plugin(s)',
296 args = parser.parse_args(sys.argv[1:])
298 f = open(args.properties, 'r')
299 lines = f.read().splitlines()
306 properties[d[0]] = d[1]
307 ansible = AnsibleInventory(properties, args.plugins)
308 inventory = ansible.generate_inventory()
310 print(json.dumps(inventory, indent=4, sort_keys=True))
312 except Exception as exp: # pylint: disable=broad-except
314 traceback.print_exc()
319 if __name__ == '__main__':