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)
82 host_labels = hostsconf.get_labels(node)
84 hostvars[node]['labels'] = host_labels
86 hostvars[node]['ssl_alt_name'] = {}
88 hostvars[node]['ssl_alt_name']['dns'] = dns
90 ips.append(hostvars[node]['ansible_host'])
91 hostvars[node]['ssl_alt_name']['ip'] = ips
93 caasconf = self.confman.get_caas_config_handler()
94 hostvars[node]['system_reserved_memory'] = hostsconf.get_system_reserved_memory(node)
95 hostvars[node]['caas_soft_eviction_threshold'] = caasconf.get_caas_soft_eviction_threshold()
96 hostvars[node]['caas_hard_eviction_threshold'] = caasconf.get_caas_hard_eviction_threshold()
98 def set_caas_master_data(self, hostvars, node, caasconf, hostsconf):
99 dns = hostvars[node]['ssl_alt_name']['dns']
100 dns.append(caasconf.get_kubernetes_domain())
101 dns.append(caasconf.get_apiserver_in_hosts())
102 dns.append(caasconf.get_registry_url())
103 dns.append(caasconf.get_update_registry_url())
104 dns.append(caasconf.get_swift_url())
105 dns.append(caasconf.get_swift_update_url())
106 dns.append(caasconf.get_ldap_master_url())
107 dns.append(caasconf.get_ldap_slave_url())
108 dns.append(caasconf.get_chart_repo_url())
109 dns.append(caasconf.get_caas_parameter('prometheus_url'))
110 dns.append(caasconf.get_tiller_url())
112 hosts = hostsconf.get_hosts()
114 if 'caas_master' in hostsconf.get_service_profiles(host):
117 hostvars[node]['ssl_alt_name']['dns'] = dns
118 ips = hostvars[node]['ssl_alt_name']['ip']
119 ips.append(caasconf.get_apiserver_svc_ip())
120 hostvars[node]['ssl_alt_name']['ip'] = ips
122 def generate_inventory(self):
126 # convert properties to inventory using the following rules:
127 # 1. cloud scoped configuration is mapped to "all" group's "vars" section
128 # 2. The host level domain configuration will be mapped to "_meta" section
129 # under "hostvars" group. Under this there will be a dictionary per host.
130 # 3. The mapping between hosts and profiles is created.
131 # This is used to allow ansible to automatically identify in which hosts
132 # the playbooks are to be run.
133 # This mapping is done as follows:
134 # - A mapping is created for each service profile.
135 # - A mapping is created for the network_profiles type.
136 # - A mapping is created for the storage_profiles type.
137 # - A mapping is created for the performance_profiles type.
139 # Get the host variables and all variables
143 netconf = self.confman.get_networking_config_handler()
144 hostsconf = self.confman.get_hosts_config_handler()
145 infra_internal_name = netconf.get_infra_internal_network_name()
146 hosts = hostsconf.get_hosts()
148 ownhost = self._get_own_host()
149 if self._is_bootstrapping():
152 hostsconf.disable_host(host)
154 hosts = hostsconf.get_enabled_hosts()
155 for name, value in self.props.iteritems():
164 if node not in hostvars:
166 hostip = netconf.get_host_ip(node, infra_internal_name)
167 hostvars[node]['ansible_host'] = hostip
170 hostvars[node][domain] = json.loads(value)
171 except Exception: # pylint: disable=broad-except
172 hostvars[node][domain] = value
174 if 'caas_master' in hostsconf.get_service_profiles(node):
175 self.set_common_caas(hostvars, node, hostsconf)
176 caasconf = self.confman.get_caas_config_handler()
177 self.set_caas_master_data(hostvars, node, caasconf, hostsconf)
178 self.set_default_route(hostvars, node, infra_internal_name)
180 if 'caas_worker' in hostsconf.get_service_profiles(node):
181 self.set_common_caas(hostvars, node, hostsconf)
182 self.set_default_route(hostvars, node, infra_internal_name)
185 allvars[domain] = json.loads(value)
186 except Exception: # pylint: disable=broad-except
187 allvars[domain] = value
189 except Exception: # pylint: disable=broad-except
192 inventory['_meta'] = {}
193 inventory['_meta']['hostvars'] = hostvars
194 inventory['all'] = {'vars': allvars}
196 # add hosts to service profiles mapping
197 serviceprofiles = profiles.Profiles().get_service_profiles()
198 for profile in serviceprofiles:
200 servicehosts = hostsconf.get_service_profile_hosts(profile)
202 for host in servicehosts:
205 inventory[profile] = tmp
206 except Exception: # pylint: disable=broad-except
209 # add mapping between profile types and hosts
210 inventory['network_profiles'] = []
211 inventory['storage_profiles'] = []
212 inventory['performance_profiles'] = []
214 # check for network profiles
216 _ = hostsconf.get_network_profiles(host)
217 inventory['network_profiles'].append(host)
218 except Exception: # pylint: disable=broad-except
221 # check for storage profiles
223 _ = hostsconf.get_storage_profiles(host)
224 inventory['storage_profiles'].append(host)
225 except Exception: # pylint: disable=broad-except
228 # check for perfromance profiles
230 _ = hostsconf.get_performance_profiles(host)
231 inventory['performance_profiles'].append(host)
232 except Exception: # pylint: disable=broad-except
235 self.pluginloader.load()
236 plugins = self.pluginloader.get_plugin_instances(self.confman, inventory, ownhost)
239 for name, plugin in sorted(plugins.iteritems()):
240 if self._is_bootstrapping():
241 plugin.handle_bootstrapping()
242 elif self._is_provisioning():
243 plugin.handle_provisioning()
244 elif self._is_setup():
245 plugin.handle_setup()
247 plugin.handle_postconfig()
251 except Exception as exp: # pylint: disable=broad-except
252 raise cmerror.CMError(str(exp))
255 class AnsibleInventoryPluginLoader(CMPluginLoader):
256 def __init__(self, plugin_location, plugin_filter=None):
257 super(AnsibleInventoryPluginLoader, self).__init__(plugin_location, plugin_filter)
259 def build_filter_dict(self):
262 def get_plugin_instances(self, confman, inventory, ownhost):
264 for plugin, module in self.loaded_plugin.iteritems():
265 class_name = getattr(module, plugin)
266 instance = class_name(confman, inventory, ownhost)
267 plugs[plugin] = instance
276 parser = argparse.ArgumentParser(description='Test ansible inventory handler', prog=sys.argv[0])
278 parser.add_argument('--properties',
281 metavar='PROPERTIES',
282 help='The file containing the properties',
286 parser.add_argument('--plugins',
290 help='The path to ansible inventory plugin(s)',
295 args = parser.parse_args(sys.argv[1:])
297 f = open(args.properties, 'r')
298 lines = f.read().splitlines()
305 properties[d[0]] = d[1]
306 ansible = AnsibleInventory(properties, args.plugins)
307 inventory = ansible.generate_inventory()
309 print(json.dumps(inventory, indent=4, sort_keys=True))
311 except Exception as exp: # pylint: disable=broad-except
313 traceback.print_exc()
318 if __name__ == '__main__':