def setUp(self): Registry.empty() self.pydmesg_expected = { "file.managed": [ { "group": "root" }, { "mode": "0755" }, { "require": [{ "file": "/usr/local/bin" }] }, { "source": "salt://debian/files/pydmesg.py" }, { "user": "******" }, ] } self.pydmesg_salt_expected = OrderedDict([("/usr/local/bin/pydmesg", self.pydmesg_expected)]) self.pydmesg_kwargs = dict( user="******", group="root", mode="0755", source="salt://debian/files/pydmesg.py", )
def render(template, saltenv="base", sls="", **kwargs): if "pyobjects_states" not in __context__: load_states() # these hold the scope that our sls file will be executed with _globals = {} _locals = {} # create our StateFactory objects mod_globals = {"StateFactory": StateFactory} for mod in __context__["pyobjects_states"]: mod_locals = {} mod_camel = "".join([part.capitalize() for part in mod.split("_")]) mod_cmd = "%s = StateFactory('%s', valid_funcs=['%s'])" % ( mod_camel, mod, "','".join(__context__["pyobjects_states"][mod].keys()), ) if sys.version > 3: exec (mod_cmd, mod_globals, mod_locals) else: exec mod_cmd in mod_globals, mod_locals _globals[mod_camel] = mod_locals[mod_camel] # add our include and extend functions _globals["include"] = Registry.include _globals["extend"] = Registry.make_extend # add our map class Map.__salt__ = __salt__ _globals["Map"] = Map # add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects try: _globals.update( { # salt, pillar & grains all provide shortcuts or object interfaces "salt": SaltObject(__salt__), "pillar": __salt__["pillar.get"], "grains": __salt__["grains.get"], "mine": __salt__["mine.get"], # the "dunder" formats are still available for direct use "__salt__": __salt__, "__pillar__": __pillar__, "__grains__": __grains__, } ) except NameError: pass # now exec our template using our created scopes # in py3+ exec is a function, prior to that it is a statement if sys.version > 3: exec (template.read(), _globals, _locals) else: exec template.read() in _globals, _locals return Registry.salt_data()
def test_salt_data(self): File.managed("/usr/local/bin/pydmesg", require=File("/usr/local/bin"), **pydmesg_kwargs) self.assertEqual(Registry.states["/usr/local/bin/pydmesg"], pydmesg_expected) self.assertEqual(Registry.salt_data(), pydmesg_salt_expected) self.assertEqual(Registry.states, OrderedDict())
def test_salt_data(self): File.managed( "/usr/local/bin/pydmesg", require=File("/usr/local/bin"), **pydmesg_kwargs ) self.assertEqual(Registry.states["/usr/local/bin/pydmesg"], pydmesg_expected) self.assertEqual(Registry.salt_data(), pydmesg_salt_expected) self.assertEqual(Registry.states, OrderedDict())
def render(template, saltenv='base', sls='', salt_data=True, **kwargs): if 'pyobjects_states' not in __context__: load_states() # these hold the scope that our sls file will be executed with _globals = {} # create our StateFactory objects mod_globals = {'StateFactory': StateFactory} for mod in __context__['pyobjects_states']: mod_locals = {} mod_camel = ''.join([part.capitalize() for part in mod.split('_')]) valid_funcs = "','".join(__context__['pyobjects_states'][mod]) mod_cmd = "{0} = StateFactory('{1!s}', valid_funcs=['{2}'])".format( mod_camel, mod, valid_funcs) exec_(mod_cmd, mod_globals, mod_locals) _globals[mod_camel] = mod_locals[mod_camel] # add our include and extend functions _globals['include'] = Registry.include _globals['extend'] = Registry.make_extend # add our map class Map.__salt__ = __salt__ _globals['Map'] = Map # add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects try: _globals.update({ # salt, pillar & grains all provide shortcuts or object interfaces 'salt': SaltObject(__salt__), 'pillar': __salt__['pillar.get'], 'grains': __salt__['grains.get'], 'mine': __salt__['mine.get'], 'config': __salt__['config.get'], # the "dunder" formats are still available for direct use '__salt__': __salt__, '__pillar__': __pillar__, '__grains__': __grains__ }) except NameError: pass # if salt_data is not True then we just return the global scope we've # built instead of returning salt data from the registry if not salt_data: return _globals # this will be used to fetch any import files client = get_file_client(__opts__) # process our sls imports # # we allow pyobjects users to use a special form of the import statement # so that they may bring in objects from other files. while we do this we # disable the registry since all we're looking for here is python objects, # not salt state data template_data = [] Registry.enabled = False for line in template.readlines(): line = line.rstrip('\r\n') matched = False for RE in (IMPORT_RE, FROM_RE): matches = RE.match(line) if not matches: continue import_file = matches.group(1).strip() try: imports = matches.group(2).split(',') except IndexError: # if we don't have a third group in the matches object it means # that we're importing everything imports = None state_file = client.cache_file(import_file, saltenv) if not state_file: raise ImportError( "Could not find the file {0!r}".format(import_file)) with salt.utils.fopen(state_file) as f: state_contents = f.read() state_locals = {} exec_(state_contents, _globals, state_locals) if imports is None: imports = list(state_locals) for name in imports: name = alias = name.strip() matches = FROM_AS_RE.match(name) if matches is not None: name = matches.group(1).strip() alias = matches.group(2).strip() if name not in state_locals: raise ImportError("{0!r} was not found in {1!r}".format( name, import_file)) _globals[alias] = state_locals[name] matched = True break if not matched: template_data.append(line) final_template = "\n".join(template_data) # re-enable the registry Registry.enabled = True # now exec our template using our created scopes exec_(final_template, _globals) return Registry.salt_data()
def setUp(self): Registry.empty()
def render(template, saltenv='base', sls='', salt_data=True, **kwargs): if 'pyobjects_states' not in __context__: load_states() # these hold the scope that our sls file will be executed with _locals = {} _globals = {} # create our StateFactory objects mod_globals = {'StateFactory': StateFactory} for mod in __context__['pyobjects_states']: mod_locals = {} mod_camel = ''.join([ part.capitalize() for part in mod.split('_') ]) valid_funcs = "','".join( __context__['pyobjects_states'][mod].keys() ) mod_cmd = "{0} = StateFactory('{1!s}', valid_funcs=['{2}'])".format( mod_camel, mod, valid_funcs ) if sys.version_info[0] > 2: # in py3+ exec is a function exec(mod_cmd, mod_globals, mod_locals) else: # prior to that it is a statement exec mod_cmd in mod_globals, mod_locals _globals[mod_camel] = mod_locals[mod_camel] # add our include and extend functions _globals['include'] = Registry.include _globals['extend'] = Registry.make_extend # add our map class Map.__salt__ = __salt__ _globals['Map'] = Map # add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects try: _globals.update({ # salt, pillar & grains all provide shortcuts or object interfaces 'salt': SaltObject(__salt__), 'pillar': __salt__['pillar.get'], 'grains': __salt__['grains.get'], 'mine': __salt__['mine.get'], 'config': __salt__['config.get'], # the "dunder" formats are still available for direct use '__salt__': __salt__, '__pillar__': __pillar__, '__grains__': __grains__ }) except NameError: pass # if salt_data is not True then we just return the global scope we've # built instead of returning salt data from the registry if not salt_data: return _globals # this will be used to fetch any import files client = get_file_client(__opts__) # process our sls imports # # we allow pyobjects users to use a special form of the import statement # so that they may bring in objects from other files. while we do this we # disable the registry since all we're looking for here is python objects, # not salt state data template_data = [] Registry.enabled = False for line in template.readlines(): line = line.rstrip('\r\n') matched = False for RE in (IMPORT_RE, FROM_RE): matches = re.match(RE, line) if not matches: continue import_file = matches.group(1).strip() try: imports = matches.group(2).split(',') except IndexError: # if we don't have a third group in the matches object it means # that we're importing everything imports = None state_file = client.cache_file(import_file, saltenv) if not state_file: raise ImportError("Could not find the file {0!r}".format(import_file)) with open(state_file) as f: state_contents = f.read() state_locals = {} if sys.version_info[0] > 2: # in py3+ exec is a function exec(state_contents, _globals, state_locals) else: # prior to that it is a statement exec state_contents in _globals, state_locals if imports is None: imports = state_locals.keys() for name in imports: name = name.strip() if name not in state_locals: raise ImportError("{0!r} was not found in {1!r}".format( name, import_file )) _globals[name] = state_locals[name] matched = True break if not matched: template_data.append(line) final_template = "\n".join(template_data) # re-enable the registry Registry.enabled = True # now exec our template using our created scopes if sys.version_info[0] > 2: # in py3+ exec is a function exec(final_template, _globals, _locals) else: # prior to that it is a statement exec final_template in _globals, _locals return Registry.salt_data()
def render(template, saltenv='base', sls='', **kwargs): if 'pyobjects_states' not in __context__: load_states() # these hold the scope that our sls file will be executed with _globals = {} _locals = {} # this will be used to fetch any import files client = get_file_client(__opts__) # create our StateFactory objects mod_globals = {'StateFactory': StateFactory} for mod in __context__['pyobjects_states']: mod_locals = {} mod_camel = ''.join([part.capitalize() for part in mod.split('_')]) valid_funcs = "','".join(__context__['pyobjects_states'][mod].keys()) mod_cmd = "{0} = StateFactory('{1!s}', valid_funcs=['{2}'])".format( mod_camel, mod, valid_funcs) if sys.version_info[0] > 2: # in py3+ exec is a function exec(mod_cmd, mod_globals, mod_locals) else: # prior to that it is a statement exec mod_cmd in mod_globals, mod_locals _globals[mod_camel] = mod_locals[mod_camel] # add our include and extend functions _globals['include'] = Registry.include _globals['extend'] = Registry.make_extend # add our map class Map.__salt__ = __salt__ _globals['Map'] = Map # add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects try: _globals.update({ # salt, pillar & grains all provide shortcuts or object interfaces 'salt': SaltObject(__salt__), 'pillar': __salt__['pillar.get'], 'grains': __salt__['grains.get'], 'mine': __salt__['mine.get'], # the "dunder" formats are still available for direct use '__salt__': __salt__, '__pillar__': __pillar__, '__grains__': __grains__ }) except NameError: pass # process our sls imports # # we allow pyobjects users to use a special form of the import statement # so that they may bring in objects from other files. while we do this we # disable the registry since all we're looking for here is python objects, # not salt state data # # once we have our template we scan through it and look for any "from X # import Y" statements and if X ends in .sls then we process it by passing # the file in X through the pyobjects renderer and putting the requested # variables into our template template_data = [] Registry.enabled = False for line in template.readlines(): line = line.rstrip('\r\n') matched = False for RE in (IMPORT_RE, FROM_RE): matches = re.match(RE, line) if not matches: continue import_file = matches.group(1).strip() try: imports = matches.group(2).split(',') except IndexError: # if we don't have a third group in the matches object it means # that we're importing everything imports = None state_file = client.cache_file(import_file, saltenv) if not state_file: raise ImportError( "Could not find the file {0!r}".format(import_file)) with open(state_file) as f: state_contents = f.read() state_locals = {} if sys.version_info[0] > 2: # in py3+ exec is a function exec(state_contents, _globals, state_locals) else: # prior to that it is a statement exec state_contents in _globals, state_locals if imports is None: imports = state_locals.keys() for name in imports: name = name.strip() if name not in state_locals: raise ImportError("{0!r} was not found in {1!r}".format( name, import_file)) _globals[name] = state_locals[name] matched = True break if not matched: template_data.append(line) final_template = "\n".join(template_data) # re-enable the registry Registry.enabled = True # now exec our template using our created scopes if sys.version_info[0] > 2: # in py3+ exec is a function exec(final_template, _globals, _locals) else: # prior to that it is a statement exec final_template in _globals, _locals return Registry.salt_data()
def render(template, saltenv='base', sls='', salt_data=True, **kwargs): if 'pyobjects_states' not in __context__: load_states() # these hold the scope that our sls file will be executed with _globals = {} # create our StateFactory objects mod_globals = {'StateFactory': StateFactory} for mod in __context__['pyobjects_states']: mod_locals = {} mod_camel = ''.join([ part.capitalize() for part in mod.split('_') ]) valid_funcs = "','".join( __context__['pyobjects_states'][mod] ) mod_cmd = "{0} = StateFactory('{1!s}', valid_funcs=['{2}'])".format( mod_camel, mod, valid_funcs ) exec_(mod_cmd, mod_globals, mod_locals) _globals[mod_camel] = mod_locals[mod_camel] # add our include and extend functions _globals['include'] = Registry.include _globals['extend'] = Registry.make_extend # add our map class Map.__salt__ = __salt__ _globals['Map'] = Map # add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects try: _globals.update({ # salt, pillar & grains all provide shortcuts or object interfaces 'salt': SaltObject(__salt__), 'pillar': __salt__['pillar.get'], 'grains': __salt__['grains.get'], 'mine': __salt__['mine.get'], 'config': __salt__['config.get'], # the "dunder" formats are still available for direct use '__salt__': __salt__, '__pillar__': __pillar__, '__grains__': __grains__ }) except NameError: pass # if salt_data is not True then we just return the global scope we've # built instead of returning salt data from the registry if not salt_data: return _globals # this will be used to fetch any import files client = get_file_client(__opts__) # process our sls imports # # we allow pyobjects users to use a special form of the import statement # so that they may bring in objects from other files. while we do this we # disable the registry since all we're looking for here is python objects, # not salt state data Registry.enabled = False def process_template(template, template_globals): template_data = [] state_globals = {} for line in template.readlines(): line = line.rstrip('\r\n') matched = False for RE in (IMPORT_RE, FROM_RE): matches = RE.match(line) if not matches: continue import_file = matches.group(1).strip() try: imports = matches.group(2).split(',') except IndexError: # if we don't have a third group in the matches object it means # that we're importing everything imports = None state_file = client.cache_file(import_file, saltenv) if not state_file: raise ImportError( 'Could not find the file \'{0}\''.format(import_file) ) state_locals = {} with salt.utils.fopen(state_file) as state_fh: state_contents, state_locals = process_template(state_fh, template_globals) exec_(state_contents, template_globals, state_locals) # if no imports have been specified then we are being imported as: import salt://foo.sls # so we want to stick all of the locals from our state file into the template globals # under the name of the module -> i.e. foo.MapClass if imports is None: import_name = os.path.splitext(os.path.basename(state_file))[0] state_globals[import_name] = PyobjectsModule(import_name, state_locals) else: for name in imports: name = alias = name.strip() matches = FROM_AS_RE.match(name) if matches is not None: name = matches.group(1).strip() alias = matches.group(2).strip() if name not in state_locals: raise ImportError( '\'{0}\' was not found in \'{1}\''.format( name, import_file ) ) state_globals[alias] = state_locals[name] matched = True break if not matched: template_data.append(line) return "\n".join(template_data), state_globals # process the template that triggered the render final_template, final_locals = process_template(template, _globals) _globals.update(final_locals) # re-enable the registry Registry.enabled = True # now exec our template using our created scopes exec_(final_template, _globals) return Registry.salt_data()
def render(template, saltenv="base", sls="", salt_data=True, **kwargs): if "pyobjects_states" not in __context__: load_states() # these hold the scope that our sls file will be executed with _globals = {} # create our StateFactory objects mod_globals = {"StateFactory": StateFactory} for mod in __context__["pyobjects_states"]: mod_locals = {} mod_camel = "".join([part.capitalize() for part in mod.split("_")]) valid_funcs = "','".join(__context__["pyobjects_states"][mod]) mod_cmd = "{} = StateFactory('{!s}', valid_funcs=['{}'])".format( mod_camel, mod, valid_funcs) exec(mod_cmd, mod_globals, mod_locals) _globals[mod_camel] = mod_locals[mod_camel] # add our include and extend functions _globals["include"] = Registry.include _globals["extend"] = Registry.make_extend # add our map class Map.__salt__ = __salt__ _globals["Map"] = Map # add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects try: _globals.update({ # salt, pillar & grains all provide shortcuts or object interfaces "salt": SaltObject(__salt__), "pillar": __salt__["pillar.get"], "grains": __salt__["grains.get"], "mine": __salt__["mine.get"], "config": __salt__["config.get"], # the "dunder" formats are still available for direct use "__salt__": __salt__, "__pillar__": __pillar__, "__grains__": __grains__, "__opts__": __opts__, "__sls__": sls, }) except NameError: pass # if salt_data is not True then we just return the global scope we've # built instead of returning salt data from the registry if not salt_data: return _globals # this will be used to fetch any import files client = get_file_client(__opts__) # process our sls imports # # we allow pyobjects users to use a special form of the import statement # so that they may bring in objects from other files. while we do this we # disable the registry since all we're looking for here is python objects, # not salt state data Registry.enabled = False def process_template(template): template_data = [] # Do not pass our globals to the modules we are including and keep the root _globals untouched template_globals = dict(_globals) for line in template.readlines(): line = line.rstrip("\r\n") matched = False for RE in (IMPORT_RE, FROM_RE): matches = RE.match(line) if not matches: continue import_file = matches.group(1).strip() try: imports = matches.group(2).split(",") except IndexError: # if we don't have a third group in the matches object it means # that we're importing everything imports = None state_file = client.cache_file(import_file, saltenv) if not state_file: raise ImportError( "Could not find the file '{}'".format(import_file)) with salt.utils.files.fopen(state_file) as state_fh: state_contents, state_globals = process_template(state_fh) exec(state_contents, state_globals) # if no imports have been specified then we are being imported as: import salt://foo.sls # so we want to stick all of the locals from our state file into the template globals # under the name of the module -> i.e. foo.MapClass if imports is None: import_name = os.path.splitext( os.path.basename(state_file))[0] template_globals[import_name] = PyobjectsModule( import_name, state_globals) else: for name in imports: name = alias = name.strip() matches = FROM_AS_RE.match(name) if matches is not None: name = matches.group(1).strip() alias = matches.group(2).strip() if name not in state_globals: raise ImportError( "'{}' was not found in '{}'".format( name, import_file)) template_globals[alias] = state_globals[name] matched = True break if not matched: template_data.append(line) return "\n".join(template_data), template_globals # process the template that triggered the render final_template, final_globals = process_template(template) _globals.update(final_globals) # re-enable the registry Registry.enabled = True # now exec our template using our created scopes exec(final_template, _globals) return Registry.salt_data()
def render(template, saltenv='base', sls='', **kwargs): ''' Creates an OrderedDict representing id's with states and values from a #!yamlscript state (sls) template. Yamlscript is a mix of python and yaml using yamls structured human readable format. ''' # Detect if we are running a template, pillar or state if 'sls_type' not in kwargs.keys(): if kwargs.get('_pillar_rend', False): kwargs['sls_type'] = 'pillar' elif get_dunder('__states__'): kwargs['sls_type'] = 'state' else: kwargs['sls_type'] = 'pillar' if not 'salt.loaded.ext.render.yamlscript' in __context__: __context__['salt.loaded.ext.render.yamlscript'] = True salt.utils.compat.pack_dunder('salt.loaded.ext.render.yamlscript') # Apply dunders to yamlscript_utils if they do not yet exist dunders = ['__salt__', '__states__', '__pillar__', '__grains__', '__utils__', '__opts__'] for dunder in dunders: pack_dunder('yamlscript_utils', dunder) # Keep track of stack during include statements yamlscript_utils.Cache(__context__) yamlscript_utils.Cache.set(sls, sls) # Convert yaml to ordered dictionary deserialize = yamlscript_utils.Deserialize( template, saltenv=saltenv, sls=sls, **kwargs ) script_data = deserialize.generate( deserialize.state_file_content, yamlscript_utils.YSOrderedDict() ) yamlscript_utils.Cache.set(sls, deserialize) # Set _globals; used for evaluation of code if kwargs['sls_type'] == 'state': # Call pyobjects to build globals and provide functions to create states pyobjects = kwargs['renderers']['pyobjects'] _globals = pyobjects(template, saltenv, sls, salt_data=False, **kwargs) _globals['__utils__'] = get_dunder('__utils__') else: # Add some convenience methods to the global scope as well as the "dunder" # format of all of the salt objects _globals = {} for dunder in dunders: _globals[dunder] = get_dunder(dunder) _globals[dunder.replace('_', '')] = get_dunder(dunder) _globals['pillar'] = _globals.get('salt')['pillar.get'] _globals['grains'] = _globals.get('salt')['grains.get'] _globals['mine'] = _globals.get('salt')['mine.get'] _globals['config'] = _globals.get('salt')['config.get'] # Use copy of __pillar__ and __grains__ dictionaries salt_dunders = ['__pillar__', '__grains__'] for dunder in salt_dunders: _globals[dunder] = copy.deepcopy(_globals[dunder]) # Additional globals _globals['__context__'] = dict(state_list=deserialize.state_list) _globals['saltenv'] = saltenv # Can't use pyobject global 'salt' since we need to import salt classes _globals.pop('salt', None) rendered = Render(script_data, kwargs['sls_type'], _globals=_globals) # If its a pillar or template, return it now if kwargs['sls_type'] in ['pillar', 'template']: return rendered.salt_data salt_data = Registry.salt_data() # Run tests if state file provided a test file location. Tests will # compare the salt_data to an expected result retreived from test file if len(yamlscript_utils.Cache.all()) == 1: if deserialize.test_data: yamlscript_utils.test(salt_data, deserialize.test_data, sls=sls) # Clean up cache yamlscript_utils.Cache.pop(sls) return salt_data