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 if hostsconf.get_nodetype(node) == "caas-master":
83 hostvars[node]['noderole'] = "master"
84 elif hostsconf.get_nodetype(node) == "caas-worker":
85 hostvars[node]['noderole'] = "worker"
87 host_labels = hostsconf.get_labels(node)
89 hostvars[node]['labels'] = host_labels
91 hostvars[node]['ssl_alt_name'] = {}
93 hostvars[node]['ssl_alt_name']['dns'] = dns
95 ips.append(hostvars[node]['ansible_host'])
96 hostvars[node]['ssl_alt_name']['ip'] = ips
98 caasconf = self.confman.get_caas_config_handler()
99 hostvars[node]['system_reserved_memory'] = hostsconf.get_system_reserved_memory(node)
100 hostvars[node]['caas_soft_eviction_threshold'] = caasconf.get_caas_soft_eviction_threshold()
101 hostvars[node]['caas_hard_eviction_threshold'] = caasconf.get_caas_hard_eviction_threshold()
103 def set_caas_master_data(self, hostvars, node, caasconf, hostsconf):
104 dns = hostvars[node]['ssl_alt_name']['dns']
105 dns.append(caasconf.get_kubernetes_domain())
106 dns.append(caasconf.get_apiserver_in_hosts())
107 dns.append(caasconf.get_registry_url())
108 dns.append(caasconf.get_update_registry_url())
109 dns.append(caasconf.get_swift_url())
110 dns.append(caasconf.get_swift_update_url())
111 dns.append(caasconf.get_ldap_master_url())
112 dns.append(caasconf.get_ldap_slave_url())
113 dns.append(caasconf.get_chart_repo_url())
114 dns.append(caasconf.get_caas_parameter('prometheus_url'))
115 dns.append(caasconf.get_tiller_url())
117 hosts = hostsconf.get_hosts()
119 if 'caas_master' in hostsconf.get_service_profiles(host):
122 hostvars[node]['ssl_alt_name']['dns'] = dns
123 ips = hostvars[node]['ssl_alt_name']['ip']
124 ips.append(caasconf.get_apiserver_svc_ip())
125 hostvars[node]['ssl_alt_name']['ip'] = ips
127 def generate_inventory(self):
131 # convert properties to inventory using the following rules:
132 # 1. cloud scoped configuration is mapped to "all" group's "vars" section
133 # 2. The host level domain configuration will be mapped to "_meta" section
134 # under "hostvars" group. Under this there will be a dictionary per host.
135 # 3. The mapping between hosts and profiles is created.
136 # This is used to allow ansible to automatically identify in which hosts
137 # the playbooks are to be run.
138 # This mapping is done as follows:
139 # - A mapping is created for each service profile.
140 # - A mapping is created for the network_profiles type.
141 # - A mapping is created for the storage_profiles type.
142 # - A mapping is created for the performance_profiles type.
144 # Get the host variables and all variables
148 netconf = self.confman.get_networking_config_handler()
149 hostsconf = self.confman.get_hosts_config_handler()
150 infra_internal_name = netconf.get_infra_internal_network_name()
151 hosts = hostsconf.get_hosts()
153 ownhost = self._get_own_host()
154 if self._is_bootstrapping():
157 hostsconf.disable_host(host)
159 hosts = hostsconf.get_enabled_hosts()
160 for name, value in self.props.iteritems():
169 if node not in hostvars:
171 hostip = netconf.get_host_ip(node, infra_internal_name)
172 hostvars[node]['ansible_host'] = hostip
175 hostvars[node][domain] = json.loads(value)
176 except Exception: # pylint: disable=broad-except
177 hostvars[node][domain] = value
179 if 'caas_master' in hostsconf.get_service_profiles(node):
180 self.set_common_caas(hostvars, node, hostsconf)
181 caasconf = self.confman.get_caas_config_handler()
182 self.set_caas_master_data(hostvars, node, caasconf, hostsconf)
183 self.set_default_route(hostvars, node, infra_internal_name)
185 if 'caas_worker' in hostsconf.get_service_profiles(node):
186 self.set_common_caas(hostvars, node, hostsconf)
187 self.set_default_route(hostvars, node, infra_internal_name)
190 allvars[domain] = json.loads(value)
191 except Exception: # pylint: disable=broad-except
192 allvars[domain] = value
194 except Exception: # pylint: disable=broad-except
197 inventory['_meta'] = {}
198 inventory['_meta']['hostvars'] = hostvars
199 inventory['all'] = {'vars': allvars}
201 # add hosts to service profiles mapping
202 serviceprofiles = profiles.Profiles().get_service_profiles()
203 for profile in serviceprofiles:
205 servicehosts = hostsconf.get_service_profile_hosts(profile)
207 for host in servicehosts:
210 inventory[profile] = tmp
211 except Exception: # pylint: disable=broad-except
214 # add mapping between profile types and hosts
215 inventory['network_profiles'] = []
216 inventory['storage_profiles'] = []
217 inventory['performance_profiles'] = []
219 # check for network profiles
221 _ = hostsconf.get_network_profiles(host)
222 inventory['network_profiles'].append(host)
223 except Exception: # pylint: disable=broad-except
226 # check for storage profiles
228 _ = hostsconf.get_storage_profiles(host)
229 inventory['storage_profiles'].append(host)
230 except Exception: # pylint: disable=broad-except
233 # check for perfromance profiles
235 _ = hostsconf.get_performance_profiles(host)
236 inventory['performance_profiles'].append(host)
237 except Exception: # pylint: disable=broad-except
240 self.pluginloader.load()
241 plugins = self.pluginloader.get_plugin_instances(self.confman, inventory, ownhost)
244 for name, plugin in sorted(plugins.iteritems()):
245 if self._is_bootstrapping():
246 plugin.handle_bootstrapping()
247 elif self._is_provisioning():
248 plugin.handle_provisioning()
249 elif self._is_setup():
250 plugin.handle_setup()
252 plugin.handle_postconfig()
256 except Exception as exp: # pylint: disable=broad-except
257 raise cmerror.CMError(str(exp))
260 class AnsibleInventoryPluginLoader(CMPluginLoader):
261 def __init__(self, plugin_location, plugin_filter=None):
262 super(AnsibleInventoryPluginLoader, self).__init__(plugin_location, plugin_filter)
264 def build_filter_dict(self):
267 def get_plugin_instances(self, confman, inventory, ownhost):
269 for plugin, module in self.loaded_plugin.iteritems():
270 class_name = getattr(module, plugin)
271 instance = class_name(confman, inventory, ownhost)
272 plugs[plugin] = instance
281 parser = argparse.ArgumentParser(description='Test ansible inventory handler', prog=sys.argv[0])
283 parser.add_argument('--properties',
286 metavar='PROPERTIES',
287 help='The file containing the properties',
291 parser.add_argument('--plugins',
295 help='The path to ansible inventory plugin(s)',
300 args = parser.parse_args(sys.argv[1:])
302 f = open(args.properties, 'r')
303 lines = f.read().splitlines()
310 properties[d[0]] = d[1]
311 ansible = AnsibleInventory(properties, args.plugins)
312 inventory = ansible.generate_inventory()
314 print(json.dumps(inventory, indent=4, sort_keys=True))
316 except Exception as exp: # pylint: disable=broad-except
318 traceback.print_exc()
323 if __name__ == '__main__':