def _parse_base_groups(self): # FIXME: refactor ungrouped = Group(name='ungrouped') all = Group(name='all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) active_group_name = 'ungrouped' for line in self.lines: if line.startswith("["): active_group_name = line.replace("[","").replace("]","").strip() if line.find(":vars") != -1 or line.find(":children") != -1: active_group_name = None else: new_group = self.groups[active_group_name] = Group(name=active_group_name) all.add_child_group(new_group) elif line.startswith("#") or line == '': pass elif active_group_name: tokens = shlex.split(line) if len(tokens) == 0: continue hostname = tokens[0] port = C.DEFAULT_REMOTE_PORT # Two cases to check: # 0. A hostname that contains a range pesudo-code and a port # 1. A hostname that contains just a port if (hostname.find("[") != -1 and hostname.find("]") != -1 and hostname.find(":") != -1 and (hostname.rindex("]") < hostname.rindex(":")) or (hostname.find("]") == -1 and hostname.find(":") != -1)): tokens2 = hostname.rsplit(":", 1) hostname = tokens2[0] port = tokens2[1] host = None _all_hosts = [] if hostname in self.hosts: host = self.hosts[hostname] _all_hosts.append(host) else: if detect_range(hostname): _hosts = expand_hostname_range(hostname) for _ in _hosts: host = Host(name=_, port=port) self.hosts[_] = host _all_hosts.append(host) else: host = Host(name=hostname, port=port) self.hosts[hostname] = host _all_hosts.append(host) if len(tokens) > 1: for t in tokens[1:]: (k,v) = t.split("=") host.set_variable(k,v) for _ in _all_hosts: self.groups[active_group_name].add_host(_)
def add_host(self, host_ip, add_to_root=True, group_list=[], var_list={}): """Add a host ip to the ansible host file This is a simple function to add hosts to add_to_root = Adds the host to the root group (unnamed) groups_list: List of groupnames where the host should appears. var_list: Variable list. see allowed_variables.""" #root group in unnamed, but in the inventory object # is the 'ungrouped' group self.__dirty = True new_host = Host(host_ip) for key,value in var_list.iteritems(): if self.is_allowed_variable(key): new_host.set_variable(key,value) if add_to_root: if 'ungrouped' not in group_list: group_list.append('ungrouped') #Check groups. The ansible inventory should contain each of the groups. for group in group_list: if not self.__inventory.get_group(group): new_group= Group(group) self.__inventory.add_group(new_group) grp = self.__inventory.get_group(group) host_names = [host.name for host in grp.get_hosts()] if new_host.name not in host_names: grp.add_host(new_host)
def test_serialize_then_deserialize(self): group = Group('some_group') self.hostA.add_group(group) hostA_data = self.hostA.serialize() hostA_clone = Host() hostA_clone.deserialize(hostA_data) self.assertEquals(self.hostA, hostA_clone)
def _create_implicit_localhost(self, pattern): new_host = Host(pattern) new_host.set_variable("ansible_python_interpreter", sys.executable) new_host.set_variable("ansible_connection", "local") ungrouped = self.get_group("ungrouped") if ungrouped is None: self.add_group(Group('ungrouped')) ungrouped = self.get_group('ungrouped') ungrouped.add_host(new_host) return new_host
def _create_implicit_localhost(self, pattern): # 如果pattern不在all礼拜中,则创建新的local Host,并添加到ungrouped组(没有则创建),然后返回Host对象 new_host = Host(pattern) new_host.set_variable("ansible_python_interpreter", sys.executable) new_host.set_variable("ansible_connection", "local") ungrouped = self.get_group("ungrouped") if ungrouped is None: self.add_group(Group('ungrouped')) ungrouped = self.get_group('ungrouped') self.get_group('all').add_child_group(ungrouped) ungrouped.add_host(new_host) return new_host
def _create_implicit_localhost(self, pattern): if self.localhost: new_host = self.localhost else: new_host = Host(pattern) # use 'all' vars but not part of all group new_host.vars = self.groups['all'].get_vars() new_host.address = "127.0.0.1" new_host.implicit = True if "ansible_python_interpreter" not in new_host.vars: py_interp = sys.executable if not py_interp: # sys.executable is not set in some cornercases. #13585 py_interp = '/usr/bin/python' display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default. ' 'You can correct this by setting ansible_python_interpreter for localhost') new_host.set_variable("ansible_python_interpreter", py_interp) if "ansible_connection" not in new_host.vars: new_host.set_variable("ansible_connection", 'local') self.localhost = new_host return new_host
def _add_host(self, host_info, iterator): ''' Helper function to add a new host to inventory based on a task result. ''' host_name = host_info.get('host_name') # Check if host in inventory, add if not new_host = self._inventory.get_host(host_name) if not new_host: new_host = Host(name=host_name) self._inventory._hosts_cache[host_name] = new_host self._inventory.get_host_vars(new_host) allgroup = self._inventory.get_group('all') allgroup.add_host(new_host) # Set/update the vars for this host new_host.vars = combine_vars(new_host.vars, self._inventory.get_host_vars(new_host)) new_host.vars = combine_vars(new_host.vars, host_info.get('host_vars', dict())) new_groups = host_info.get('groups', []) for group_name in new_groups: if not self._inventory.get_group(group_name): new_group = Group(group_name) self._inventory.add_group(new_group) self._inventory.get_group_vars(new_group) new_group.vars = self._inventory.get_group_variables(group_name) else: new_group = self._inventory.get_group(group_name) new_group.add_host(new_host) # add this host to the group cache if self._inventory.groups is not None: if group_name in self._inventory.groups: if new_host not in self._inventory.get_group(group_name).hosts: self._inventory.get_group(group_name).hosts.append(new_host.name) # clear pattern caching completely since it's unpredictable what # patterns may have referenced the group self._inventory.clear_pattern_cache() # clear cache of group dict, which is used in magic host variables self._inventory.clear_group_dict_cache() # also clear the hostvar cache entry for the given play, so that # the new hosts are available if hostvars are referenced self._variable_manager.invalidate_hostvars_cache(play=iterator._play)
def _add_host(self, host_info): ''' Helper function to add a new host to inventory based on a task result. ''' host_name = host_info.get('host_name') # Check if host in cache, add if not if host_name in self._inventory._hosts_cache: new_host = self._inventory._hosts_cache[host_name] else: new_host = Host(name=host_name) self._inventory._hosts_cache[host_name] = new_host allgroup = self._inventory.get_group('all') allgroup.add_host(new_host) # Set/update the vars for this host # FIXME: probably should have a set vars method for the host? new_vars = host_info.get('host_vars', dict()) new_host.vars = self._inventory.get_host_vars(new_host) new_host.vars.update(new_vars) new_groups = host_info.get('groups', []) for group_name in new_groups: if not self._inventory.get_group(group_name): new_group = Group(group_name) self._inventory.add_group(new_group) new_group.vars = self._inventory.get_group_variables(group_name) else: new_group = self._inventory.get_group(group_name) new_group.add_host(new_host) # add this host to the group cache if self._inventory.groups is not None: if group_name in self._inventory.groups: if new_host not in self._inventory.get_group(group_name).hosts: self._inventory.get_group(group_name).hosts.append(new_host.name) # clear pattern caching completely since it's unpredictable what # patterns may have referenced the group # FIXME: is this still required? self._inventory.clear_pattern_cache()
class TestHostWithPort(TestHost): ansible_port = 8822 def setUp(self): self.hostA = Host(name='a', port=self.ansible_port) self.hostB = Host(name='b', port=self.ansible_port) def test_get_vars_ansible_port(self): host_vars = self.hostA.get_vars() self.assertEquals(host_vars['ansible_port'], self.ansible_port)
def _create_implicit_localhost(self, pattern): new_host = Host(pattern) new_host.address = "127.0.0.1" new_host.vars = self.get_host_vars(new_host) new_host.set_variable("ansible_connection", "local") if "ansible_python_interpreter" not in new_host.vars: new_host.set_variable("ansible_python_interpreter", sys.executable) self.get_group("ungrouped").add_host(new_host) return new_host
def __init__(self, vars_manager, play, inventory, loader): self._lookup = {} self._loader = loader # temporarily remove the inventory filter restriction # so we can compile the variables for all of the hosts # in inventory restriction = inventory._restriction inventory.remove_restriction() hosts = inventory.get_hosts(ignore_limits_and_restrictions=True) inventory.restrict_to_hosts(restriction) # check to see if localhost is in the hosts list, as we # may have it referenced via hostvars but if created implicitly # it doesn't sow up in the hosts list has_localhost = False for host in hosts: if host.name in C.LOCALHOST: has_localhost = True break # we don't use the method in inventory to create the implicit host, # because it also adds it to the 'ungrouped' group, and we want to # avoid any side-effects if not has_localhost: new_host = Host(name='localhost') new_host.set_variable("ansible_python_interpreter", sys.executable) new_host.set_variable("ansible_connection", "local") new_host.ipv4_address = '127.0.0.1' hosts.append(new_host) for host in hosts: self._lookup[host.name] = vars_manager.get_vars(loader=loader, play=play, host=host, include_hostvars=False)
def _parse_base_groups(self): ungrouped = Group(name='ungrouped') all = Group(name='all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) active_group_name = 'ungrouped' for line in self.lines: if line.startswith("["): active_group_name = line.replace("[","").replace("]","").strip() if line.find(":vars") != -1 or line.find(":children") != -1: active_group_name = None else: new_group = self.groups[active_group_name] = Group(name=active_group_name) all.add_child_group(new_group) elif line.startswith("#") or line == '': pass elif active_group_name: tokens = line.split() if len(tokens) == 0: continue hostname = tokens[0] port = C.DEFAULT_REMOTE_PORT if hostname.find(":") != -1: tokens2 = hostname.split(":") hostname = tokens2[0] port = tokens2[1] host = None if hostname in self.hosts: host = self.hosts[hostname] else: host = Host(name=hostname, port=port) self.hosts[hostname] = host if len(tokens) > 1: for t in tokens[1:]: (k,v) = t.split("=") host.set_variable(k,v) self.groups[active_group_name].add_host(host)
def __init__(self, play, inventory, variable_manager, loader): self._lookup = dict() self._loader = loader self._play = play self._variable_manager = variable_manager hosts = inventory.get_hosts(ignore_limits_and_restrictions=True) # check to see if localhost is in the hosts list, as we # may have it referenced via hostvars but if created implicitly # it doesn't sow up in the hosts list has_localhost = False for host in hosts: if host.name in C.LOCALHOST: has_localhost = True break if not has_localhost: new_host = Host(name='localhost') new_host.set_variable("ansible_python_interpreter", sys.executable) new_host.set_variable("ansible_connection", "local") new_host.address = '127.0.0.1' hosts.append(new_host) for host in hosts: self._lookup[host.name] = host
def run_module(hosts, module_name, args, **complex_args): import ansible.inventory pattern = "all" inventory = ansible.inventory.Inventory(',') all_group = inventory.get_group("all") from ansible.inventory.host import Host for h in hosts: host = Host(h["host"], h.get("port")) for key, value in h["settings"].iteritems(): host.set_variable(key, value) all_group.add_host(host) # в конструкторе кэш посчитался заранее inventory.clear_pattern_cache() # сам Ansible использует отдельный Runner для каждого действия в playbook, # так что вот готов отдельный кирпичик для системы развертывания import ansible.runner runner = ansible.runner.Runner( module_name=module_name, module_args=args, complex_args=complex_args, pattern=pattern, inventory=inventory, ) results = runner.run() # :COPY_N_PASTE_REALIZATION: bin/ansible if results['dark']: assert False, "Couldn't connect to %s" % results['dark'] total = 0 for result in results['contacted'].values(): if 'failed' in result or result.get('rc', 0) != 0: assert False, result total += 1 assert total == len(hosts), "The host was not connected to"
def add_host(self, host, group=None, port=None): ''' adds a host to inventory and possibly a group if not there already ''' if host: if not isinstance(host, string_types): raise AnsibleError( "Invalid host name supplied, expected a string but got %s for %s" % (type(host), host)) # TODO: add to_safe_host_name g = None if group: if group in self.groups: g = self.groups[group] else: raise AnsibleError("Could not find group %s in inventory" % group) if host not in self.hosts: h = Host(host, port) self.hosts[host] = h if self.current_source: # set to 'first source' in which host was encountered self.set_variable(host, 'inventory_file', self.current_source) self.set_variable(host, 'inventory_dir', basedir(self.current_source)) else: self.set_variable(host, 'inventory_file', None) self.set_variable(host, 'inventory_dir', None) display.debug("Added host %s to inventory" % (host)) # set default localhost from inventory to avoid creating an implicit one. Last localhost defined 'wins'. if host in C.LOCALHOST: if self.localhost is None: self.localhost = self.hosts[host] display.vvvv("Set default localhost to %s" % h) else: display.warning( "A duplicate localhost-like entry was found (%s). First found localhost was %s" % (h, self.localhost.name)) else: h = self.hosts[host] if g: g.add_host(h) self._groups_dict_cache = {} display.debug("Added host %s to group %s" % (host, group)) else: raise AnsibleError("Invalid empty host name provided: %s" % host) return host
def _create_implicit_localhost(self, pattern='localhost'): new_host = Host(pattern) new_host.address = "127.0.0.1" new_host.implicit = True new_host.vars = self.get_host_vars(new_host) new_host.set_variable("ansible_connection", "local") if "ansible_python_interpreter" not in new_host.vars: py_interp = sys.executable if not py_interp: # sys.executable is not set in some cornercases. #13585 display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default. You can correct this by setting ansible_python_interpreter for localhost') py_interp = '/usr/bin/python' new_host.set_variable("ansible_python_interpreter", py_interp) self.get_group("ungrouped").add_host(new_host) return new_host
def createplay(self, filename, hosts, taskid, username, password, sshLoginType, systemType, command): # action try: with open('/etc/ansible/{0}'.format(hosts), 'w') as f: f.writelines(hosts) except Exception as e: # logger.error("【错误】 ansible配置文件写入失败 -- mission.py line68") pass self.inventory = InventoryManager( loader=self.loader, sources='/etc/ansible/{0}'.format(hosts)) self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) if sshLoginType == 'ssh_key' and systemType == 'linux': command = "iptables-save" #重启防火墙命令 remote_command = command self.variable_manager.set_host_variable(Host(hosts, '22'), 'ansible_ssh_user', username) self.variable_manager.set_host_variable(Host(hosts, '22'), 'ansible_ssh_pass', password) play_source = dict( name="Ansible Play", hosts='all', gather_facts='no', tasks=[ dict(action=dict(module="command", args=remote_command)), dict(action=dict(module="command", args=command)), ]) self.play = Play.load(play_source, variable_manager=self.variable_manager, loader=self.loader) return self.play, self.variable_manager, self.inventory
def add_host(self, group, host): if isinstance(group, basestring): g = self.get_group(group) group = g is None and self.add_group(group) or g if host in [h.name for h in group.get_hosts()]: raise InventoryError('Host already in group %s: %s' % (group.name, host)) if isinstance(host, basestring): host = Host(host) self.log.debug('group %s: add host: %s' % (group.name, host.name)) group.add_host(host) return group
def add_dynamic_group(self, hosts, groupname, groupvars=None): """add new hosts to a group""" self.inventory.add_group(groupname) my_group = Group(name=groupname) # if group variables exists, add them to group if groupvars: for key in groupvars: my_group.set_variable(key, groupvars[key]) # add hosts to group for host in hosts: # set connection variables hostname = host.get("hostname") hostip = host.get('ip', hostname) hostport = host.get("port") username = host.get("username") password = host.get("password") ssh_key = host.get("ssh_key") my_host = Host(name=hostname, port=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_host', value=hostip) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_pass', value=password) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_port', value=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_user', value=username) self.variable_manager.set_host_variable( host=my_host, varname='ansible_ssh_private_key_file', value=ssh_key) # my_host.set_variable('ansible_ssh_pass', password) # my_host.set_variable('ansible_ssh_private_key_file', ssh_key) # set other variables for key in host: if key not in ["hostname", "port", "username", "password"]: self.variable_manager.set_host_variable(host=my_host, varname=key, value=host[key]) # add to group self.inventory.add_host(host=hostname, group=groupname, port=hostport)
def add_dynamic_group(self, hosts, groupname, groupvars=None): """ 将主机添加到对应主机组中 """ self.inventory.add_group(groupname) my_group = Group(name=groupname) # 判断是否有主机组变量 if groupvars: for key, value in groupvars.items(): my_group.set_variable(key, value) # add hosts to group for host in hosts: # set connection variables hostname = host.get("hostname") hostip = host.get('ip', hostname) hostport = host.get("port") username = host.get("username") password = host.get("password") ssh_key = host.get("ssh_key") my_host = Host(name=hostname, port=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_host', value=hostip) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_pass', value=password) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_port', value=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_user', value=username) self.variable_manager.set_host_variable( host=my_host, varname='ansible_ssh_private_key_file', value=ssh_key) # 判断是否还有除hostname,port,username,password之外的变量 for key, value in host.items(): if key not in ["hostname", "port", "username", "password"]: self.variable_manager.set_host_variable(host=my_host, varname=key, value=value) # 添加到指定主机组 self.inventory.add_host(host=hostname, group=groupname, port=hostport)
def _create_implicit_localhost(self, pattern): new_host = Host(pattern) new_host.set_variable("ansible_python_interpreter", sys.executable) new_host.set_variable("ansible_connection", "local") new_host.ipv4_address = '127.0.0.1' ungrouped = self.get_group("ungrouped") if ungrouped is None: self.add_group(Group('ungrouped')) ungrouped = self.get_group('ungrouped') self.get_group('all').add_child_group(ungrouped) ungrouped.add_host(new_host) return new_host
def parse_inventory(self, host_list): if isinstance(host_list, string_types): if "," in host_list: host_list = host_list.split(",") host_list = [ h for h in host_list if h and h.strip() ] self.parser = None # Always create the 'all' and 'ungrouped' groups, even if host_list is # empty: in this case we will subsequently an the implicit 'localhost' to it. ungrouped = Group(name='ungrouped') all = Group('all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) if host_list is None: pass elif isinstance(host_list, list): for h in host_list: (host, port) = parse_address(h, allow_ranges=False) all.add_host(Host(host, port)) elif self._loader.path_exists(host_list): #TODO: switch this to a plugin loader and a 'condition' per plugin on which it should be tried, restoring 'inventory pllugins' if self.is_directory(host_list): # Ensure basedir is inside the directory host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(loader=self._loader, groups=self.groups, filename=host_list) else: self.parser = get_file_parser(host_list, self.groups, self._loader) vars_loader.add_directory(self.basedir(), with_subdir=True) if not self.parser: # should never happen, but JIC raise AnsibleError("Unable to parse %s as an inventory source" % host_list) self._vars_plugins = [ x for x in vars_loader.all(self) ] # FIXME: shouldn't be required, since the group/host vars file # management will be done in VariableManager # get group vars from group_vars/ files and vars plugins for group in self.groups.values(): group.vars = combine_vars(group.vars, self.get_group_variables(group.name)) # get host vars from host_vars/ files and vars plugins for host in self.get_hosts(): host.vars = combine_vars(host.vars, self.get_host_variables(host.name))
def _create_implicit_localhost(self, pattern): if self.localhost: new_host = self.localhost else: new_host = Host(pattern) new_host.address = "127.0.0.1" new_host.implicit = True # set localhost defaults py_interp = sys.executable if not py_interp: # sys.executable is not set in some cornercases. see issue #13585 py_interp = '/usr/bin/python' display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default. ' 'You can correct this by setting ansible_python_interpreter for localhost') new_host.set_variable("ansible_python_interpreter", py_interp) new_host.set_variable("ansible_connection", 'local') new_host.set_variable("ansible_remote_tmp", C.DEFAULT_LOCAL_TMP) self.localhost = new_host return new_host
def _create_implicit_localhost(self, pattern): if self.localhost: new_host = self.localhost else: new_host = Host(pattern) new_host.address = "127.0.0.1" new_host.implicit = True new_host.vars = self.get_host_vars(new_host) new_host.set_variable("ansible_connection", "local") if "ansible_python_interpreter" not in new_host.vars: py_interp = sys.executable if not py_interp: # sys.executable is not set in some cornercases. #13585 display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default.' ' You can correct this by setting ansible_python_interpreter for localhost') py_interp = '/usr/bin/python' new_host.set_variable("ansible_python_interpreter", py_interp) self.get_group("ungrouped").add_host(new_host) self.localhost = new_host return new_host
def _parse(self, err): all_hosts = {} self.raw = utils.parse_json(self.data) all = Group('all') groups = dict(all=all) group = None if 'failed' in self.raw: sys.stderr.write(err + "\n") raise errors.AnsibleError( "failed to parse executable inventory script results: %s" % self.raw) for (group_name, data) in self.raw.items(): group = groups[group_name] = Group(group_name) host = None if not isinstance(data, dict): data = {'hosts': data} elif not any(k in data for k in ('hosts', 'vars')): data = {'hosts': [group_name], 'vars': data} if 'hosts' in data: for hostname in data['hosts']: if not hostname in all_hosts: all_hosts[hostname] = Host(hostname) host = all_hosts[hostname] group.add_host(host) if 'vars' in data: for k, v in data['vars'].iteritems(): if group.name == all.name: all.set_variable(k, v) else: group.set_variable(k, v) if group.name != all.name: all.add_child_group(group) # Separate loop to ensure all groups are defined for (group_name, data) in self.raw.items(): if isinstance(data, dict) and 'children' in data: for child_name in data['children']: if child_name in groups: groups[group_name].add_child_group(groups[child_name]) return groups
def _parse(self): groups = {} self.raw = utils.parse_json(self.data) all = Group('all') self.groups = dict(all=all) group = None for (group_name, hosts) in self.raw.items(): group = groups[group_name] = Group(group_name) host = None for hostname in hosts: host = Host(hostname) group.add_host(host) # FIXME: hack shouldn't be needed all.add_host(host) all.add_child_group(group) return groups
def find_running_task(self, alias, vars): task = self._task.copy() task.name = self._task.name + " - lookup existing job" task.args = {'alias': alias} task._ds = {"name": task.name, "async_status_id": {"alias": alias}} handler = self._shared_loader_obj.action_loader.get( 'async_status_id', task=task, connection=self._connection, play_context=self._play_context, loader=self._loader, templar=self._templar, shared_loader_obj=self._shared_loader_obj) result = handler.run(task_vars=vars) return self.v2_on_result(Host(), task, result)
def __init__(self, filename=C.DEFAULT_HOST_LIST): self.names = os.listdir(filename) self.names.sort() self.directory = filename self.parsers = [] self.hosts = {} self.groups = {} for i in self.names: if i.endswith("~") or i.endswith(".orig") or i.endswith(".bak"): continue if i.endswith(".ini"): # configuration file for an inventory script continue if i.endswith(".retry"): # this file is generated on a failed playbook and should only be # used when run specifically continue # These are things inside of an inventory basedir if i in ("host_vars", "group_vars", "vars_plugins"): continue fullpath = os.path.join(self.directory, i) if os.path.isdir(fullpath): parser = InventoryDirectory(filename=fullpath) elif utils.is_executable(fullpath): parser = InventoryScript(filename=fullpath) else: parser = InventoryParser(filename=fullpath) self.parsers.append(parser) # This takes a lot of code because we can't directly use any of the objects, as they have to blend for name, group in parser.groups.iteritems(): if name not in self.groups: self.groups[name] = Group(name) for k, v in group.get_variables().iteritems(): self.groups[name].set_variable(k, v) for host in group.get_hosts(): if host.name not in self.hosts: self.hosts[host.name] = Host(host.name) for k, v in host.vars.iteritems(): self.hosts[host.name].set_variable(k, v) self.groups[name].add_host(self.hosts[host.name]) # This needs to be a second loop to ensure all the parent groups exist for name, group in parser.groups.iteritems(): for ancestor in group.get_ancestors(): self.groups[ancestor.name].add_child_group( self.groups[name])
def execute(playbooks: list, context: dict): ''' ''' assert playbooks os.environ["ANSIBLE_CONDITIONAL_BARE_VARS"] = "False" # ctx._init_global_context({}) # since the API is constructed for CLI it expects certain options to always be set in the context object ctx.CLIARGS = ImmutableDict(connection='local', module_path=['./playbooks/roles'], forks=1, become=False, become_method="sudo", syntax=False, start_at_task=None, diff=False, verbosity=0) # initialize needed objects loader = DataLoader( ) # Takes care of finding and reading yaml, json and ini files # passwords = dict(become_pass="******") passwords = dict() # Instantiate our ResultCallback for handling results as they come in. Ansible expects this to be one of its main display outlets results_callback = ResultCallback() # create inventory, use path to host config file as source or hosts in a comma separated string inventory = InventoryManager(loader=loader, sources='localhost,') host = Host(name="localhost") # variable manager takes care of merging all the different sources to give you a unified view of variables available in each context variable_manager = VariableManager(loader=loader, inventory=inventory) variable_manager.set_host_variable(host, "current_directory", context.get("current_directory", "")) pbex = PlaybookExecutor(playbooks=playbooks, inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords) result = pbex.run() post_command = variable_manager.get_vars()["hostvars"]["localhost"].get( "mondrik_post_command") return result, post_command
def __init__(self): # Leverage the ansible python api # to run a playbook against a molecule host. # # see: ansible python api # https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html try: self._molecule_ephemeral_directory = \ Path(os.environ['MOLECULE_EPHEMERAL_DIRECTORY']) self._molecule_scenario_directory = \ Path(os.environ['MOLECULE_SCENARIO_DIRECTORY']) except KeyError: # return None if we can't access the molecule environment variables return None # create symlink in molecule ephemeral directory # to roles directory in project dir self._create_symlink_('roles') # use molecule managed inventory inventory_file = self._molecule_ephemeral_directory / \ 'inventory/ansible_inventory.yml' # FIXME: add TESTAID_EXTRA_VARS_FILES # inject extra_vars into ansible play with high weight self._extra_vars = dict() context.CLIARGS = ImmutableDict(connection='local', module_path=[''], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False) self._loader = DataLoader() self._inventory = InventoryManager(loader=self._loader, sources=str(inventory_file)) self._variable_manager = VariableManager(loader=self._loader, inventory=self._inventory) # use inventory host host = next(iter(self._inventory.hosts)) # create a Host object self._host = Host(name=host)
def autocreate_publickey(host_list, password, jobid): C.HOST_KEY_CHECKING = False loader = DataLoader() options = Options(connection='smart', forks=5, ssh_common_args='-C -o ControlPersist=30s') passwords = dict() if len(host_list) <= 1: sources = host_list[0] + ',' else: sources = ','.join(host_list) inventory = InventoryManager(loader=loader, sources=sources) variable_manager = VariableManager(loader=loader, inventory=inventory) for host in host_list: host_info = Host(name=host, port=22) variable_manager.set_host_variable(host_info, 'ansible_ssh_user', 'root') variable_manager.set_host_variable(host_info, 'ansible_ssh_pass', password) play_source = dict( name='Generate Publickey', hosts=host_list, gather_facts='no', tasks=[ dict(action=dict( module='authorized_key', args=dict(user='******', key="{{ lookup('file','/root/.ssh/id_rsa.pub') }}"))) ]) play = Play().load(play_source, variable_manager=variable_manager, loader=loader) tqm = None callback = ResultsCollector(jobid) try: tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords) tqm._stdout_callback = callback result = tqm.run(play) finally: if tqm is not None: tqm.cleanup() return callback.result
def _add_host(self, host_info): ''' Helper function to add a new host to inventory based on a task result. ''' host_name = host_info.get('host_name') # Check if host in cache, add if not if host_name in self._inventory._hosts_cache: new_host = self._inventory._hosts_cache[host_name] else: new_host = Host(name=host_name) self._inventory._hosts_cache[host_name] = new_host allgroup = self._inventory.get_group('all') allgroup.add_host(new_host) # Set/update the vars for this host # FIXME: probably should have a set vars method for the host? new_vars = host_info.get('host_vars', dict()) new_host.vars.update(new_vars) new_groups = host_info.get('groups', []) for group_name in new_groups: if not self._inventory.get_group(group_name): new_group = Group(group_name) self._inventory.add_group(new_group) new_group.vars = self._inventory.get_group_variables( group_name) else: new_group = self._inventory.get_group(group_name) new_group.add_host(new_host) # add this host to the group cache if self._inventory._groups_list is not None: if group_name in self._inventory._groups_list: if new_host.name not in self._inventory._groups_list[ group_name]: self._inventory._groups_list[group_name].append( new_host.name) # clear pattern caching completely since it's unpredictable what # patterns may have referenced the group # FIXME: is this still required? self._inventory.clear_pattern_cache()
def _Hosts(self, hostnames, port): ''' Takes a list of hostnames and a port (which may be None) and returns a list of Hosts (without recreating anything in self.hosts). ''' hosts = [] # Note that we decide whether or not to create a Host based solely on # the (non-)existence of its hostname in self.hosts. This means that one # cannot add both "foo:22" and "foo:23" to the inventory. for hn in hostnames: if hn not in self.hosts: self.hosts[hn] = Host(name=hn, port=port) hosts.append(self.hosts[hn]) return hosts
def add_host(self, host, port=None, user=None, passwd=None, private_file=None): h = Host(host, port) self.inventory.add_host(host, 'all', port) self.inventory.add_host(host, 'all', port) if user: self.variable_manager.set_host_variable(h, 'ansible_ssh_user', user) if passwd: self.variable_manager.set_host_variable(h, 'ansible_ssh_pass', passwd) if private_file: self.variable_manager.set_host_variable( h, 'ansible_ssh_private_key_file', private_file)
def parse_inventory(self, host_list): if isinstance(host_list, basestring): if "," in host_list: host_list = host_list.split(",") host_list = [ h for h in host_list if h and h.strip() ] self.parser = None if host_list is None: pass elif isinstance(host_list, list): all = Group('all') self.groups = [ all ] for h in host_list: (host, port) = parse_address(h, allow_ranges=False) all.add_host(Host(host, port)) elif self._loader.path_exists(host_list): #TODO: switch this to a plugin loader and a 'condition' per plugin on which it should be tried, restoring 'inventory pllugins' if self._loader.is_directory(host_list): # Ensure basedir is inside the directory host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(loader=self._loader, filename=host_list) else: self.parser = get_file_parser(host_list, self._loader) vars_loader.add_directory(self.basedir(), with_subdir=True) if self.parser: self.groups = self.parser.groups.values() else: # should never happen, but JIC raise AnsibleError("Unable to parse %s as an inventory source" % host_list) self._vars_plugins = [ x for x in vars_loader.all(self) ] # FIXME: shouldn't be required, since the group/host vars file # management will be done in VariableManager # get group vars from group_vars/ files and vars plugins for group in self.groups: group.vars = combine_vars(group.vars, self.get_group_variables(group.name)) # get host vars from host_vars/ files and vars plugins for host in self.get_hosts(): host.vars = combine_vars(host.vars, self.get_host_variables(host.name))
def _create_implicit_localhost(self, pattern): new_host = Host(pattern) new_host.set_variable("ansible_python_interpreter", sys.executable) new_host.set_variable("ansible_connection", "local") new_host.ipv4_address = "127.0.0.1" ungrouped = self.get_group("ungrouped") if ungrouped is None: self.add_group(Group("ungrouped")) ungrouped = self.get_group("ungrouped") self.get_group("all").add_child_group(ungrouped) ungrouped.add_host(new_host) return new_host
def my_add_group(self, hosts, groupname, groupvars=None): """ add hosts to a group """ self.add_group(groupname) group_dict = self.get_groups_dict() my_group = group_dict[groupname] # if group variables exists, add them to group if groupvars: for key in groupvars: value = groupvars.get(key) my_group.set_variable(key, value) # add hosts to group for host in hosts: # set connection variables host_ip = host.get('ip') host_port = '22' username = '******' if 'port' in host: host_port = host.get("port") if 'username' in host: username = host.get("username") password = host.get("password") my_host = Host(name=host_ip, port=host_port) my_host.set_variable('ansible_ssh_port', host_port) my_host.set_variable('ansible_ssh_user', username) my_host.set_variable('ansible_ssh_pass', password) self.add_host(host_ip, group=groupname, port=host_port) self._inventory.set_variable(host_ip, 'ansible_ssh_port', host_port) self._inventory.set_variable(host_ip, 'ansible_ssh_user', username) self._inventory.set_variable(host_ip, 'ansible_ssh_pass', password) # set other variables for key in host: if key not in ["hostname", "port", "username", "password"]: value = host.get(key) my_host.set_variable(key, value) self._inventory.set_variable(host_ip, key, value)
def add_dynamic_group(self, hosts, group_name, group_vars=None): self.inventory.add_group(group_name) my_group = Group(name=group_name) if group_vars is not None: for k, v in group_vars.items(): my_group.set_variable(k, v) for host in hosts: hostname = host.get("hostname") hostip = host.get("ip", hostname) hostport = host.get("port", 22) username = host.get("username") password = host.get("password") ssh_key = host.get("ssh_key", "~/.ssh/id_rsa") my_host = Host(name=hostname, port=hostport) self.variable_manager.set_host_variable(host=my_host, varname="ansible_ssh_host", value=hostip) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_pass', value=password) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_port', value=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_user', value=username) self.variable_manager.set_host_variable( host=my_host, varname='ansible_ssh_private_key_file', value=ssh_key) for key, value in host.items(): if key not in ["hostname", "port", "username", "password"]: self.variable_manager.set_host_variable(host=my_host, varname=key, value=value) self.inventory.add_host(host=hostname, group=group_name, port=hostport)
def add_dynamic_host(self, hosts_list): for hosts in hosts_list: hostname = hosts.get("hostname") hostip = hosts.get("ip", hostname) hostport = hosts.get("hostport") password = hosts.get("password") my_host = Host(name=hostname, port=hostport) # self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_host', value=hostip) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_pass', value=password) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_port', value=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_user', value=username)
def get_ansible_groups(group_map): """ Constructs a list of :class:`ansible.inventory.group.Group` objects from a map of lists of host strings. """ # Some of this logic is cribbed from # ansible.inventory.script.InventoryScript all_hosts = {} group_all = Group('all') groups = [group_all] for gname, hosts in group_map.iteritems(): g = Group(gname) for host in hosts: h = all_hosts.get(host, Host(host)) all_hosts[host] = h g.add_host(h) group_all.add_host(h) group_all.add_child_group(g) groups.append(g) return groups
def add_host(self, host, group=None, port=None): ''' adds a host to inventory and possibly a group if not there already ''' g = None if group: if group in self.groups: g = self.groups[group] else: raise AnsibleError("Could not find group %s in inventory" % group) if host not in self.hosts: h = Host(host, port) self.hosts[host] = h if self.current_source: # set to 'first source' in which host was encountered self.set_variable(host, 'inventory_file', os.path.basename(self.current_source)) self.set_variable(host, 'inventory_dir', basedir(self.current_source)) else: self.set_variable(host, 'inventory_file', None) self.set_variable(host, 'inventory_dir', None) display.debug("Added host %s to inventory" % (host)) # set default localhost from inventory to avoid creating an implicit one. Last localhost defined 'wins'. if host in C.LOCALHOST: if self.localhost is None: self.localhost = self.hosts[host] display.vvvv("Set default localhost to %s" % h) else: display.warning( "A duplicate localhost-like entry was found (%s). First found localhost was %s" % (h, self.localhost.name)) else: h = self.hosts[host] if g and h not in g.get_hosts(): g.add_host(h) self._groups_dict_cache = {} display.debug("Added host %s to group %s" % (host, group))
def reg_async_task(self, jid, alias, vars): task = self._task.copy() task.name = self._task.name + " - register async job" task.args = {'alias': alias, 'jid': jid} task._ds = { "name": task.name, "async_alias": { "alias": alias, "jid": jid } } handler = self._shared_loader_obj.action_loader.get( 'async_alias', task=task, connection=self._connection, play_context=self._play_context, loader=self._loader, templar=self._templar, shared_loader_obj=self._shared_loader_obj) result = handler.run(task_vars=vars) return self.v2_on_result(Host(), task, result)
def wait_async_task(self, alias, cleanup, retries, delay, vars): task = self._task.copy() task.name = self._task.name + " - wait async job" task.args = { 'alias': alias, 'cleanup': cleanup, 'retries': retries, 'delay': delay } task._ds = {"name": task.name, "async_wait": task.args.copy()} task.retries = retries task.delay = delay handler = self._shared_loader_obj.action_loader.get( 'async_wait', task=task, connection=self._connection, play_context=self._play_context, loader=self._loader, templar=self._templar, shared_loader_obj=self._shared_loader_obj) result = handler.run(task_vars=vars) return self.v2_on_result(Host(), task, result)
def add_dynamic_group(self, hosts, groupname, groupvars=None): """ add hosts to a group """ self.inventory.add_group(groupname) my_group = Group(name=groupname) # if group variables exists, add them to group if groupvars: for key, value in groupvars.iteritems(): my_group.set_variable(key, value) # add hosts to group for host in hosts: # set connection variables hostname = host.get("hostname") hostip = host.get('ip', hostname) hostport = host.get("port") my_host = Host(name=hostname, port=hostport) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_host', value=hostip) self.variable_manager.set_host_variable(host=my_host, varname='ansible_ssh_port', value=hostport) # set other variables for key, value in host.iteritems(): if key not in ["hostname", "port", "username", "password"]: self.variable_manager.set_host_variable(host=my_host, varname=key, value=value) # add to group self.inventory.add_host(host=hostname, group=groupname, port=hostport)
def _create_implicit_localhost(self, pattern): if self.localhost: new_host = self.localhost else: new_host = Host(pattern) new_host.address = "127.0.0.1" new_host.implicit = True # set localhost defaults py_interp = sys.executable if not py_interp: # sys.executable is not set in some cornercases. see issue #13585 py_interp = '/usr/bin/python' display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default. ' 'You can correct this by setting ansible_python_interpreter for localhost') new_host.set_variable("ansible_python_interpreter", py_interp) new_host.set_variable("ansible_connection", 'local') self.localhost = new_host return new_host
def _parse_base_groups(self): # FIXME: refactor ungrouped = Group(name='ungrouped') all = Group(name='all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) active_group_name = 'ungrouped' for line in self.lines: if line.startswith("["): active_group_name = line.split(" #")[0].replace("[","").replace("]","").strip() if line.find(":vars") != -1 or line.find(":children") != -1: active_group_name = active_group_name.rsplit(":", 1)[0] if active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) all.add_child_group(new_group) active_group_name = None elif active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) all.add_child_group(new_group) elif line.startswith("#") or line.startswith(";") or line == '': pass elif active_group_name: tokens = shlex.split(line.split(" #")[0]) if len(tokens) == 0: continue hostname = tokens[0] port = C.DEFAULT_REMOTE_PORT # Two cases to check: # 0. A hostname that contains a range pesudo-code and a port # 1. A hostname that contains just a port if (hostname.find("[") != -1 and hostname.find("]") != -1 and hostname.find(":") != -1 and (hostname.rindex("]") < hostname.rindex(":")) or (hostname.find("]") == -1 and hostname.find(":") != -1)): tokens2 = hostname.rsplit(":", 1) hostname = tokens2[0] port = tokens2[1] hostnames = [] if detect_range(hostname): hostnames = expand_hostname_range(hostname) else: hostnames = [hostname] for hn in hostnames: host = None if hn in self.hosts: host = self.hosts[hn] else: host = Host(name=hn, port=port) self.hosts[hn] = host if len(tokens) > 1: for t in tokens[1:]: if t.startswith('#'): break try: (k,v) = t.split("=") except ValueError, e: raise errors.AnsibleError("Invalid ini entry: %s - %s" % (t, str(e))) try: host.set_variable(k,ast.literal_eval(v)) except: # most likely a string that literal_eval # doesn't like, so just set it host.set_variable(k,v) self.groups[active_group_name].add_host(host)
def my_add_group(self, hosts, groupname, groupvars=None): """ add hosts to a group """ my_group = Group(name=groupname) # if group variables exists, add them to group if groupvars: for key, value in groupvars.iteritems(): my_group.set_variable(key, value) # add hosts to group for host in hosts: # set connection variables hostname = host.get("hostname") hostip = host.get('ip', hostname) hostport = host.get("port") username = host.get("username") password = host.get("password") ssh_key = host.get("ssh_key") my_host = Host(name=hostname, port=hostport) my_host.set_variable('ansible_ssh_host', hostip) my_host.set_variable('ansible_ssh_port', hostport) my_host.set_variable('ansible_ssh_user', username) my_host.set_variable('ansible_ssh_pass', password) my_host.set_variable('ansible_ssh_private_key_file', ssh_key) # set other variables for key, value in host.iteritems(): if key not in ["hostname", "port", "username", "password"]: my_host.set_variable(key, value) # add to group my_group.add_host(my_host) self.inventory.add_group(my_group)
def setUp(self): self.hostA = Host(name='a', port=self.ansible_port) self.hostB = Host(name='b', port=self.ansible_port)
def setUp(self): self.hostA = Host('a') self.hostB = Host('b')
class TestHost(unittest.TestCase): ansible_port = 22 def setUp(self): self.hostA = Host('a') self.hostB = Host('b') def test_equality(self): self.assertEqual(self.hostA, self.hostA) self.assertNotEqual(self.hostA, self.hostB) self.assertNotEqual(self.hostA, Host('a')) def test_hashability(self): # equality implies the hash values are the same self.assertEqual(hash(self.hostA), hash(Host('a'))) def test_get_vars(self): host_vars = self.hostA.get_vars() self.assertIsInstance(host_vars, dict) def test_repr(self): host_repr = repr(self.hostA) self.assertIsInstance(host_repr, string_types) def test_add_group(self): group = Group('some_group') group_len = len(self.hostA.groups) self.hostA.add_group(group) self.assertEqual(len(self.hostA.groups), group_len + 1) def test_get_groups(self): group = Group('some_group') self.hostA.add_group(group) groups = self.hostA.get_groups() self.assertEqual(len(groups), 1) for _group in groups: self.assertIsInstance(_group, Group) def test_equals_none(self): other = None self.hostA == other other == self.hostA self.hostA != other other != self.hostA self.assertNotEqual(self.hostA, other) def test_serialize(self): group = Group('some_group') self.hostA.add_group(group) data = self.hostA.serialize() self.assertIsInstance(data, dict) def test_serialize_then_deserialize(self): group = Group('some_group') self.hostA.add_group(group) hostA_data = self.hostA.serialize() hostA_clone = Host() hostA_clone.deserialize(hostA_data) self.assertEquals(self.hostA, hostA_clone) def test_set_state(self): group = Group('some_group') self.hostA.add_group(group) pickled_hostA = pickle.dumps(self.hostA) hostA_clone = pickle.loads(pickled_hostA) self.assertEquals(self.hostA, hostA_clone)
def my_add_group(self, hosts, groupname, groupvars=None): my_group = Group(name=groupname) if groupvars: for key, value in groupvars.iteritems(): my_group.set_variable(key, value) for host in hosts: hostname = host.get('hostname') hostip = host.get('ip', hostname) hostport = host.get('port', 22) username = host.get('username', 'root') password = host.get('password') ssh_key = host.get("ssh_key") my_host = Host(name=hostname, port=hostport) my_host.set_variable('ansible_ssh_host', hostip) my_host.set_variable('ansible_ssh_port', hostport) my_host.set_variable('ansible_ssh_user', username) my_host.set_variable('ansible_ssh_pass', password) my_host.set_variable('ansible_ssh_private_key_file', ssh_key) for key, value in host.iteritems(): if key not in ['hostname', 'port', 'username', 'password']: my_host.set_variable(key, value) my_group.add_host(my_host) self.inventory.add_group(my_group)
def _parse_base_groups(self): # FIXME: refactor,貌似在后面的版本中该函数会被重构 # 这部分解析ini配置文件的代码却是写的很臃肿,急需要重构 # 基础group解析,除了已经定义组名的group以外,还有ungrouped表示未分组的组名,all表示所有组的总和 ungrouped = Group(name='ungrouped') all = Group(name='all') all.add_child_group(ungrouped) # 喜欢这种dict创建字典的方式,比用{}的方式好看多了 self.groups = dict(all=all, ungrouped=ungrouped) active_group_name = 'ungrouped' # 遍历self.lines,self.lines是文件内容, # ini文件的解析大多可以用python内置的conparser类,不过ansible的inventory所支持的语法比较复杂,这里作者自己处理了 for lineno in range(len(self.lines)): line = utils.before_comment(self.lines[lineno]).strip() # 如果某行以'['开头,以']'结尾则表名是一个section if line.startswith("[") and line.endswith("]"): # 将中括号replace掉获得组名 active_group_name = line.replace("[","").replace("]","") # 如果组名中有:vars 或:children,则进行二次处理,比如[southeast:vars],在通过冒号分割得到southeast if ":vars" in line or ":children" in line: active_group_name = active_group_name.rsplit(":", 1)[0] # rsplit(":", 1)表示右边开始以冒号为分隔符分割一次 # 如果组名未加到self.groups里面,则创建一个新的Group类,并添加到self.groups里面 # 如果组名已经存在与self.groups里面,跳过... if active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) # 在这种情况下将active_group_name设置为None,用来表示这不是一个包含真正host的group active_group_name = None # 这部分是组名中没有冒号的处理方式,和上面一样。 elif active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) elif line.startswith(";") or line == '': # 如果改行以分号开始或为空行则跳过。 pass elif active_group_name: # 这种情况表示当前行为非中括号打头的行,既包含真实host主机数据的行 # 在section中包含:vars/:children的段并不包含真实主机 # shlex模块实现了一个类来解析简单的类shell语法,可以用来编写领域特定的语言,或者解析加引号的字符串。 tokens = shlex.split(line) if len(tokens) == 0: continue hostname = tokens[0] # 获取主机名 port = C.DEFAULT_REMOTE_PORT # 使用默认的SSH端口号 # Three cases to check: # 0. A hostname that contains a range pesudo-code and a port,like badwol[a:f].example.com:5309 # 1. A hostname that contains just a port ,like badwolf.example.com:5309 # 对hostname需要进行以下的检测 if hostname.count(":") > 1: # IPV6格式的地址,端口号和hostname之间用"."表示。 # Possible an IPv6 address, or maybe a host line with multiple ranges # IPv6 with Port XXX:XXX::XXX.port # FQDN foo.example.com if hostname.count(".") == 1: (hostname, port) = hostname.rsplit(".", 1) elif ("[" in hostname and "]" in hostname and ":" in hostname and (hostname.rindex("]") < hostname.rindex(":")) or ("]" not in hostname and ":" in hostname)): # 如果冒号在中括号外面,表示这个冒号后面是端口号,因此通过通过rsplit按照冒号分割一次获取端口号和hostname (hostname, port) = hostname.rsplit(":", 1) hostnames = [] # 检测hostname是否是表示一个范围的hosts,如果是则将其扩展成一组host列表,否则加入空列表 if detect_range(hostname): hostnames = expand_hostname_range(hostname) else: hostnames = [hostname] # 遍历hostnames列表 for hn in hostnames: host = None if hn in self.hosts: host = self.hosts[hn] else: # 如果host不在self.hosts列表中,则创建一个Host基类 host = Host(name=hn, port=port) self.hosts[hn] = host # len(tokens) > 1表示该行拥有变量,如:jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50 if len(tokens) > 1: for t in tokens[1:]: if t.startswith('#'): # 如果是注释则退出,在ini文件中仍然可以使用#作为注释标识。 break try: (k,v) = t.split("=", 1) # kv变量解析 except ValueError, e: raise errors.AnsibleError("%s:%s: Invalid ini entry: %s - %s" % (self.filename, lineno + 1, t, str(e))) host.set_variable(k, self._parse_value(v)) # 将该行解析的变量设置到该host下 self.groups[active_group_name].add_host(host) # 将该host加入到对应的group中。
def gen_hosts(hosts=None): """ if host_vars exists then, generate hosts Args: hosts: <list> [<host variable dict>, <host variable dict>, ...] Returns: host_objs: <list> [<host object>, <host object>, ...] """ assert isinstance(hosts, list), "the hosts must be a list" host_objs = [] if hosts: for host in hosts: hostname = host.get("hostname") hostip = host.get('ip', hostname) hostport = host.get("port") username = host.get("username") password = host.get("password") ssh_key = host.get("ssh_key") my_host = Host(name=hostname, port=hostport) my_host.set_variable('ansible_ssh_host', hostip) my_host.set_variable('ansible_ssh_port', hostport) my_host.set_variable('ansible_ssh_user', username) if password: my_host.set_variable('ansible_ssh_pass', password) if ssh_key: my_host.set_variable('ansible_ssh_private_key_file', ssh_key) # set other variables for key, value in host.iteritems(): if key not in ["hostname", "port", "username", "password", "ip", "ssh_key"]: my_host.set_variable(key, value) host_objs.append(my_host) return host_objs
def _parse_base_groups(self): # FIXME: refactor ungrouped = Group(name='ungrouped') all = Group(name='all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) active_group_name = 'ungrouped' for line in self.lines: line = self._before_comment(line).strip() if line.startswith("[") and line.endswith("]"): active_group_name = line.replace("[","").replace("]","") if ":vars" in line or ":children" in line: active_group_name = active_group_name.rsplit(":", 1)[0] if active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) active_group_name = None elif active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) elif line.startswith(";") or line == '': pass elif active_group_name: tokens = shlex.split(line) if len(tokens) == 0: continue hostname = tokens[0] port = C.DEFAULT_REMOTE_PORT # Three cases to check: # 0. A hostname that contains a range pesudo-code and a port # 1. A hostname that contains just a port if hostname.count(":") > 1: # Possible an IPv6 address, or maybe a host line with multiple ranges # IPv6 with Port XXX:XXX::XXX.port # FQDN foo.example.com if hostname.count(".") == 1: (hostname, port) = hostname.rsplit(".", 1) elif ("[" in hostname and "]" in hostname and ":" in hostname and (hostname.rindex("]") < hostname.rindex(":")) or ("]" not in hostname and ":" in hostname)): (hostname, port) = hostname.rsplit(":", 1) hostnames = [] if detect_range(hostname): hostnames = expand_hostname_range(hostname) else: hostnames = [hostname] for hn in hostnames: host = None if hn in self.hosts: host = self.hosts[hn] else: host = Host(name=hn, port=port) self.hosts[hn] = host if len(tokens) > 1: for t in tokens[1:]: if t.startswith('#'): break try: (k,v) = t.split("=", 1) except ValueError, e: raise AnsibleError("Invalid ini entry in %s: %s - %s" % (self.filename, t, str(e))) if k == 'ansible_ssh_host': host.ipv4_address = self._parse_value(v) else: host.set_variable(k, self._parse_value(v)) self.groups[active_group_name].add_host(host)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): if self.runner.noop_on_check(inject): return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for this module')) args = {} if complex_args: args.update(complex_args) args.update(parse_kv(module_args)) if not 'hostname' in args and not 'name' in args: raise ae("'name' is a required argument.") result = {} # Parse out any hostname:port patterns new_name = args.get('name', args.get('hostname', None)) vv("creating host via 'add_host': hostname=%s" % new_name) if ":" in new_name: new_name, new_port = new_name.split(":") args['ansible_ssh_port'] = new_port # redefine inventory and get group "all" inventory = self.runner.inventory allgroup = inventory.get_group('all') # check if host in cache, add if not if new_name in inventory._hosts_cache: new_host = inventory._hosts_cache[new_name] else: new_host = Host(new_name) # only groups can be added directly to inventory inventory._hosts_cache[new_name] = new_host allgroup.add_host(new_host) # Add any variables to the new_host for k in args.keys(): if not k in [ 'name', 'hostname', 'groupname', 'groups' ]: new_host.set_variable(k, args[k]) groupnames = args.get('groupname', args.get('groups', args.get('group', ''))) # add it to the group if that was specified if groupnames != '': for group_name in groupnames.split(","): group_name = group_name.strip() if not inventory.get_group(group_name): new_group = Group(group_name) inventory.add_group(new_group) grp = inventory.get_group(group_name) grp.add_host(new_host) # add this host to the group cache if inventory._groups_list is not None: if group_name in inventory._groups_list: if new_host.name not in inventory._groups_list[group_name]: inventory._groups_list[group_name].append(new_host.name) vv("added host to group via add_host module: %s" % group_name) result['new_groups'] = groupnames.split(",") result['new_host'] = new_name # clear pattern caching completely since it's unpredictable what # patterns may have referenced the group inventory.clear_pattern_cache() return ReturnData(conn=conn, comm_ok=True, result=result)
def _get_delegated_vars(self, play, task, existing_variables): # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() templar = Templar(loader=self._loader, variables=vars_copy) items = [] if task.loop is not None: if task.loop in lookup_loader: try: loop_terms = listify_lookup_plugin_terms(terms=task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=False) items = lookup_loader.get(task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) except AnsibleUndefinedVariable: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % task.loop) else: items = [None] delegated_host_vars = dict() for item in items: # update the variables with the item value for templating, in case we need it if item is not None: vars_copy['item'] = item templar.set_available_variables(vars_copy) delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) if delegated_host_name is None: raise AnsibleError(message="Undefined delegate_to host for task:", obj=task._ds) if delegated_host_name in delegated_host_vars: # no need to repeat ourselves, as the delegate_to value # does not appear to be tied to the loop item variable continue # a dictionary of variables to use if we have to create a new host below # we set the default port based on the default transport here, to make sure # we use the proper default for windows new_port = C.DEFAULT_REMOTE_PORT if C.DEFAULT_TRANSPORT == 'winrm': new_port = 5986 new_delegated_host_vars = dict( ansible_delegated_host=delegated_host_name, ansible_host=delegated_host_name, # not redundant as other sources can change ansible_host ansible_port=new_port, ansible_user=C.DEFAULT_REMOTE_USER, ansible_connection=C.DEFAULT_TRANSPORT, ) # now try to find the delegated-to host in inventory, or failing that, # create a new host on the fly so we can fetch variables for it delegated_host = None if self._inventory is not None: delegated_host = self._inventory.get_host(delegated_host_name) # try looking it up based on the address field, and finally # fall back to creating a host on the fly to use for the var lookup if delegated_host is None: if delegated_host_name in C.LOCALHOST: delegated_host = self._inventory.localhost else: for h in self._inventory.get_hosts(ignore_limits=True, ignore_restrictions=True): # check if the address matches, or if both the delegated_to host # and the current host are in the list of localhost aliases if h.address == delegated_host_name: delegated_host = h break else: delegated_host = Host(name=delegated_host_name) delegated_host.vars = combine_vars(delegated_host.vars, new_delegated_host_vars) else: delegated_host = Host(name=delegated_host_name) delegated_host.vars = combine_vars(delegated_host.vars, new_delegated_host_vars) # now we go fetch the vars for the delegated-to host and save them in our # master dictionary of variables to be used later in the TaskExecutor/PlayContext delegated_host_vars[delegated_host_name] = self.get_vars( play=play, host=delegated_host, task=task, include_delegate_to=False, include_hostvars=False, ) return delegated_host_vars
def _parse_base_groups(self): # FIXME: refactor ungrouped = Group(name='ungrouped') all = Group(name='all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) active_group_name = 'ungrouped' for line in self.lines: line = utils.before_comment(line).strip() if line.startswith("[") and line.endswith("]"): active_group_name = line.replace("[","").replace("]","") if ":vars" in line or ":children" in line: active_group_name = active_group_name.rsplit(":", 1)[0] if active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) all.add_child_group(new_group) active_group_name = None elif active_group_name not in self.groups: new_group = self.groups[active_group_name] = Group(name=active_group_name) all.add_child_group(new_group) elif line.startswith(";") or line == '': pass elif active_group_name: tokens = shlex.split(line) if len(tokens) == 0: continue hostname = tokens[0] port = C.DEFAULT_REMOTE_PORT # Three cases to check: # 0. A hostname that contains a range pesudo-code and a port # 1. A hostname that contains just a port if hostname.count(":") > 1: # Possible an IPv6 address, or maybe a host line with multiple ranges # IPv6 with Port XXX:XXX::XXX.port # FQDN foo.example.com if hostname.count(".") == 1: (hostname, port) = hostname.rsplit(".", 1) elif ("[" in hostname and "]" in hostname and ":" in hostname and (hostname.rindex("]") < hostname.rindex(":")) or ("]" not in hostname and ":" in hostname)): (hostname, port) = hostname.rsplit(":", 1) hostnames = [] if detect_range(hostname): hostnames = expand_hostname_range(hostname) else: hostnames = [hostname] for hn in hostnames: host = None if hn in self.hosts: host = self.hosts[hn] else: host = Host(name=hn, port=port) self.hosts[hn] = host if len(tokens) > 1: for t in tokens[1:]: if t.startswith('#'): break try: (k,v) = t.split("=", 1) except ValueError, e: raise errors.AnsibleError("Invalid ini entry: %s - %s" % (t, str(e))) # If there is a hash in the value don't pass it through to ast at ast will split at the hash. if "#" in v: host.set_variable(k, v) else: try: host.set_variable(k,ast.literal_eval(v)) # Using explicit exceptions. # Likely a string that literal_eval does not like. We wil then just set it. except ValueError: # For some reason this was thought to be malformed. host.set_variable(k, v) except SyntaxError: # Is this a hash with an equals at the end? host.set_variable(k, v) self.groups[active_group_name].add_host(host)