def generate_filenames(host, inject, filename): """ Render the raw filename into 3 forms """ # filename2 is the templated version of the filename, which will # be fully rendered if any variables contained within it are # non-inventory related filename2 = template(self.basedir, filename, self.vars) # filename3 is the same as filename2, but when the host object is # available, inventory variables will be expanded as well since the # name is templated with the injected variables filename3 = filename2 if host is not None: filename3 = template(self.basedir, filename2, inject) # filename4 is the dwim'd path, but may also be mixed-scope, so we use # both play scoped vars and host scoped vars to template the filepath if self._has_vars_in(filename3) and host is not None: inject.update(self.vars) filename4 = template(self.basedir, filename3, inject) filename4 = utils.path_dwim(self.basedir, filename4) else: filename4 = utils.path_dwim(self.basedir, filename3) return filename2, filename3, filename4
def check_conditional(conditional, basedir, inject, fail_on_undefined=False, jinja2=False): if jinja2: conditional = "jinja2_compare %s" % conditional if conditional.startswith("jinja2_compare"): conditional = conditional.replace("jinja2_compare ","") # allow variable names if conditional in inject: conditional = inject[conditional] conditional = template.template(basedir, conditional, inject, fail_on_undefined=fail_on_undefined) # a Jinja2 evaluation that results in something Python can eval! presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional conditional = template.template(basedir, presented, inject) val = conditional.lstrip().rstrip() if val == "True": return True elif val == "False": return False else: raise errors.AnsibleError("unable to evaluate conditional: %s" % conditional) if not isinstance(conditional, basestring): return conditional try: conditional = conditional.replace("\n", "\\n") result = safe_eval(conditional) if result not in [ True, False ]: raise errors.AnsibleError("Conditional expression must evaluate to True or False: %s" % conditional) return result except (NameError, SyntaxError): raise errors.AnsibleError("Could not evaluate the expression: (%s)" % conditional)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for template operations ''' # note: since this module just calls the copy module, the --check mode support # can be implemented entirely over there if not self.runner.is_playbook: raise errors.AnsibleError("in current versions of ansible, templates are only usable in playbooks") # load up options options = {} if complex_args: options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) dest = options.get('dest', None) if (source is None and 'first_available_file' not in inject) or dest is None: result = dict(failed=True, msg="src and dest are required") return ReturnData(conn=conn, comm_ok=False, result=result) # if we have first_available_file in our vars # look up the files and use the first one we find as src if 'first_available_file' in inject: found = False for fn in self.runner.module_vars.get('first_available_file'): fn_orig = fn fnt = template.template(self.runner.basedir, fn, inject) fnd = utils.path_dwim(self.runner.basedir, fnt) if not os.path.exists(fnd) and '_original_file' in inject: fnd = utils.path_dwim_relative(inject['_original_file'], 'templates', fnt, self.runner.basedir, check=False) if os.path.exists(fnd): source = fnd found = True break if not found: result = dict(failed=True, msg="could not find src in first_available_file list") return ReturnData(conn=conn, comm_ok=False, result=result) else: source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'templates', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if dest.endswith("/"): # CCTODO: Fix path for Windows hosts. base = os.path.basename(source) dest = os.path.join(dest, base) # template the source data locally & get ready to transfer try: resultant = template.template_from_file(self.runner.basedir, source, inject, vault_password=self.runner.vault_pass) except Exception, e: result = dict(failed=True, msg=type(e).__name__ + ": " + str(e)) return ReturnData(conn=conn, comm_ok=False, result=result)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): args = {} if complex_args: args.update(complex_args) args.update(utils.parse_kv(module_args)) dest = args.get('dest') extra_vars = args.get('vars') sources = args.get('sources') if extra_vars: # Extend 'inject' args used in templating if isinstance(extra_vars, dict): inject.update(extra_vars) else: inject.update(utils.parse_kv(extra_vars)) # Catch the case where sources is a str() if not isinstance(sources, list): sources = [sources] config = ConfigParser() for source in sources: # template the source string source = template.template(self.runner.basedir, source, inject) try: self.read_config(source, inject, config) except Exception as e: return ReturnData(conn=conn, comm_ok=False, result={'failed': True, 'msg': str(e)}) # Dump configparser to string via an emulated file fakefile = StringIO() config.write(fakefile) # Template the file to fill out any variables content = template.template(self.runner.basedir, fakefile.getvalue(), inject) fakefile.close() # Ship this content over to a new file for use with the copy module xfered = self.runner._transfer_str(conn, tmp, 'source', content) copy_module_args = dict( src=xfered, dest=dest, original_basename=os.path.basename(source), follow=True, ) return self.runner._execute_module(conn, tmp, 'copy', '', inject=inject, complex_args=copy_module_args)
def check_conditional(conditional, basedir, inject, fail_on_undefined=False, jinja2=False): if isinstance(conditional, list): for x in conditional: if not check_conditional(x, basedir, inject, fail_on_undefined=fail_on_undefined, jinja2=jinja2): return False return True if jinja2: conditional = "jinja2_compare %s" % conditional if conditional.startswith("jinja2_compare"): conditional = conditional.replace("jinja2_compare ", "") # allow variable names if conditional in inject and str(inject[conditional]).find("-") == -1: conditional = inject[conditional] conditional = template.template(basedir, conditional, inject, fail_on_undefined=fail_on_undefined) original = str(conditional).replace("jinja2_compare ", "") # a Jinja2 evaluation that results in something Python can eval! presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional conditional = template.template(basedir, presented, inject) val = conditional.strip() if val == presented: # the templating failed, meaning most likely a # variable was undefined. If we happened to be # looking for an undefined variable, return True, # otherwise fail if conditional.find("is undefined") != -1: return True elif conditional.find("is defined") != -1: return False else: raise errors.AnsibleError("error while evaluating conditional: %s" % original) elif val == "True": return True elif val == "False": return False else: raise errors.AnsibleError("unable to evaluate conditional: %s" % original) if not isinstance(conditional, basestring): return conditional try: conditional = conditional.replace("\n", "\\n") result = safe_eval(conditional) if result not in [True, False]: raise errors.AnsibleError("Conditional expression must evaluate to True or False: %s" % conditional) return result except (NameError, SyntaxError): raise errors.AnsibleError("Could not evaluate the expression: (%s)" % conditional)
def _process_include(self, data, basedir, vars={}): tokens = shlex.split(data['include']) defaults = vars.copy() # allow key=value parameters to be specified on the include line # to set variables for t in tokens[1:]: (k, v) = t.split("=", 1) defaults[k] = template(basedir, v, defaults) included_path = utils.path_dwim(basedir, template(basedir, tokens[0], defaults)) return self._load_play_from_file(included_path, defaults)
def run(self, terms, inject=None, **kwargs): ''' Main execution path ''' try: terms = template.template(self.basedir, terms, inject) # Reason: disable broad-except to really ignore any potential exception # This is inspired by the upstream "env" lookup plugin: # https://github.com/ansible/ansible/blob/devel/v1/ansible/runner/lookup_plugins/env.py#L29 # pylint: disable=broad-except except Exception: pass if isinstance(terms, basestring): terms = [terms] ret = [] for term in terms: option_name = term.split()[0] cli_key = 'cli_' + option_name if inject and cli_key in inject: ret.append(inject[cli_key]) elif option_name in os.environ: ret.append(os.environ[option_name]) else: ret.append('') return ret
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): if not module_args: result = dict(failed=True, msg="No source file given") return ReturnData(conn=conn, comm_ok=True, result=result) source = template.template(self.runner.basedir, module_args, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'vars', source, self.runner.basedir, False) else: source = utils.path_dwim(self.runner.basedir, source) data = {} if os.path.exists(source): data = utils.parse_yaml_from_file(source, vault_password=self.runner.vault_pass) if data and type(data) != dict: raise errors.AnsibleError("%s must be stored as a dictionary/hash" % source) if not hasattr(conn.runner, 'mergeBuffer'): conn.runner.mergeBuffer = {} if conn.host in conn.runner.mergeBuffer: data = utils.merge_hash(conn.runner.mergeBuffer[conn.host], data) conn.runner.mergeBuffer[conn.host] = data result = dict(ansible_facts=data) return ReturnData(conn=conn, comm_ok=True, result=result)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): try: args = {} if complex_args: args.update(complex_args) args.update(parse_kv(module_args)) envdict={} if self.runner.environment: env=template.template(self.runner.basedir, self.runner.environment, inject, convert_bare=True) env = utils.safe_eval(env) testQueue = args["queue_name"] region = args["region"] spec_file = path.expanduser("~/.nucleator/contrib/Bucketandq/orchestrator/specification.json") queue = self.initQueue(testQueue, region, env) self.main(self.addMessageToQueue, queue, spec_file) return ReturnData(conn=conn, comm_ok=True, result=dict(failed=False, changed=False, msg="Bucketandq Messages Created!")) except Exception, e: # deal with failure gracefully result = dict(failed=True, msg=type(e).__name__ + ": " + str(e)) return ReturnData(conn=conn, comm_ok=False, result=result)
def _get_role_path(self, role): """ Returns the path on disk to the directory containing the role directories like tasks, templates, etc. Also returns any variables that were included with the role """ orig_path = template(self.basedir,role,self.vars) role_vars = {} if type(orig_path) == dict: # what, not a path? role_name = orig_path.get('role', None) if role_name is None: raise errors.AnsibleError("expected a role name in dictionary: %s" % orig_path) role_vars = orig_path orig_path = role_name path = utils.path_dwim(self.basedir, os.path.join('roles', orig_path)) if not os.path.isdir(path) and not orig_path.startswith(".") and not orig_path.startswith("/"): path2 = utils.path_dwim(self.basedir, orig_path) if not os.path.isdir(path2): raise errors.AnsibleError("cannot find role in %s or %s" % (path, path2)) path = path2 elif not os.path.isdir(path): raise errors.AnsibleError("cannot find role in %s" % (path)) return (path, role_vars)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): args = {} if complex_args: args.update(complex_args) # attempt to prevent confusing messages when the variable didn't interpolate module_args = module_args.replace("{{ ","{{").replace(" }}","}}") kv = utils.parse_kv(module_args) args.update(kv) if not 'msg' in args and not 'var' in args: args['msg'] = 'Hello world!' result = {} if 'msg' in args: if 'fail' in args and utils.boolean(args['fail']): result = dict(failed=True, msg=args['msg']) else: result = dict(msg=args['msg']) elif 'var' in args and not utils.LOOKUP_REGEX.search(args['var']): results = template.template(self.basedir, args['var'], inject, convert_bare=True) result[args['var']] = results # force flag to make debug output module always verbose result['verbose_always'] = True return ReturnData(conn=conn, result=result)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' run the pause action module ''' # note: this module does not need to pay attention to the 'check' # flag, it always runs hosts = ', '.join(self.runner.host_set) args = {} if complex_args: args.update(complex_args) # extra template call unneeded? args.update(parse_kv(template.template(self.runner.basedir, module_args, inject))) # Are 'minutes' or 'seconds' keys that exist in 'args'? if 'minutes' in args or 'seconds' in args: try: if 'minutes' in args: self.pause_type = 'minutes' # The time() command operates in seconds so we need to # recalculate for minutes=X values. self.seconds = int(args['minutes']) * 60 else: self.pause_type = 'seconds' self.seconds = int(args['seconds']) self.duration_unit = 'seconds' except ValueError, e: raise ae("non-integer value given for prompt duration:\n%s" % str(e))
def listify_lookup_plugin_terms(terms, basedir, inject): if isinstance(terms, basestring): # someone did: # with_items: alist # OR # with_items: {{ alist }} stripped = terms.strip() if not (stripped.startswith('{') or stripped.startswith('[')) and not stripped.startswith("/"): # if not already a list, get ready to evaluate with Jinja2 # not sure why the "/" is in above code :) try: new_terms = template.template(basedir, "{{ %s }}" % terms, inject) if isinstance(new_terms, basestring) and new_terms.find("{{") != -1: pass else: terms = new_terms except: pass if '{' in terms or '[' in terms: # Jinja2 already evaluated a variable to a list. # Jinja2-ified list needs to be converted back to a real type # TODO: something a bit less heavy than eval return safe_eval(terms) if isinstance(terms, basestring): terms = [ terms ] return terms
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): if not module_args: result = dict(failed=True, msg="No source file given") return ReturnData(conn=conn, comm_ok=True, result=result) source = module_args source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'vars', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if os.path.exists(source): data = utils.parse_yaml_from_file(source, vault_password=self.runner.vault_pass) if data and type(data) != dict: raise errors.AnsibleError("%s must be stored as a dictionary/hash" % source) elif data is None: data = {} result = dict(ansible_facts=data) return ReturnData(conn=conn, comm_ok=True, result=result) else: result = dict(failed=True, msg="Source file not found.", file=source) return ReturnData(conn=conn, comm_ok=True, result=result)
def generate_filenames(host, inject, filename): """ Render the raw filename into 3 forms """ filename2 = template(self.basedir, filename, self.vars) filename3 = filename2 if host is not None: filename3 = template(self.basedir, filename2, inject) if self._has_vars_in(filename3) and host is not None: # allow play scoped vars and host scoped vars to template the filepath inject.update(self.vars) filename4 = template(self.basedir, filename3, inject) filename4 = utils.path_dwim(self.basedir, filename4) else: filename4 = utils.path_dwim(self.basedir, filename3) return filename2, filename3, filename4
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): # the group_by module does not need to pay attention to check mode. # it always runs. args = {} if complex_args: args.update(complex_args) args.update(parse_kv(self.runner.module_args)) if not 'key' in args: raise ae("'key' is a required argument.") vv("created 'group_by' ActionModule: key=%s"%(args['key'])) inventory = self.runner.inventory result = {'changed': False} ### find all groups groups = {} for host in self.runner.host_set: data = {} data.update(inject) data.update(inject['hostvars'][host]) conds = self.runner.conditional if type(conds) != list: conds = [ conds ] next_host = False for cond in conds: if not check_conditional(cond, self.runner.basedir, data, fail_on_undefined=self.runner.error_on_undefined_vars): next_host = True break if next_host: continue group_name = template.template(self.runner.basedir, args['key'], data) group_name = group_name.replace(' ','-') if group_name not in groups: groups[group_name] = [] groups[group_name].append(host) result['groups'] = groups ### add to inventory for group, hosts in groups.items(): inv_group = inventory.get_group(group) if not inv_group: inv_group = ansible.inventory.Group(name=group) inventory.add_group(inv_group) for host in hosts: del self.runner.inventory._vars_per_host[host] inv_host = inventory.get_host(host) if not inv_host: inv_host = ansible.inventory.Host(name=host) if inv_group not in inv_host.get_groups(): result['changed'] = True inv_group.add_host(inv_host) return ReturnData(conn=conn, comm_ok=True, result=result)
def run(self, terms, variables, **kwargs): if isNotV2: try: inject = variables['inject'] if 'inject' in variables else None key = template.template(self.basedir, terms[0], inject) except Exception, e: pass
def _arg_or_fact(self, arg_name, fact_name, args, inject): res = args.get(arg_name) if res is not None: return res template_string = '{{ %s }}' % fact_name res = template.template(self.basedir, template_string, inject) return None if res == template_string else res
def _prepare_settings(self, settings, default_vars, extra_vars): combined_vars = ansible.utils.combine_vars(default_vars, extra_vars) for k, v in settings.iteritems(): settings[k] = template(self.basedir, v, combined_vars) return settings
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for file transfer operations ''' # load up options options = {} if complex_args: options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) dest = options.get('dest', None) copy = utils.boolean(options.get('copy', 'yes')) if source is None or dest is None: result = dict(failed=True, msg="src (or content) and dest are required") return ReturnData(conn=conn, result=result) dest = os.path.expanduser(dest) # CCTODO: Fix path for Windows hosts. source = template.template(self.runner.basedir, os.path.expanduser(source), inject) if copy: if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) remote_md5 = self.runner._remote_md5(conn, tmp, dest) if remote_md5 != '3': result = dict(failed=True, msg="dest '%s' must be an existing dir" % dest) return ReturnData(conn=conn, result=result) if copy: # transfer the file to a remote tmp location tmp_src = tmp + 'source' conn.put_file(source, tmp_src) # handle diff mode client side # handle check mode client side # fix file permissions when the copy is done as a different user if copy: if self.runner.sudo and self.runner.sudo_user != 'root' or self.runner.su and self.runner.su_user != 'root': if not self.runner.noop_on_check(inject): self.runner._remote_chmod(conn, 'a+r', tmp_src, tmp) # Build temporary module_args. new_module_args = dict( src=tmp_src, original_basename=os.path.basename(source), ) # make sure checkmod is passed on correctly if self.runner.noop_on_check(inject): new_module_args['CHECKMODE'] = True module_args = utils.merge_module_args(module_args, new_module_args) else: module_args = "%s original_basename=%s" % (module_args, pipes.quote(os.path.basename(source))) # make sure checkmod is passed on correctly if self.runner.noop_on_check(inject): module_args += " CHECKMODE=True" return self.runner._execute_module(conn, tmp, 'unarchive', module_args, inject=inject, complex_args=complex_args)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): """Run the method""" if not self.runner.is_playbook: raise errors.AnsibleError("FAILED: `config_templates` are only available in playbooks") options = self.grab_options(complex_args, module_args) try: source = options["src"] dest = options["dest"] config_overrides = options.get("config_overrides", dict()) config_type = options["config_type"] assert config_type.lower() in ["ini", "json", "yaml"] except KeyError as exp: result = dict(failed=True, msg=exp) return ReturnData(conn=conn, comm_ok=False, result=result) source_template = template.template(self.runner.basedir, source, inject) if "_original_file" in inject: source_file = utils.path_dwim_relative( inject["_original_file"], "templates", source_template, self.runner.basedir ) else: source_file = utils.path_dwim(self.runner.basedir, source_template) # Open the template file and return the data as a string. This is # being done here so that the file can be a vault encrypted file. resultant = template.template_from_file( self.runner.basedir, source_file, inject, vault_password=self.runner.vault_pass ) if config_overrides: type_merger = getattr(self, CONFIG_TYPES.get(config_type)) resultant = type_merger(config_overrides=config_overrides, resultant=resultant) # Retemplate the resultant object as it may have new data within it # as provided by an override variable. template.template_from_string(basedir=self.runner.basedir, data=resultant, vars=inject, fail_on_undefined=True) # Access to protected method is unavoidable in Ansible 1.x. new_module_args = dict( src=self.runner._transfer_str(conn, tmp, "source", resultant), dest=dest, original_basename=os.path.basename(source), follow=True, ) module_args_tmp = utils.merge_module_args(module_args, new_module_args) # Remove data types that are not available to the copy module complex_args.pop("config_overrides") complex_args.pop("config_type") # Return the copy module status. Access to protected method is # unavoidable in Ansible 1.x. return self.runner._execute_module(conn, tmp, "copy", module_args_tmp, inject=inject, complex_args=complex_args)
def _load_playbook_from_file(self, path, vars={}, vars_files=[]): ''' run top level error checking on playbooks and allow them to include other playbooks. ''' playbook_data = utils.parse_yaml_from_file( path, vault_password=self.vault_password) accumulated_plays = [] play_basedirs = [] if type(playbook_data) != list: raise errors.AnsibleError( "parse error: playbooks must be formatted as a YAML list, got %s" % type(playbook_data)) 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 be a YAML dictionary (hash), received: %s" % play) if 'include' in play: # a playbook (list of plays) decided to include some other list of plays # from another file. The result is a flat list of plays in the end. play_vars = self._get_playbook_vars(play, vars) play_vars_files = self._get_playbook_vars_files( play, vars_files) inc_vars, inc_path = self._get_include_info( play, basedir, play_vars) play_vars.update(inc_vars) included_path = utils.path_dwim( basedir, template(basedir, inc_path, play_vars)) (plays, basedirs) = self._load_playbook_from_file( included_path, vars=play_vars, vars_files=play_vars_files) for p in plays: # support for parameterized play includes works by passing # those variables along to the subservient play p['vars'] = self._extend_play_vars(p, play_vars) # now add in the vars_files p['vars_files'] = utils.list_union(p.get('vars_files', []), play_vars_files) accumulated_plays.extend(plays) play_basedirs.extend(basedirs) else: # this is a normal (non-included play) accumulated_plays.append(play) play_basedirs.append(basedir) return (accumulated_plays, play_basedirs)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for file transfer operations ''' if self.runner.check: # in check mode, always skip this module return ReturnData( conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for this module')) tokens = shlex.split(module_args) source = tokens[0] # FIXME: error handling args = " ".join(tokens[1:]) source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) # transfer the file to a remote tmp location source = source.replace('\x00', '') # why does this happen here? args = args.replace('\x00', '') # why does this happen here? tmp_src = os.path.join(tmp, os.path.basename(source)) tmp_src = tmp_src.replace('\x00', '') conn.put_file(source, tmp_src) # fix file permissions when the copy is done as a different user if self.runner.sudo and self.runner.sudo_user != 'root': prepcmd = 'chmod a+rx %s' % tmp_src else: prepcmd = 'chmod +x %s' % tmp_src # add preparation steps to one ssh roundtrip executing the script module_args = prepcmd + '; ' + tmp_src + ' ' + args handler = utils.plugins.action_loader.get('raw', self.runner) result = handler.run(conn, tmp, 'raw', module_args, inject) # clean up after if tmp.find("tmp") != -1 and C.DEFAULT_KEEP_REMOTE_FILES != '1': self.runner._low_level_exec_command( conn, 'rm -rf %s >/dev/null 2>&1' % tmp, tmp) return result
def _load_playbook_from_file(self, path, vars={}, vars_files=[]): ''' run top level error checking on playbooks and allow them to include other playbooks. ''' playbook_data = utils.parse_yaml_from_file(path, vault_password=self.vault_password) accumulated_plays = [] play_basedirs = [] if type(playbook_data) != list: raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list, got %s" % type(playbook_data)) 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 be a YAML dictionary (hash), recieved: %s" % play) if 'include' in play: # a playbook (list of plays) decided to include some other list of plays # from another file. The result is a flat list of plays in the end. play_vars = self._get_playbook_vars(play, vars) play_vars_files = self._get_playbook_vars_files(play, vars_files) inc_vars, inc_path = self._get_include_info(play, basedir, play_vars) play_vars.update(inc_vars) included_path = utils.path_dwim(basedir, template(basedir, inc_path, play_vars)) (plays, basedirs) = self._load_playbook_from_file(included_path, vars=play_vars, vars_files=play_vars_files) for p in plays: # support for parameterized play includes works by passing # those variables along to the subservient play if 'vars' not in p: p['vars'] = {} if isinstance(p['vars'], dict): p['vars'].update(play_vars) elif isinstance(p['vars'], list): # nobody should really do this, but handle vars: a=1 b=2 p['vars'].extend([{k:v} for k,v in play_vars.iteritems()]) elif p['vars'] == None: # someone specified an empty 'vars:', so reset # it to the vars we currently have p['vars'] = play_vars.copy() # now add in the vars_files p['vars_files'] = utils.list_union(p.get('vars_files', []), play_vars_files) accumulated_plays.extend(plays) play_basedirs.extend(basedirs) else: # this is a normal (non-included play) accumulated_plays.append(play) play_basedirs.append(basedir) return (accumulated_plays, play_basedirs)
def test_varReplace_var_complex_var(self): vars = { 'x': '$y', 'y': { 'foo': 'result', }, } template = '${x.foo}' res = template2.template(None, template, vars) assert res == 'result'
def test_template_varReplace_iterated(self): template = 'hello $who' vars = { 'who': 'oh great $person', 'person': 'one', } res = template2.template(None, template, vars) assert res == u'hello oh great one'
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for file transfer operations ''' # load up options options = {} if complex_args: options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) dest = options.get('dest', None) if source is None or dest is None: result = dict(failed=True, msg="src (or content) and dest are required") return ReturnData(conn=conn, result=result) source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) remote_md5 = self.runner._remote_md5(conn, tmp, dest) if remote_md5 != '3': result = dict(failed=True, msg="dest must be an existing dir") return ReturnData(conn=conn, result=result) # transfer the file to a remote tmp location tmp_src = tmp + 'source' conn.put_file(source, tmp_src) # handle diff mode client side # handle check mode client side # fix file permissions when the copy is done as a different user if self.runner.sudo and self.runner.sudo_user != 'root': self.runner._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp) module_args = "%s src=%s original_basename=%s" % ( module_args, pipes.quote(tmp_src), pipes.quote(os.path.basename(source))) return self.runner._execute_module(conn, tmp, 'unarchive', module_args, inject=inject, complex_args=complex_args)
def check_conditional(conditional, basedir, inject, fail_on_undefined=False): from ansible.utils import template if conditional is None or conditional == '': return True if isinstance(conditional, list): for x in conditional: if not check_conditional(x, basedir, inject, fail_on_undefined=fail_on_undefined): return False return True if not isinstance(conditional, basestring): return conditional conditional = conditional.replace("jinja2_compare ","") # allow variable names if conditional in inject and '-' not in str(inject[conditional]): conditional = inject[conditional] conditional = template.template(basedir, conditional, inject, fail_on_undefined=fail_on_undefined) original = str(conditional).replace("jinja2_compare ","") # a Jinja2 evaluation that results in something Python can eval! presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional conditional = template.template(basedir, presented, inject) val = conditional.strip() if val == presented: # the templating failed, meaning most likely a # variable was undefined. If we happened to be # looking for an undefined variable, return True, # otherwise fail if "is undefined" in conditional: return True elif "is defined" in conditional: return False else: raise errors.AnsibleError("error while evaluating conditional: %s" % original) elif val == "True": return True elif val == "False": return False else: raise errors.AnsibleError("unable to evaluate conditional: %s" % original)
def _command_filter(self, command, arg, items, inject): """Return only the items for which filter is true""" if '{{' not in arg: arg = '{{%s}}' % arg for item in items: template_vars = dict(inject, item=item) decision = safe_eval( template(self.basedir, arg, template_vars), locals=template_vars) if decision: yield item
def get_value(self, varname): """Get a variable's value by applying a template. If the value is dict or list, *varname* may include '.' or '[]' to get the content of dict or list. * For example, if the value of variable "var" is {"k": "v"}, get_value("var.k") will return "v". """ value = template.template('.', '{{ %s }}' % varname, self.task_info.vars) if '{{' in value: value = 'Not defined' return value
def check_conditional(conditional, basedir, inject, fail_on_undefined=False): if conditional is None or conditional == '': return True if isinstance(conditional, list): for x in conditional: if not check_conditional(x, basedir, inject, fail_on_undefined=fail_on_undefined): return False return True if not isinstance(conditional, basestring): return conditional conditional = conditional.replace("jinja2_compare ","") # allow variable names if conditional in inject and '-' not in str(inject[conditional]): conditional = inject[conditional] conditional = template.template(basedir, conditional, inject, fail_on_undefined=fail_on_undefined) original = str(conditional).replace("jinja2_compare ","") # a Jinja2 evaluation that results in something Python can eval! presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional conditional = template.template(basedir, presented, inject) val = conditional.strip() if val == presented: # the templating failed, meaning most likely a # variable was undefined. If we happened to be # looking for an undefined variable, return True, # otherwise fail if "is undefined" in conditional: return True elif "is defined" in conditional: return False else: raise errors.AnsibleError("error while evaluating conditional: %s" % original) elif val == "True": return True elif val == "False": return False else: raise errors.AnsibleError("unable to evaluate conditional: %s" % original)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for file transfer operations ''' # load up options options = {} if complex_args: options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) content = options.get('content', None) dest = options.get('dest', None) raw = utils.boolean(options.get('raw', 'no')) force = utils.boolean(options.get('force', 'yes')) if (source is None and content is None and not 'first_available_file' in inject) or dest is None: result=dict(failed=True, msg="src (or content) and dest are required") return ReturnData(conn=conn, result=result) elif (source is not None or 'first_available_file' in inject) and content is not None: result=dict(failed=True, msg="src and content are mutually exclusive") return ReturnData(conn=conn, result=result) source_trailing_slash = False if source: source_trailing_slash = source.endswith("/") # if we have first_available_file in our vars # look up the files and use the first one we find as src if 'first_available_file' in inject: found = False for fn in inject.get('first_available_file'): fn_orig = fn fnt = template.template(self.runner.basedir, fn, inject) fnd = utils.path_dwim(self.runner.basedir, fnt) if not os.path.exists(fnd) and '_original_file' in inject: fnd = utils.path_dwim_relative(inject['_original_file'], 'files', fnt, self.runner.basedir, check=False) if os.path.exists(fnd): source = fnd found = True break if not found: results=dict(failed=True, msg="could not find src in first_available_file list") return ReturnData(conn=conn, result=results) elif content is not None: fd, tmp_content = tempfile.mkstemp() f = os.fdopen(fd, 'w') try: f.write(content) except Exception, err: os.remove(tmp_content) result = dict(failed=True, msg="could not write content temp file: %s" % err) return ReturnData(conn=conn, result=result) f.close() source = tmp_content
def _get_include_info(self, play_ds, basedir, existing_vars={}): ''' Gets any key=value pairs specified with the included file name and returns the merged vars along with the path ''' new_vars = existing_vars.copy() tokens = shlex.split(play_ds.get('include', '')) for t in tokens[1:]: (k,v) = t.split("=", 1) new_vars[k] = template(basedir, v, new_vars) return (new_vars, tokens[0])
def _get_include_info(self, play_ds, basedir, existing_vars={}): ''' Gets any key=value pairs specified with the included file name and returns the merged vars along with the path ''' new_vars = existing_vars.copy() tokens = shlex.split(play_ds.get('include', '')) for t in tokens[1:]: (k, v) = t.split("=", 1) new_vars[k] = template(basedir, v, new_vars) return (new_vars, tokens[0])
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for file transfer operations ''' if self.runner.noop_on_check(inject): # in check mode, always skip this module return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for this module')) # Decode the result of shlex.split() to UTF8 to get around a bug in that's been fixed in Python 2.7 but not Python 2.6. # See: http://bugs.python.org/issue6988 tokens = shlex.split(module_args.encode('utf8')) tokens = [s.decode('utf8') for s in tokens] source = tokens[0] # FIXME: error handling args = " ".join(tokens[1:]) source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) # transfer the file to a remote tmp location source = source.replace('\x00','') # why does this happen here? args = args.replace('\x00','') # why does this happen here? tmp_src = os.path.join(tmp, os.path.basename(source)) tmp_src = tmp_src.replace('\x00', '') conn.put_file(source, tmp_src) sudoable=True # set file permissions, more permisive when the copy is done as a different user if self.runner.sudo and self.runner.sudo_user != 'root': cmd_args_chmod = "chmod a+rx %s" % tmp_src sudoable=False else: cmd_args_chmod = "chmod +rx %s" % tmp_src self.runner._low_level_exec_command(conn, cmd_args_chmod, tmp, sudoable=sudoable) # add preparation steps to one ssh roundtrip executing the script env_string = self.runner._compute_environment_string(inject) module_args = env_string + tmp_src + ' ' + args handler = utils.plugins.action_loader.get('raw', self.runner) result = handler.run(conn, tmp, 'raw', module_args, inject) # clean up after if tmp.find("tmp") != -1 and not C.DEFAULT_KEEP_REMOTE_FILES: self.runner._low_level_exec_command(conn, 'rm -rf %s >/dev/null 2>&1' % tmp, tmp) result.result['changed'] = True return result
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): args = parse_kv(module_args) environment = args.get('environment') account_id = args.get('account_id') assume_role = args.get('assume_role') for name, val in (("environment", environment), ("account_id", account_id), ("assume_role", assume_role)): if val is None: result = dict(failed=True, msg="No {0} specified".format(name)) return ReturnData(conn=conn, comm_ok=True, result=result) source = template.template(self.runner.basedir, environment, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'vars', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if os.path.exists(source): decrypted_data = {} data = json.load(open(source)) with assume(account_id, assume_role): kms = boto.kms.connect_to_region('ap-southeast-2') for key, val in data.items(): data_key = kms.decrypt(base64.b64decode( val['key']))["Plaintext"] content = base64.b64decode(val['content']) counter = Counter.new(128) decryptor = AES.new(data_key[:32], AES.MODE_CTR, counter=counter) decrypted_data[key] = decryptor.decrypt(content) result = dict(ansible_facts=decrypted_data) return ReturnData(conn=conn, comm_ok=True, result=result) else: result = dict(failed=True, msg="Couldn't find secrets!", file=source) return ReturnData(conn=conn, comm_ok=True, result=result)
def _compute_environment_string(self, inject=None): ''' what environment variables to use when running the command? ''' if not self.environment: return "" enviro = template.template(self.basedir, self.environment, inject, convert_bare=True) enviro = utils.safe_eval(enviro) if type(enviro) != dict: raise errors.AnsibleError("environment must be a dictionary, received %s" % enviro) result = "" for (k,v) in enviro.iteritems(): result = "%s=%s %s" % (k, pipes.quote(str(v)), result) return result
def _resolve_file_path(self, filepath, dirname, inject): ''' Resolve absolute path of the file. ''' basedir = self.runner.basedir filepath = template.template(basedir, filepath, inject) if '_original_file' in inject: origin_path = inject['_original_file'] filepath = utils.path_dwim_relative(origin_path, dirname, filepath, basedir) else: filepath = utils.path_dwim(basedir, filepath) return filepath
def _get_include_info(self, play_ds, basedir, existing_vars={}): ''' Gets any key=value pairs specified with the included file name and returns the merged vars along with the path ''' new_vars = existing_vars.copy() tokens = split_args(play_ds.get('include', '')) for t in tokens[1:]: try: (k,v) = unquote(t).split("=", 1) new_vars[k] = template(basedir, v, new_vars) except ValueError, e: raise errors.AnsibleError('included playbook variables must be in the form k=v, got: %s' % t)
def _load_tasks(self, tasks, vars={}, default_vars={}, sudo_vars={}, additional_conditions=[], original_file=None): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] for x in tasks: if not isinstance(x, dict): raise errors.AnsibleError("expecting dict; got: %s" % x) # evaluate sudo vars for current and child tasks included_sudo_vars = {} for k in ["sudo", "sudo_user"]: if k in x: included_sudo_vars[k] = x[k] elif k in sudo_vars: included_sudo_vars[k] = sudo_vars[k] x[k] = sudo_vars[k] if 'meta' in x: if x['meta'] == 'flush_handlers': results.append(Task(self,x)) continue task_vars = self.vars.copy() task_vars.update(vars) if original_file: task_vars['_original_file'] = original_file if 'include' in x: tokens = shlex.split(str(x['include'])) items = [''] included_additional_conditions = list(additional_conditions) include_vars = {} 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 = template(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.insert(0, utils.compile_when_to_only_if("%s %s" % (k[5:], x[k]))) elif k == 'when': included_additional_conditions.insert(0, utils.compile_when_to_only_if("jinja2_compare %s" % x[k])) elif k in ("include", "vars", "default_vars", "only_if", "sudo", "sudo_user"): continue else: include_vars[k] = x[k]
def check_conditional(conditional, basedir, inject, fail_on_undefined=False): if conditional.startswith("jinja2_compare"): conditional = conditional.replace("jinja2_compare ", "") # allow variable names if conditional in inject: conditional = inject[conditional] conditional = template.template(basedir, conditional, inject, fail_on_undefined=fail_on_undefined) # a Jinja2 evaluation that results in something Python can eval! presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional conditional = template.template(basedir, presented, inject) val = conditional.lstrip().rstrip() if val == "True": return True elif val == "False": return False else: raise errors.AnsibleError("unable to evaluate conditional: %s" % conditional) if not isinstance(conditional, basestring): return conditional try: conditional = conditional.replace("\n", "\\n") result = safe_eval(conditional) if result not in [True, False]: raise errors.AnsibleError( "Conditional expression must evaluate to True or False: %s" % conditional) return result except (NameError, SyntaxError): raise errors.AnsibleError("Could not evaluate the expression: (%s)" % conditional)
def safe_eval(str, locals=None, include_exceptions=False, template_call=False): ''' this is intended for allowing things like: with_items: a_list_variable where Jinja2 would return a string but we do not want to allow it to call functions (outside of Jinja2, where the env is constrained) ''' # FIXME: is there a more native way to do this? if template_call: # for the debug module in Ansible, allow debug of the form foo.bar.baz versus Python dictionary form str = template.template(None, "{{ %s }}" % str, locals) def is_set(var): return not var.startswith("$") and not '{{' in var def is_unset(var): return var.startswith("$") or '{{' in var # do not allow method calls to modules if not isinstance(str, basestring): # already templated to a datastructure, perhaps? if include_exceptions: return (str, None) return str if re.search(r'\w\.\w+\(', str): if include_exceptions: return (str, None) return str # do not allow imports if re.search(r'import \w+', str): if include_exceptions: return (str, None) return str try: result = None if not locals: result = eval(str) else: result = eval(str, None, locals) if include_exceptions: return (result, None) else: return result except Exception, e: if include_exceptions: return (str, e) return str
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for file transfer operations ''' # load up options options = {} if complex_args: options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) dest = options.get('dest', None) copy = utils.boolean(options.get('copy', 'yes')) if source is None or dest is None: result = dict(failed=True, msg="src (or content) and dest are required") return ReturnData(conn=conn, result=result) dest = os.path.expanduser(dest) # CCTODO: Fix path for Windows hosts. source = template.template(self.runner.basedir, os.path.expanduser(source), inject) if copy: if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'files', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) remote_md5 = self.runner._remote_md5(conn, tmp, dest) if remote_md5 != '3': result = dict(failed=True, msg="dest '%s' must be an existing dir" % dest) return ReturnData(conn=conn, result=result) if copy: # transfer the file to a remote tmp location tmp_src = tmp + 'source' conn.put_file(source, tmp_src) # handle diff mode client side # handle check mode client side # fix file permissions when the copy is done as a different user if copy: if self.runner.sudo and self.runner.sudo_user != 'root' or self.runner.su and self.runner.su_user != 'root': self.runner._remote_chmod(conn, 'a+r', tmp_src, tmp) # Build temporary module_args. new_module_args = dict( src=tmp_src, original_basename=os.path.basename(source), ) module_args = utils.merge_module_args(module_args, new_module_args) else: module_args = "%s original_basename=%s" % (module_args, pipes.quote(os.path.basename(source))) return self.runner._execute_module(conn, tmp, 'unarchive', module_args, inject=inject, complex_args=complex_args)
def get_inject_vars(self, host): host_variables = self.inventory.get_variables( host, vault_password=self.vault_pass) ansible_host = self.inventory.get_host(host) # Keep track of variables in the order they will be merged to_merge = [ ('Default Variables', self.default_vars), ] # Group variables groups = ansible_host.get_groups() for group in sorted(groups, key=lambda g: g.depth): to_merge.append( ("Group Variables ({})".format(group.name), group.get_variables()) ) combined_cache = self.get_combined_cache() # use combined_cache and host_variables to template the module_vars # we update the inject variables with the data we're about to template # since some of the variables we'll be replacing may be contained there too module_vars_inject = combine_vars( host_variables, combined_cache.get(host, {})) module_vars_inject = combine_vars( self.module_vars, module_vars_inject) module_vars = template.template( self.basedir, self.module_vars, module_vars_inject) inject = {} to_merge.extend([ ('Host Variables', ansible_host.vars), ('Setup Cache', self.setup_cache.get(host, {})), ('Play Variables', self.play_vars), ('Play File Variables', self.play_file_vars), ('Role Variables', self.role_vars), ('Module Variables', module_vars), ('Variables Cache', self.vars_cache.get(host, {})), ('Role Parameters', self.role_params), ('Extra Variables', self.extra_vars), ]) for name, value in to_merge: old_inject = inject inject = combine_vars(inject, value) print name show_diff(old_inject, inject) return inject
def _flag_handler(self, play, handler_name, host): ''' if a task has any notify elements, flag handlers for run at end of execution cycle for hosts that have indicated changes have been made ''' found = False for x in play.handlers(): if handler_name == template(play.basedir, x.name, x.module_vars): found = True self.callbacks.on_notify(host, x.name) x.notified_by.append(host) if not found: raise errors.AnsibleError("change handler (%s) is not defined" % handler_name)
def test_varReplace_var_complex_var(self): old_setting = C.DEFAULT_LEGACY_PLAYBOOK_VARIABLES C.DEFAULT_LEGACY_PLAYBOOK_VARIABLES = True vars = { 'x': '$y', 'y': { 'foo': 'result', }, } template = '${x.foo}' res = template2.template(None, template, vars) assert res == 'result' C.DEFAULT_LEGACY_PLAYBOOK_VARIABLES = old_setting
def _get_role_path(self, role): """ Returns the path on disk to the directory containing the role directories like tasks, templates, etc. Also returns any variables that were included with the role """ orig_path = template(self.basedir, role, self.vars) role_vars = {} if type(orig_path) == dict: # what, not a path? parsed_role = utils.role_yaml_parse(orig_path) role_name = parsed_role.get('role', parsed_role.get('name')) if role_name is None: raise errors.AnsibleError( "expected a role name in dictionary: %s" % orig_path) role_vars = orig_path else: role_name = utils.role_spec_parse(orig_path)["name"] role_path = None possible_paths = [ utils.path_dwim(self.basedir, os.path.join('roles', role_name)), utils.path_dwim(self.basedir, role_name) ] if C.DEFAULT_ROLES_PATH: search_locations = C.DEFAULT_ROLES_PATH.split(os.pathsep) for loc in search_locations: loc = os.path.expanduser(loc) possible_paths.append(utils.path_dwim(loc, role_name)) for path_option in possible_paths: if os.path.isdir(path_option): role_path = path_option break if role_path is None: raise errors.AnsibleError("cannot find role in %s" % " or ".join(possible_paths)) return (role_path, role_vars)
def run_handlers(self, play): on_hosts = play._play_hosts hosts_count = len(on_hosts) for task in play.tasks(): if task.meta is not None: fired_names = {} for handler in play.handlers(): if len(handler.notified_by) > 0: self.inventory.restrict_to(handler.notified_by) # Resolve the variables first handler_name = template(play.basedir, handler.name, handler.module_vars) if handler_name not in fired_names: self._run_task(play, handler, True) # prevent duplicate handler includes from running more than once fired_names[handler_name] = 1 host_list = self._trim_unavailable_hosts( play._play_hosts) if handler.any_errors_fatal and len( host_list) < hosts_count: play.max_fail_pct = 0 if (hosts_count - len(host_list)) > int( (play.max_fail_pct) / 100.0 * hosts_count): host_list = None if not host_list and not play.force_handlers: self.callbacks.on_no_hosts_remaining() return False self.inventory.lift_restriction() new_list = handler.notified_by[:] for host in handler.notified_by: if host in on_hosts: while host in new_list: new_list.remove(host) handler.notified_by = new_list continue return True
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): args = {} if complex_args: args.update(complex_args) # attempt to prevent confusing messages when the variable didn't interpolate module_args = module_args.replace("{{ ", "{{").replace(" }}", "}}") kv = utils.parse_kv(module_args) args.update(kv) if not 'msg' in args and not 'var' in args: args['msg'] = 'Hello world!' result = {} if 'msg' in args: if 'fail' in args and utils.boolean(args['fail']): result = dict(failed=True, msg=args['msg']) else: result = dict(msg=args['msg']) elif 'var' in args and not utils.LOOKUP_REGEX.search(args['var']): results = template.template(self.basedir, args['var'], inject, convert_bare=True) result[args['var']] = results # force flag to make debug output module always verbose result['verbose_always'] = True return ReturnData(conn=conn, result=result)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): if not module_args: result = dict(failed=True, msg="No source file given") return ReturnData(conn=conn, comm_ok=True, result=result) source = module_args source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'defaults', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if os.path.exists(source): data = utils.parse_yaml_from_file( source, vault_password=self.runner.vault_pass) if data and type(data) != dict: raise errors.AnsibleError( "%s must be stored as a dictionary/hash" % source) elif data is None: data = {} inject['defaults'].update(data) return ReturnData(conn=conn, comm_ok=True, result={}) else: result = dict(failed=True, msg="Source file not found.", file=source) return ReturnData(conn=conn, comm_ok=True, result=result)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' run the pause action module ''' # note: this module does not need to pay attention to the 'check' # flag, it always runs hosts = ', '.join(self.runner.host_set) args = {} if complex_args: args.update(complex_args) # extra template call unneeded? args.update( parse_kv( template.template(self.runner.basedir, module_args, inject))) # Are 'minutes' or 'seconds' keys that exist in 'args'? if 'minutes' in args or 'seconds' in args: try: if 'minutes' in args: self.pause_type = 'minutes' # The time() command operates in seconds so we need to # recalculate for minutes=X values. self.seconds = int(args['minutes']) * 60 else: self.pause_type = 'seconds' self.seconds = int(args['seconds']) self.duration_unit = 'seconds' except ValueError, e: raise ae("non-integer value given for prompt duration:\n%s" % str(e))
def _update_vars_files_for_host(self, host): if type(self.vars_files) != list: self.vars_files = [ self.vars_files ] if host is not None: inject = {} inject.update(self.playbook.inventory.get_variables(host)) inject.update(self.playbook.SETUP_CACHE[host]) for filename in self.vars_files: if type(filename) == list: # loop over all filenames, loading the first one, and failing if # none found found = False sequence = [] for real_filename in filename: filename2 = template(self.basedir, real_filename, self.vars) filename3 = filename2 if host is not None: filename3 = template(self.basedir, filename2, inject) filename4 = utils.path_dwim(self.basedir, filename3) sequence.append(filename4) if os.path.exists(filename4): found = True data = utils.parse_yaml_from_file(filename4) if type(data) != dict: raise errors.AnsibleError("%s must be stored as a dictionary/hash" % filename4) if host is not None: if self._has_vars_in(filename2) and not self._has_vars_in(filename3): # this filename has variables in it that were fact specific # so it needs to be loaded into the per host SETUP_CACHE self.playbook.SETUP_CACHE[host].update(data) self.playbook.callbacks.on_import_for_host(host, filename4) elif not self._has_vars_in(filename4): # found a non-host specific variable, load into vars and NOT # the setup cache self.vars.update(data) elif host is not None: self.playbook.callbacks.on_not_import_for_host(host, filename4) if found: break if not found and host is not None: raise errors.AnsibleError( "%s: FATAL, no files matched for vars_files import sequence: %s" % (host, sequence) ) else: # just one filename supplied, load it! filename2 = template(self.basedir, filename, self.vars) filename3 = filename2 if host is not None: filename3 = template(self.basedir, filename2, inject) filename4 = utils.path_dwim(self.basedir, filename3) if self._has_vars_in(filename4): continue new_vars = utils.parse_yaml_from_file(filename4) if new_vars: if type(new_vars) != dict: raise errors.AnsibleError("%s must be stored as dictionary/hash: %s" % (filename4, type(new_vars))) if host is not None and self._has_vars_in(filename2) and not self._has_vars_in(filename3): # running a host specific pass and has host specific variables # load into setup cache self.playbook.SETUP_CACHE[host] = utils.combine_vars( self.playbook.SETUP_CACHE[host], new_vars) self.playbook.callbacks.on_import_for_host(host, filename4) elif host is None: # running a non-host specific pass and we can update the global vars instead self.vars = utils.combine_vars(self.vars, new_vars)
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) # allow all playbook keys to be set by --extra-vars self.vars = ds.get('vars', {}) self.vars_prompt = ds.get('vars_prompt', {}) self.playbook = playbook self.vars = self._get_vars() self.basedir = basedir self.roles = ds.get('roles', None) self.tags = ds.get('tags', None) if self.tags is None: self.tags = [] elif type(self.tags) in [ str, unicode ]: self.tags = self.tags.split(",") elif type(self.tags) != list: self.tags = [] # We first load the vars files from the datastructure # so we have the default variables to pass into the roles self.vars_files = ds.get('vars_files', []) if not isinstance(self.vars_files, list): raise errors.AnsibleError('vars_files must be a list') self._update_vars_files_for_host(None) # now we load the roles into the datastructure self.included_roles = [] ds = self._load_roles(self.roles, ds) # and finally re-process the vars files as they may have # been updated by the included roles self.vars_files = ds.get('vars_files', []) if not isinstance(self.vars_files, list): raise errors.AnsibleError('vars_files must be a list') self._update_vars_files_for_host(None) # template everything to be efficient, but do not pre-mature template # tasks/handlers as they may have inventory scope overrides _tasks = ds.pop('tasks', []) _handlers = ds.pop('handlers', []) ds = template(basedir, ds, self.vars) ds['tasks'] = _tasks ds['handlers'] = _handlers self._ds = ds hosts = ds.get('hosts') if hosts is None: raise errors.AnsibleError('hosts declaration is required') elif isinstance(hosts, list): hosts = ';'.join(hosts) self.serial = int(ds.get('serial', 0)) self.hosts = hosts self.name = ds.get('name', self.hosts) self._tasks = ds.get('tasks', []) self._handlers = ds.get('handlers', []) self.remote_user = ds.get('remote_user', ds.get('user', self.playbook.remote_user)) self.remote_port = ds.get('port', self.playbook.remote_port) self.sudo = ds.get('sudo', self.playbook.sudo) self.sudo_user = ds.get('sudo_user', self.playbook.sudo_user) self.transport = ds.get('connection', self.playbook.transport) self.gather_facts = ds.get('gather_facts', None) self.remote_port = self.remote_port self.any_errors_fatal = utils.boolean(ds.get('any_errors_fatal', 'false')) self.accelerate = utils.boolean(ds.get('accelerate', 'false')) self.accelerate_port = ds.get('accelerate_port', None) self.accelerate_ipv6 = ds.get('accelerate_ipv6', False) self.max_fail_pct = int(ds.get('max_fail_percentage', 100)) load_vars = {} load_vars['playbook_dir'] = self.basedir if self.playbook.inventory.basedir() is not None: load_vars['inventory_dir'] = self.playbook.inventory.basedir() self._tasks = self._load_tasks(self._ds.get('tasks', []), load_vars) self._handlers = self._load_tasks(self._ds.get('handlers', []), load_vars) if self.sudo_user != 'root': self.sudo = True
def _load_tasks(self, tasks, vars=None, default_vars=None, sudo_vars=None, additional_conditions=None, original_file=None, role_name=None): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] if additional_conditions is None: additional_conditions = [] if vars is None: vars = {} if default_vars is None: default_vars = {} if sudo_vars is None: sudo_vars = {} old_conditions = list(additional_conditions) for x in tasks: # prevent assigning the same conditions to each task on an include included_additional_conditions = list(old_conditions) if not isinstance(x, dict): raise errors.AnsibleError("expecting dict; got: %s" % x) # evaluate sudo vars for current and child tasks included_sudo_vars = {} for k in ["sudo", "sudo_user"]: if k in x: included_sudo_vars[k] = x[k] elif k in sudo_vars: included_sudo_vars[k] = sudo_vars[k] x[k] = sudo_vars[k] if 'meta' in x: if x['meta'] == 'flush_handlers': results.append(Task(self,x)) continue task_vars = self.vars.copy() task_vars.update(vars) if original_file: task_vars['_original_file'] = original_file if 'include' in x: tokens = shlex.split(str(x['include'])) items = [''] included_additional_conditions = list(additional_conditions) include_vars = {} for k in x: if k.startswith("with_"): utils.deprecated("include + with_items is an unsupported feature and has been undocumented for many releases because of this", "1.5") 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 = template(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.insert(0, utils.compile_when_to_only_if("%s %s" % (k[5:], x[k]))) elif k == 'when': if type(x[k]) is str: included_additional_conditions.insert(0, utils.compile_when_to_only_if("jinja2_compare %s" % x[k])) elif type(x[k]) is list: for i in x[k]: included_additional_conditions.insert(0, utils.compile_when_to_only_if("jinja2_compare %s" % i)) elif k in ("include", "vars", "default_vars", "only_if", "sudo", "sudo_user", "role_name"): continue else: include_vars[k] = x[k] default_vars = x.get('default_vars', {}) if not default_vars: default_vars = self.default_vars else: default_vars = utils.combine_vars(self.default_vars, default_vars) # append the vars defined with the include (from above) # as well as the old-style 'vars' element. The old-style # vars are given higher precedence here (just in case) task_vars = utils.combine_vars(task_vars, include_vars) if 'vars' in x: task_vars = utils.combine_vars(task_vars, x['vars']) if 'only_if' in x: included_additional_conditions.append(x['only_if']) new_role = None if 'role_name' in x: new_role = x['role_name'] for item in items: mv = task_vars.copy() mv['item'] = item for t in tokens[1:]: (k,v) = t.split("=", 1) mv[k] = template(self.basedir, v, mv) dirname = self.basedir if original_file: dirname = os.path.dirname(original_file) include_file = template(dirname, tokens[0], mv) include_filename = utils.path_dwim(dirname, include_file) data = utils.parse_yaml_from_file(include_filename) if 'role_name' in x and data is not None: for x in data: if 'include' in x: x['role_name'] = new_role loaded = self._load_tasks(data, mv, default_vars, included_sudo_vars, list(included_additional_conditions), original_file=include_filename, role_name=new_role) results += loaded elif type(x) == dict: task = Task(self,x,module_vars=task_vars,default_vars=default_vars,additional_conditions=list(additional_conditions),role_name=role_name) results.append(task) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): try: args = {} if complex_args: args.update(complex_args) args.update(parse_kv(module_args)) account_number = args["account_number"] region = args["region"] cloudtrail_bucket = args["cloudtrail_bucket"] envdict = {} if self.runner.environment: env = template.template(self.runner.basedir, self.runner.environment, inject, convert_bare=True) env = utils.safe_eval(env) if region == "us-east-1": other_regions = [ "us-west-1", "us-west-2", "eu-west-1", "us-east-2" ] elif region == "us-east-2": other_regions = [ "us-east-1", "us-west-1", "us-west-2", "eu-west-1" ] elif region == "us-west-1": other_regions = [ "us-east-1", "us-east-2", "us-west-2", "eu-west-1" ] elif region == "us-west-2": other_regions = [ "us-east-1", "us-east-2", "us-west-1", "eu-west-1" ] elif region == "eu-west-1": other_regions = [ "us-east-1", "us-east-2", "us-west-1", "us-west-2" ] else: raise SystemExit(1) # unsupported region for connect_region in other_regions: cloudtrail_name = "Cloudtrail-%s-%s" % (account_number, connect_region) try: connection = cloudtrail.connect_to_region( connect_region, aws_access_key_id=env.get("AWS_ACCESS_KEY_ID"), aws_secret_access_key=env.get("AWS_SECRET_ACCESS_KEY"), security_token=env.get("AWS_SECURITY_TOKEN")) except Exception, e: raise Exception try: result = connection.update_trail( cloudtrail_name, cloudtrail_bucket, include_global_service_events=False) result = connection.start_logging(cloudtrail_name) except Exception, e: result = connection.create_trail( cloudtrail_name, cloudtrail_bucket, include_global_service_events=False) result = connection.start_logging(cloudtrail_name)
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): ''' handler for template operations ''' # note: since this module just calls the copy module, the --check mode support # can be implemented entirely over there if not self.runner.is_playbook: raise errors.AnsibleError( "in current versions of ansible, templates are only usable in playbooks" ) # load up options options = {} if complex_args: options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) dest = options.get('dest', None) if (source is None and 'first_available_file' not in inject) or dest is None: result = dict(failed=True, msg="src and dest are required") return ReturnData(conn=conn, comm_ok=False, result=result) # if we have first_available_file in our vars # look up the files and use the first one we find as src if 'first_available_file' in inject: found = False for fn in self.runner.module_vars.get('first_available_file'): fn_orig = fn fnt = template.template(self.runner.basedir, fn, inject) fnd = utils.path_dwim(self.runner.basedir, fnt) if not os.path.exists(fnd) and '_original_file' in inject: fnd = utils.path_dwim_relative(inject['_original_file'], 'templates', fn_orig, self.runner.basedir, check=False) if os.path.exists(fnd): source = fnd found = True break if not found: result = dict( failed=True, msg="could not find src in first_available_file list") return ReturnData(conn=conn, comm_ok=False, result=result) else: source = template.template(self.runner.basedir, source, inject) if '_original_file' in inject: source = utils.path_dwim_relative(inject['_original_file'], 'templates', source, self.runner.basedir) else: source = utils.path_dwim(self.runner.basedir, source) if dest.endswith("/"): base = os.path.basename(source) dest = os.path.join(dest, base) # template the source data locally & get ready to transfer try: resultant = template.template_from_file(self.runner.basedir, source, inject) except Exception, e: result = dict(failed=True, msg=str(e)) return ReturnData(conn=conn, comm_ok=False, result=result)