def _load_playbook_from_file(self, path, vars={}): ''' run top level error checking on playbooks and allow them to include other playbooks. ''' playbook_data = utils.parse_yaml_from_file(path) accumulated_plays = [] play_basedirs = [] if type(playbook_data) != list: raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list") basedir = os.path.dirname(path) utils.plugins.push_basedir(basedir) for play in playbook_data: if type(play) != dict: raise errors.AnsibleError("parse error: each play in a playbook must a YAML dictionary (hash), recieved: %s" % play) if 'include' in play: if len(play.keys()) <= 2: tokens = shlex.split(play['include']) items = [''] for k in play.keys(): if not k.startswith("with_"): continue plugin_name = k[5:] if plugin_name not in utils.plugins.lookup_loader: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) terms = utils.template_ds(basedir, play[k], vars) items = utils.plugins.lookup_loader.get(plugin_name, basedir=basedir, runner=None).run(terms, inject=vars) break for item in items: incvars = vars.copy() incvars['item'] = item for t in tokens[1:]: (k,v) = t.split("=", 1) incvars[k] = utils.template_ds(basedir, v, incvars) included_path = utils.path_dwim(basedir, tokens[0]) (plays, basedirs) = self._load_playbook_from_file(included_path, incvars) for p in plays: if 'vars' not in p: p['vars'] = {} if isinstance(p['vars'], dict): p['vars'].update(incvars) elif isinstance(p['vars'], list): p['vars'].extend([dict(k=v) for k,v in incvars.iteritems()]) accumulated_plays.extend(plays) play_basedirs.extend(basedirs) else: raise errors.AnsibleError("parse error: playbook includes cannot be used with other directives: %s" % play) else: accumulated_plays.append(play) play_basedirs.append(basedir) return (accumulated_plays, play_basedirs)
def _load_tasks(self, tasks, vars={}, additional_conditions=[]): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] for x in tasks: task_vars = self.vars.copy() task_vars.update(vars) if 'include' in x: tokens = shlex.split(x['include']) items = [''] included_additional_conditions = list(additional_conditions) for k in x: if k.startswith("with_"): plugin_name = k[5:] if plugin_name not in utils.plugins.lookup_loader: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) terms = utils.template_ds(self.basedir, x[k], task_vars) items = utils.plugins.lookup_loader.get(plugin_name, basedir=self.basedir, runner=None).run(terms, inject=task_vars) elif k.startswith("when_"): included_additional_conditions.append(utils.compile_when_to_only_if("%s %s" % (k[5:], x[k]))) elif k in ("include", "vars", "only_if"): pass else: raise errors.AnsibleError("parse error: task includes cannot be used with other directives: %s" % k) if 'vars' in x: task_vars.update(x['vars']) if 'only_if' in x: included_additional_conditions.append(x['only_if']) for item in items: mv = task_vars.copy() mv['item'] = item for t in tokens[1:]: (k,v) = t.split("=", 1) mv[k] = utils.template_ds(self.basedir, v, mv) include_file = utils.template(self.basedir, tokens[0], mv) data = utils.parse_yaml_from_file(utils.path_dwim(self.basedir, include_file)) results += self._load_tasks(data, mv, included_additional_conditions) elif type(x) == dict: results.append(Task(self,x,module_vars=task_vars, additional_conditions=additional_conditions)) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def _load_tasks(self, ds, keyname): ''' handle task and handler include statements ''' tasks = ds.get(keyname, []) results = [] for x in tasks: if 'include' in x: task_vars = self.vars.copy() tokens = shlex.split(x['include']) items = [''] for k in x: if not k.startswith("with_"): continue plugin_name = k[5:] if plugin_name not in utils.plugins.lookup_loader: raise errors.AnsibleError( "cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) terms = utils.template_ds(self.basedir, x[k], task_vars) items = utils.plugins.lookup_loader.get( plugin_name, basedir=self.basedir, runner=None).run(terms, inject=task_vars) for item in items: mv = task_vars.copy() mv['item'] = item for t in tokens[1:]: (k, v) = t.split("=", 1) mv[k] = utils.template_ds(self.basedir, v, mv) include_file = utils.template(self.basedir, tokens[0], mv) data = utils.parse_yaml_from_file( utils.path_dwim(self.basedir, include_file)) for y in data: results.append(Task(self, y, module_vars=mv.copy())) elif type(x) == dict: task_vars = self.vars.copy() results.append(Task(self, x, module_vars=task_vars)) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def __init__(self, playbook, ds, basedir): ''' constructor loads from a play datastructure ''' for x in ds.keys(): if not x in Play.VALID_KEYS: raise errors.AnsibleError( "%s is not a legal parameter in an Ansible Playbook" % x) # TODO: more error handling hosts = ds.get('hosts') if hosts is None: raise errors.AnsibleError('hosts declaration is required') elif isinstance(hosts, list): hosts = ';'.join(hosts) self._ds = ds self.playbook = playbook self.basedir = basedir self.vars = ds.get('vars', {}) self.vars_files = ds.get('vars_files', []) self.vars_prompt = ds.get('vars_prompt', {}) self.vars = self._get_vars() self.hosts = utils.template(basedir, hosts, self.vars) self.name = ds.get('name', self.hosts) self._tasks = ds.get('tasks', []) self._handlers = ds.get('handlers', []) self.remote_user = utils.template( basedir, ds.get('user', self.playbook.remote_user), self.vars) self.remote_port = ds.get('port', self.playbook.remote_port) self.sudo = ds.get('sudo', self.playbook.sudo) self.sudo_user = utils.template( basedir, ds.get('sudo_user', self.playbook.sudo_user), self.vars) self.transport = ds.get('connection', self.playbook.transport) self.tags = ds.get('tags', None) self.gather_facts = ds.get('gather_facts', None) self.serial = int( utils.template_ds(basedir, ds.get('serial', 0), self.vars)) if isinstance(self.remote_port, basestring): self.remote_port = utils.template(basedir, self.remote_port, self.vars) self._update_vars_files_for_host(None) self._tasks = self._load_tasks(self._ds.get('tasks', [])) self._handlers = self._load_tasks(self._ds.get('handlers', [])) if self.tags is None: self.tags = [] elif type(self.tags) in [str, unicode]: self.tags = [self.tags] elif type(self.tags) != list: self.tags = [] if self.sudo_user != 'root': self.sudo = True
def __init__(self, playbook, ds, basedir): ''' constructor loads from a play datastructure ''' for x in ds.keys(): if not x in Play.VALID_KEYS: raise errors.AnsibleError("%s is not a legal parameter in an Ansible Playbook" % x) # TODO: more error handling hosts = ds.get('hosts') if hosts is None: raise errors.AnsibleError('hosts declaration is required') elif isinstance(hosts, list): hosts = ';'.join(hosts) self._ds = ds self.playbook = playbook self.basedir = basedir self.vars = ds.get('vars', {}) self.vars_files = ds.get('vars_files', []) self.vars_prompt = ds.get('vars_prompt', {}) self.vars = self._get_vars() self.hosts = utils.template(basedir, hosts, self.vars) self.name = ds.get('name', self.hosts) self._tasks = ds.get('tasks', []) self._handlers = ds.get('handlers', []) self.remote_user = utils.template(basedir, ds.get('user', self.playbook.remote_user), self.vars) self.remote_port = ds.get('port', self.playbook.remote_port) self.sudo = ds.get('sudo', self.playbook.sudo) self.sudo_user = utils.template(basedir, ds.get('sudo_user', self.playbook.sudo_user), self.vars) self.transport = ds.get('connection', self.playbook.transport) self.tags = ds.get('tags', None) self.gather_facts = ds.get('gather_facts', None) self.serial = int(utils.template_ds(basedir, ds.get('serial', 0), self.vars)) if isinstance(self.remote_port, basestring): self.remote_port = utils.template(basedir, self.remote_port, self.vars) self._update_vars_files_for_host(None) self._tasks = self._load_tasks(self._ds.get('tasks', [])) self._handlers = self._load_tasks(self._ds.get('handlers', [])) if self.tags is None: self.tags = [] elif type(self.tags) in [ str, unicode ]: self.tags = [ self.tags ] elif type(self.tags) != list: self.tags = [] if self.sudo_user != 'root': self.sudo = True
def _executor_internal(self, host): ''' executes any module one or more times ''' host_variables = self.inventory.get_variables(host) if self.transport in ['paramiko', 'ssh']: port = host_variables.get('ansible_ssh_port', self.remote_port) if port is None: port = C.DEFAULT_REMOTE_PORT else: # fireball, local, etc port = self.remote_port inject = {} inject.update(host_variables) inject.update(self.module_vars) inject.update(self.setup_cache[host]) inject['hostvars'] = HostVars(self.setup_cache, self.inventory) inject['group_names'] = host_variables.get('group_names', []) inject['groups'] = self.inventory.groups_list() # allow with_foo to work in playbooks... items = None items_plugin = self.module_vars.get('items_lookup_plugin', None) if items_plugin is not None and items_plugin in utils.plugins.lookup_loader: items_terms = self.module_vars.get('items_lookup_terms', '') items_terms = utils.template_ds(self.basedir, items_terms, inject) items = utils.plugins.lookup_loader.get(items_plugin, runner=self, basedir=self.basedir).run( items_terms, inject=inject) if type(items) != list: raise errors.AnsibleError( "lookup plugins have to return a list: %r" % items) if len(items) and self.module_name in ['apt', 'yum']: # hack for apt and soon yum, with_items maps back into a single module call inject['item'] = ",".join(items) items = None # logic to decide how to run things depends on whether with_items is used if items is None: return self._executor_internal_inner(host, self.module_name, self.module_args, inject, port) elif len(items) > 0: # executing using with_items, so make multiple calls # TODO: refactor aggregrate = {} all_comm_ok = True all_changed = False all_failed = False results = [] for x in items: inject['item'] = x result = self._executor_internal_inner(host, self.module_name, self.module_args, inject, port) results.append(result.result) if result.comm_ok == False: all_comm_ok = False all_failed = True break for x in results: if x.get('changed') == True: all_changed = True if (x.get('failed') == True) or (('rc' in x) and (x['rc'] != 0)): all_failed = True break msg = 'All items completed' if all_failed: msg = "One or more items failed." rd_result = dict(failed=all_failed, changed=all_changed, results=results, msg=msg) if not all_failed: del rd_result['failed'] return ReturnData(host=host, comm_ok=all_comm_ok, result=rd_result) else: self.callbacks.on_skipped(host, None) return ReturnData(host=host, comm_ok=True, result=dict(skipped=True))
def _load_tasks(self, tasks, vars={}, additional_conditions=[]): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] for x in tasks: task_vars = self.vars.copy() task_vars.update(vars) if 'include' in x: tokens = shlex.split(x['include']) items = [''] included_additional_conditions = list(additional_conditions) for k in x: if k.startswith("with_"): plugin_name = k[5:] if plugin_name not in utils.plugins.lookup_loader: raise errors.AnsibleError( "cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) terms = utils.template_ds(self.basedir, x[k], task_vars) items = utils.plugins.lookup_loader.get( plugin_name, basedir=self.basedir, runner=None).run(terms, inject=task_vars) elif k.startswith("when_"): included_additional_conditions.append( utils.compile_when_to_only_if("%s %s" % (k[5:], x[k]))) elif k in ("include", "vars", "only_if"): pass else: raise errors.AnsibleError( "parse error: task includes cannot be used with other directives: %s" % k) if 'vars' in x: task_vars.update(x['vars']) if 'only_if' in x: included_additional_conditions.append(x['only_if']) for item in items: mv = task_vars.copy() mv['item'] = item for t in tokens[1:]: (k, v) = t.split("=", 1) mv[k] = utils.template_ds(self.basedir, v, mv) include_file = utils.template(self.basedir, tokens[0], mv) data = utils.parse_yaml_from_file( utils.path_dwim(self.basedir, include_file)) results += self._load_tasks( data, mv, included_additional_conditions) elif type(x) == dict: results.append( Task(self, x, module_vars=task_vars, additional_conditions=additional_conditions)) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def _load_playbook_from_file(self, path, vars={}): ''' run top level error checking on playbooks and allow them to include other playbooks. ''' playbook_data = utils.parse_yaml_from_file(path) accumulated_plays = [] play_basedirs = [] if type(playbook_data) != list: raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list") basedir = os.path.dirname(path) or '.' utils.plugins.push_basedir(basedir) for play in playbook_data: if type(play) != dict: raise errors.AnsibleError("parse error: each play in a playbook must a YAML dictionary (hash), recieved: %s" % play) if 'include' in play: tokens = shlex.split(play['include']) items = [''] for k in play.keys(): if not k.startswith("with_"): # These are the keys allowed to be mixed with playbook includes if k in ("include", "vars"): continue else: raise errors.AnsibleError("parse error: playbook includes cannot be used with other directives: %s" % play) plugin_name = k[5:] if plugin_name not in utils.plugins.lookup_loader: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) terms = utils.template_ds(basedir, play[k], vars) items = utils.plugins.lookup_loader.get(plugin_name, basedir=basedir, runner=None).run(terms, inject=vars) for item in items: incvars = vars.copy() incvars['item'] = item if 'vars' in play: if isinstance(play['vars'], dict): incvars.update(play['vars']) elif isinstance(play['vars'], list): for v in play['vars']: incvars.update(v) for t in tokens[1:]: (k,v) = t.split("=", 1) incvars[k] = utils.template_ds(basedir, v, incvars) included_path = utils.path_dwim(basedir, tokens[0]) (plays, basedirs) = self._load_playbook_from_file(included_path, incvars) for p in plays: if 'vars' not in p: p['vars'] = {} if isinstance(p['vars'], dict): p['vars'].update(incvars) elif isinstance(p['vars'], list): p['vars'].extend([dict(k=v) for k,v in incvars.iteritems()]) accumulated_plays.extend(plays) play_basedirs.extend(basedirs) else: accumulated_plays.append(play) play_basedirs.append(basedir) return (accumulated_plays, play_basedirs)
def _executor_internal(self, host): ''' executes any module one or more times ''' host_variables = self.inventory.get_variables(host) if self.transport in [ 'paramiko', 'ssh' ]: port = host_variables.get('ansible_ssh_port', self.remote_port) if port is None: port = C.DEFAULT_REMOTE_PORT else: # fireball, local, etc port = self.remote_port inject = {} inject.update(host_variables) inject.update(self.module_vars) inject.update(self.setup_cache[host]) inject['hostvars'] = HostVars(self.setup_cache, self.inventory) inject['group_names'] = host_variables.get('group_names', []) inject['groups'] = self.inventory.groups_list() # allow with_foo to work in playbooks... items = None items_plugin = self.module_vars.get('items_lookup_plugin', None) if items_plugin is not None and items_plugin in utils.plugins.lookup_loader: items_terms = self.module_vars.get('items_lookup_terms', '') items_terms = utils.template_ds(self.basedir, items_terms, inject) items = utils.plugins.lookup_loader.get(items_plugin, runner=self, basedir=self.basedir).run(items_terms, inject=inject) if type(items) != list: raise errors.AnsibleError("lookup plugins have to return a list: %r" % items) if len(items) and self.module_name in [ 'apt', 'yum' ]: # hack for apt and soon yum, with_items maps back into a single module call inject['item'] = ",".join(items) items = None # logic to decide how to run things depends on whether with_items is used if items is None: return self._executor_internal_inner(host, self.module_name, self.module_args, inject, port) elif len(items) > 0: # executing using with_items, so make multiple calls # TODO: refactor aggregrate = {} all_comm_ok = True all_changed = False all_failed = False results = [] for x in items: inject['item'] = x result = self._executor_internal_inner(host, self.module_name, self.module_args, inject, port) results.append(result.result) if result.comm_ok == False: all_comm_ok = False all_failed = True break for x in results: if x.get('changed') == True: all_changed = True if (x.get('failed') == True) or (('rc' in x) and (x['rc'] != 0)): all_failed = True break msg = 'All items completed' if all_failed: msg = "One or more items failed." rd_result = dict(failed=all_failed, changed=all_changed, results=results, msg=msg) if not all_failed: del rd_result['failed'] return ReturnData(host=host, comm_ok=all_comm_ok, result=rd_result) else: self.callbacks.on_skipped(host, None) return ReturnData(host=host, comm_ok=True, result=dict(skipped=True))