def to_highstate(self, slsmod): # generate a state that uses the stateconf.set state, which # is a no-op state, to hold a reference to the sls module # containing the DSL statements. This is to prevent the module # from being GC'ed, so that objects defined in it will be # available while salt is executing the states. slsmod_id = '_slsmod_' + self.name self.state(slsmod_id).stateconf.set(slsmod=slsmod) del self.get_all_decls()[slsmod_id] highstate = OrderedDict() if self.includes: highstate['include'] = [{t[0]: t[1]} for t in self.includes] if self.extends: highstate['extend'] = extend = OrderedDict() for ext in self.extends: extend[ext._id] = ext._repr(context='extend') for decl in self.decls: highstate[decl._id] = decl._repr() if self.included_highstate: errors = [] HighState.get_active().merge_included_states( highstate, self.included_highstate, errors ) if errors: raise PyDslError('\n'.join(errors)) return highstate
class GPGTestCase(TestCase): def setUp(self): self.HIGHSTATE = HighState(OPTS) self.HIGHSTATE.push_active() def tearDown(self): self.HIGHSTATE.pop_active() def render_sls(self, data, sls='', env='base', **kws): return self.HIGHSTATE.state.rend['gpg']( data, env=env, sls=sls, **kws ) def make_decryption_mock(self): decrypted_data_mock = Mock() decrypted_data_mock.ok = True decrypted_data_mock.__str__ = lambda x: DECRYPTED_STRING return decrypted_data_mock @skipIf(not OD_AVAILABLE, 'OrderedDict not available. Skipping.') def make_nested_object(self, s): return OrderedDict([ ('array_key', [1, False, s]), ('string_key', 'A Normal String'), ('dict_key', {1: None}), ]) @patch('gnupg.GPG') def test_homedir_is_passed_to_gpg(self, gpg_mock): self.render_sls({}) gpg_mock.assert_called_with(gnupghome=OPTS['gpg_keydir']) def test_normal_string_is_unchanged(self): s = 'I am just another string' new_s = self.render_sls(s) self.assertEqual(s, new_s) def test_encrypted_string_is_decrypted(self): with patch('gnupg.GPG.decrypt', return_value=self.make_decryption_mock()): new_s = self.render_sls(ENCRYPTED_STRING) self.assertEqual(new_s, DECRYPTED_STRING) def test_encrypted_string_is_unchanged_when_gpg_fails(self): d_mock = self.make_decryption_mock() d_mock.ok = False with patch('gnupg.GPG.decrypt', return_value=d_mock): new_s = self.render_sls(ENCRYPTED_STRING) self.assertEqual(new_s, ENCRYPTED_STRING) def test_nested_object_is_decrypted(self): encrypted_o = self.make_nested_object(ENCRYPTED_STRING) decrypted_o = self.make_nested_object(DECRYPTED_STRING) with patch('gnupg.GPG.decrypt', return_value=self.make_decryption_mock()): new_o = self.render_sls(encrypted_o) self.assertEqual(new_o, decrypted_o)
def test_merge_strategy_same(self): ''' Test to see if the top file that corresponds to the requested env is the one that is used by the state system ''' config = self._make_default_config() config['top_file_merging_strategy'] = 'same' config['environment'] = 'b' highstate = HighState(config) ret = highstate.get_tops() self.assertEqual(ret, OrderedDict([('b', [{}])]))
def test_ordered_merge(self): ''' Test to see if the merger respects environment ordering ''' config = self._make_default_config() config['top_file_merging_strategy'] = 'merge' config['env_order'] = ['b', 'a', 'c'] with patch('salt.fileclient.FSClient.envs', MagicMock(return_value=['a', 'b', 'c'])): highstate = HighState(config) ret = highstate.get_tops() self.assertEqual(ret, OrderedDict([('a', [{}]), ('c', [{}]), ('b', [{}])]))
def __init__(self, sls, saltenv, rendered_sls): self.name = sls self.saltenv = saltenv self.includes = [] self.included_highstate = HighState.get_active().building_highstate self.extends = [] self.decls = [] self.options = Options() self.funcs = [] # track the ordering of state func declarations self.rendered_sls = rendered_sls # a set of names of rendered sls modules if not HighState.get_active(): raise PyDslError('PyDSL only works with a running high state!')
class HighStateTestCase(TestCase): def setUp(self): self.highstate = HighState(OPTS) self.highstate.push_active() def tearDown(self): self.highstate.pop_active() def test_top_matches_with_list(self): top = {'env': {'match': ['state1', 'state2'], 'nomatch': ['state3']}} matches = self.highstate.top_matches(top) self.assertEqual(matches, {'env': ['state1', 'state2']}) def test_top_matches_with_string(self): top = {'env': {'match': 'state1', 'nomatch': 'state2'}} matches = self.highstate.top_matches(top) self.assertEqual(matches, {'env': ['state1']}) def test_matches_whitelist(self): matches = {'env': ['state1', 'state2', 'state3']} matches = self.highstate.matches_whitelist(matches, ['state2']) self.assertEqual(matches, {'env': ['state2']}) def test_matches_whitelist_with_string(self): matches = {'env': ['state1', 'state2', 'state3']} matches = self.highstate.matches_whitelist(matches, 'state2,state3') self.assertEqual(matches, {'env': ['state2', 'state3']})
class CommonTestCaseBoilerplate(TestCase): def setUp(self): self.root_dir = tempfile.mkdtemp(dir=integration.TMP) self.state_tree_dir = os.path.join(self.root_dir, 'state_tree') self.cache_dir = os.path.join(self.root_dir, 'cachedir') if not os.path.isdir(self.root_dir): os.makedirs(self.root_dir) if not os.path.isdir(self.state_tree_dir): os.makedirs(self.state_tree_dir) if not os.path.isdir(self.cache_dir): os.makedirs(self.cache_dir) self.config = salt.config.minion_config(None) self.config['root_dir'] = self.root_dir self.config['state_events'] = False self.config['id'] = 'match' self.config['file_client'] = 'local' self.config['file_roots'] = dict(base=[self.state_tree_dir]) self.config['cachedir'] = self.cache_dir self.config['test'] = False self.config['grains'] = salt.loader.grains(self.config) self.HIGHSTATE = HighState(self.config) self.HIGHSTATE.push_active() def tearDown(self): try: self.HIGHSTATE.pop_active() except IndexError: pass def state_highstate(self, state, dirpath): opts = copy.copy(self.config) opts['file_roots'] = dict(base=[dirpath]) HIGHSTATE = HighState(opts) HIGHSTATE.push_active() try: high, errors = HIGHSTATE.render_highstate(state) if errors: import pprint pprint.pprint('\n'.join(errors)) pprint.pprint(high) out = HIGHSTATE.state.call_high(high) # pprint.pprint(out) finally: HIGHSTATE.pop_active()
def __call__(self, check=True): sls = Sls.get_render_stack()[-1] if self._id in sls.get_all_decls(): last_func = sls.last_func() if last_func and self._mods[-1]._func is not last_func: raise PyDslError( ('Cannot run state({0}: {1}) that is required by a runtime ' 'state({2}: {3}), at compile time.').format( self._mods[-1]._name, self._id, last_func.mod, last_func.mod._state_id ) ) sls.get_all_decls().pop(self._id) sls.decls.remove(self) self._mods[0]._func._remove_auto_require() for m in self._mods: try: sls.funcs.remove(m._func) except ValueError: pass result = HighState.get_active().state.functions['state.high']({self._id: self._repr()}) result = sorted(result.iteritems(), key=lambda t: t[1]['__run_num__']) if check: for k, v in result: if not v['result']: import pprint raise PyDslError( 'Failed executing low state at compile time:\n{0}' .format(pprint.pformat({k:v}))) return result
def setUp(self): ''' Create multiple top files for use in each test ''' self.env1 = {'base': {'*': ['e1_a', 'e1_b', 'e1_c']}} self.env2 = {'base': {'*': ['e2_a', 'e2_b', 'e2_c']}} self.env3 = {'base': {'*': ['e3_a', 'e3_b', 'e3_c']}} self.config = self._make_default_config() self.highstate = HighState(self.config)
def include(self, *sls_names, **kws): if kws.get('env', None) is not None: warn_until( 'Boron', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt Boron.' ) # Backwards compatibility kws['saltenv'] = kws.pop('env') saltenv = kws.get('saltenv', self.saltenv) if kws.get('delayed', False): for incl in sls_names: self.includes.append((saltenv, incl)) return HIGHSTATE = HighState.get_active() global SLS_MATCHES if SLS_MATCHES is None: SLS_MATCHES = HIGHSTATE.top_matches(HIGHSTATE.get_top()) highstate = self.included_highstate slsmods = [] # a list of pydsl sls modules rendered. for sls in sls_names: r_env = '{0}:{1}'.format(saltenv, sls) if r_env not in self.rendered_sls: self.rendered_sls.add(sls) # needed in case the starting sls # uses the pydsl renderer. histates, errors = HIGHSTATE.render_state( sls, saltenv, self.rendered_sls, SLS_MATCHES ) HIGHSTATE.merge_included_states(highstate, histates, errors) if errors: raise PyDslError('\n'.join(errors)) HIGHSTATE.clean_duplicate_extends(highstate) state_id = '_slsmod_{0}'.format(sls) if state_id not in highstate: slsmods.append(None) else: for arg in highstate[state_id]['stateconf']: if isinstance(arg, dict) and iter(arg).next() == 'slsmod': slsmods.append(arg['slsmod']) break if not slsmods: return None return slsmods[0] if len(slsmods) == 1 else slsmods
class HighStateTestCase(TestCase): def setUp(self): self.root_dir = tempfile.mkdtemp(dir=integration.TMP) self.state_tree_dir = os.path.join(self.root_dir, 'state_tree') self.cache_dir = os.path.join(self.root_dir, 'cachedir') if not os.path.isdir(self.root_dir): os.makedirs(self.root_dir) if not os.path.isdir(self.state_tree_dir): os.makedirs(self.state_tree_dir) if not os.path.isdir(self.cache_dir): os.makedirs(self.cache_dir) self.config = salt.config.minion_config(None) self.config['root_dir'] = self.root_dir self.config['state_events'] = False self.config['id'] = 'match' self.config['file_client'] = 'local' self.config['file_roots'] = dict(base=[self.state_tree_dir]) self.config['cachedir'] = self.cache_dir self.config['test'] = False self.highstate = HighState(self.config) self.highstate.push_active() def tearDown(self): self.highstate.pop_active() def test_top_matches_with_list(self): top = {'env': {'match': ['state1', 'state2'], 'nomatch': ['state3']}} matches = self.highstate.top_matches(top) self.assertEqual(matches, {'env': ['state1', 'state2']}) def test_top_matches_with_string(self): top = {'env': {'match': 'state1', 'nomatch': 'state2'}} matches = self.highstate.top_matches(top) self.assertEqual(matches, {'env': ['state1']}) def test_matches_whitelist(self): matches = {'env': ['state1', 'state2', 'state3']} matches = self.highstate.matches_whitelist(matches, ['state2']) self.assertEqual(matches, {'env': ['state2']}) def test_matches_whitelist_with_string(self): matches = {'env': ['state1', 'state2', 'state3']} matches = self.highstate.matches_whitelist(matches, 'state2,state3') self.assertEqual(matches, {'env': ['state2', 'state3']})
def include(self, *sls_names, **kws): if 'env' in kws: warn_until( 'Oxygen', 'Parameter \'env\' has been detected in the argument list. This ' 'parameter is no longer used and has been replaced by \'saltenv\' ' 'as of Salt 2016.11.0. This warning will be removed in Salt Oxygen.' ) kws.pop('env') saltenv = kws.get('saltenv', self.saltenv) if kws.get('delayed', False): for incl in sls_names: self.includes.append((saltenv, incl)) return HIGHSTATE = HighState.get_active() global SLS_MATCHES if SLS_MATCHES is None: SLS_MATCHES = HIGHSTATE.top_matches(HIGHSTATE.get_top()) highstate = self.included_highstate slsmods = [] # a list of pydsl sls modules rendered. for sls in sls_names: r_env = '{0}:{1}'.format(saltenv, sls) if r_env not in self.rendered_sls: self.rendered_sls.add(sls) # needed in case the starting sls uses the pydsl renderer. histates, errors = HIGHSTATE.render_state( sls, saltenv, self.rendered_sls, SLS_MATCHES ) HIGHSTATE.merge_included_states(highstate, histates, errors) if errors: raise PyDslError('\n'.join(errors)) HIGHSTATE.clean_duplicate_extends(highstate) state_id = '_slsmod_{0}'.format(sls) if state_id not in highstate: slsmods.append(None) else: for arg in highstate[state_id]['stateconf']: if isinstance(arg, dict) and next(iter(arg)) == 'slsmod': slsmods.append(arg['slsmod']) break if not slsmods: return None return slsmods[0] if len(slsmods) == 1 else slsmods
def state_highstate(self, state, dirpath): opts = copy.copy(self.config) opts["file_roots"] = dict(base=[dirpath]) HIGHSTATE = HighState(opts) HIGHSTATE.push_active() try: high, errors = HIGHSTATE.render_highstate(state) if errors: import pprint pprint.pprint("\n".join(errors)) pprint.pprint(high) out = HIGHSTATE.state.call_high(high) # pprint.pprint(out) finally: HIGHSTATE.pop_active()
def __call__(self, check=True): sls = Sls.get_render_stack()[-1] if self._id in sls.get_all_decls(): last_func = sls.last_func() if last_func and self._mods[-1]._func is not last_func: raise PyDslError( 'Cannot run state({0}: {1}) that is required by a runtime ' 'state({2}: {3}), at compile time.'.format( self._mods[-1]._name, self._id, last_func.mod, last_func.mod._state_id ) ) sls.get_all_decls().pop(self._id) sls.decls.remove(self) self._mods[0]._func._remove_auto_require() for m in self._mods: try: sls.funcs.remove(m._func) except ValueError: pass result = HighState.get_active().state.functions['state.high']( {self._id: self._repr()} ) if not isinstance(result, dict): # A list is an error raise PyDslError( 'An error occurred while running highstate: {0}'.format( '; '.join(result) ) ) result = sorted(six.iteritems(result), key=lambda t: t[1]['__run_num__']) if check: for k, v in result: if not v['result']: import pprint raise PyDslError( 'Failed executing low state at compile time:\n{0}' .format(pprint.pformat({k: v})) ) return result
def state_highstate(matches, dirpath): OPTS['file_roots'] = dict(base=[dirpath]) HIGHSTATE = HighState(OPTS) HIGHSTATE.push_active() try: high, errors = HIGHSTATE.render_highstate({'base': ['aaa']}) if errors: import pprint pprint.pprint('\n'.join(errors)) pprint.pprint(high) out = HIGHSTATE.state.call_high(high) # pprint.pprint(out) finally: HIGHSTATE.pop_active()
def include(self, *sls_names, **kws): env = kws.get('env', self.env) if kws.get('delayed', False): for incl in sls_names: self.includes.append((env, incl)) return HIGHSTATE = HighState.get_active() global SLS_MATCHES if SLS_MATCHES is None: SLS_MATCHES = HIGHSTATE.top_matches(HIGHSTATE.get_top()) highstate = self.included_highstate slsmods = [] # a list of pydsl sls modules rendered. for sls in sls_names: if sls not in self.rendered_sls: self.rendered_sls.add(sls) # needed in case the starting sls # uses the pydsl renderer. histates, errors = HIGHSTATE.render_state( sls, env, self.rendered_sls, SLS_MATCHES ) HIGHSTATE.merge_included_states(highstate, histates, errors) if errors: raise PyDslError('\n'.join(errors)) HIGHSTATE.clean_duplicate_extends(highstate) state_id = '_slsmod_{0}'.format(sls) if state_id not in highstate: slsmods.append(None) else: for arg in highstate[state_id]['stateconf']: if isinstance(arg, dict) and iter(arg).next() == 'slsmod': slsmods.append(arg['slsmod']) break if not slsmods: return None return slsmods[0] if len(slsmods) == 1 else slsmods
def state_highstate(matches, dirpath): OPTS["file_roots"] = dict(base=[dirpath]) HIGHSTATE = HighState(OPTS) HIGHSTATE.push_active() try: high, errors = HIGHSTATE.render_highstate({"base": ["aaa"]}) if errors: import pprint pprint.pprint("\n".join(errors)) pprint.pprint(high) out = HIGHSTATE.state.call_high(high) # pprint.pprint(out) finally: HIGHSTATE.pop_active()
def state_highstate(self, state, dirpath): opts = copy.copy(self.config) opts['file_roots'] = dict(base=[dirpath]) HIGHSTATE = HighState(opts) HIGHSTATE.push_active() try: high, errors = HIGHSTATE.render_highstate(state) if errors: import pprint pprint.pprint('\n'.join(errors)) pprint.pprint(high) out = HIGHSTATE.state.call_high(high) # pprint.pprint(out) finally: HIGHSTATE.pop_active()
def include(self, *sls_names, **kws): env = kws.get('env', self.env) if kws.get('delayed', False): for incl in sls_names: self.includes.append((env, incl)) return HIGHSTATE = HighState.get_active() global SLS_MATCHES if SLS_MATCHES is None: SLS_MATCHES = HIGHSTATE.top_matches(HIGHSTATE.get_top()) highstate = self.included_highstate slsmods = [] # a list of pydsl sls modules rendered. for sls in sls_names: if sls not in self.rendered_sls: self.rendered_sls.add( sls ) # needed in case the starting sls uses the pydsl renderer. histates, errors = HIGHSTATE.render_state( sls, env, self.rendered_sls, SLS_MATCHES) HIGHSTATE.merge_included_states(highstate, histates, errors) if errors: raise PyDslError('\n'.join(errors)) HIGHSTATE.clean_duplicate_extends(highstate) id = '_slsmod_' + sls if id not in highstate: slsmods.append(None) else: for arg in highstate[id]['stateconf']: if isinstance(arg, dict) and iter(arg).next() == 'slsmod': slsmods.append(arg['slsmod']) break if not slsmods: return None return slsmods[0] if len(slsmods) == 1 else slsmods
def setUp(self): self.root_dir = tempfile.mkdtemp(dir=integration.TMP) self.state_tree_dir = os.path.join(self.root_dir, 'state_tree') self.cache_dir = os.path.join(self.root_dir, 'cachedir') if not os.path.isdir(self.root_dir): os.makedirs(self.root_dir) if not os.path.isdir(self.state_tree_dir): os.makedirs(self.state_tree_dir) if not os.path.isdir(self.cache_dir): os.makedirs(self.cache_dir) self.config = salt.config.minion_config(None) self.config['root_dir'] = self.root_dir self.config['state_events'] = False self.config['id'] = 'match' self.config['file_client'] = 'local' self.config['file_roots'] = dict(base=[self.state_tree_dir]) self.config['cachedir'] = self.cache_dir self.config['test'] = False self.highstate = HighState(self.config) self.highstate.push_active()
class HighStateTestCase(TestCase): def setUp(self): self.highstate = HighState(OPTS) self.highstate.push_active() def tearDown(self): self.highstate.pop_active() def test_top_matches_with_list(self): top = {'env': {'match': ['state1', 'state2'], 'nomatch': ['state3']}} matches = self.highstate.top_matches(top) self.assertEqual(matches, {'env': ['state1', 'state2']}) def test_top_matches_with_string(self): top = {'env': {'match': 'state1', 'nomatch': 'state2'}} matches = self.highstate.top_matches(top) self.assertEqual(matches, {'env': ['state1']})
def setUp(self): self.root_dir = tempfile.mkdtemp(dir=integration.TMP) self.state_tree_dir = os.path.join(self.root_dir, "state_tree") self.cache_dir = os.path.join(self.root_dir, "cachedir") if not os.path.isdir(self.root_dir): os.makedirs(self.root_dir) if not os.path.isdir(self.state_tree_dir): os.makedirs(self.state_tree_dir) if not os.path.isdir(self.cache_dir): os.makedirs(self.cache_dir) self.config = salt.config.minion_config(None) self.config["root_dir"] = self.root_dir self.config["state_events"] = False self.config["id"] = "match" self.config["file_client"] = "local" self.config["file_roots"] = dict(base=[self.state_tree_dir]) self.config["cachedir"] = self.cache_dir self.config["test"] = False self.config["grains"] = salt.loader.grains(self.config) self.HIGHSTATE = HighState(self.config) self.HIGHSTATE.push_active()
def setUp(self): self.HIGHSTATE = HighState(OPTS) self.HIGHSTATE.push_active()
def get_render_stack(cls): return HighState.get_active()._pydsl_render_stack
def get_all_decls(cls): return HighState.get_active()._pydsl_all_decls
class TopFileMergeTestCase(TestCase): ''' Test various merge strategies for multiple tops files collected from multiple environments. Various options correspond to merge strategies which can be set by the user with the top_file_merging_strategy config option. Refs #12483 ''' def setUp(self): ''' Create multiple top files for use in each test ''' self.env1 = {'base': {'*': ['e1_a', 'e1_b', 'e1_c']}} self.env2 = {'base': {'*': ['e2_a', 'e2_b', 'e2_c']}} self.env3 = {'base': {'*': ['e3_a', 'e3_b', 'e3_c']}} self.config = self._make_default_config() self.highstate = HighState(self.config) def _make_default_config(self): config = salt.config.minion_config(None) root_dir = tempfile.mkdtemp(dir=integration.TMP) state_tree_dir = os.path.join(root_dir, 'state_tree') cache_dir = os.path.join(root_dir, 'cachedir') config['root_dir'] = root_dir config['state_events'] = False config['id'] = 'match' config['file_client'] = 'local' config['file_roots'] = dict(base=[state_tree_dir]) config['cachedir'] = cache_dir config['test'] = False return config def _get_tops(self): ''' A test helper to emulate HighState.get_tops() but just to construct an appropriate data structure for top files from multiple environments ''' tops = DefaultOrderedDict(list) tops['a'].append(self.env1) tops['b'].append(self.env2) tops['c'].append(self.env3) return tops def test_basic_merge(self): ''' This is the default approach for Salt. Merge the top files with the earlier appends taking precendence. Since Salt does the appends lexecographically, this is effectively a test against the default lexecographical behaviour. ''' merged_tops = self.highstate.merge_tops(self._get_tops()) expected_merge = DefaultOrderedDict(OrderedDict) expected_merge['base']['*'] = ['e1_c', 'e1_b', 'e1_a'] self.assertEqual(merged_tops, expected_merge) def test_merge_strategy_same(self): ''' Test to see if the top file that corresponds to the requested env is the one that is used by the state system ''' config = self._make_default_config() config['top_file_merging_strategy'] = 'same' config['environment'] = 'b' highstate = HighState(config) ret = highstate.get_tops() self.assertEqual(ret, OrderedDict([('b', [{}])])) def test_ordered_merge(self): ''' Test to see if the merger respects environment ordering ''' config = self._make_default_config() config['top_file_merging_strategy'] = 'merge' config['env_order'] = ['b', 'a', 'c'] with patch('salt.fileclient.FSClient.envs', MagicMock(return_value=['a', 'b', 'c'])): highstate = HighState(config) ret = highstate.get_tops() self.assertEqual(ret, OrderedDict([('a', [{}]), ('c', [{}]), ('b', [{}])]))
class PyDSLRendererTestCase(TestCase): def setUp(self): self.HIGHSTATE = HighState(OPTS) self.HIGHSTATE.push_active() def tearDown(self): self.HIGHSTATE.pop_active() def render_sls(self, content, sls='', env='base', **kws): return self.HIGHSTATE.state.rend['pydsl']( StringIO(content), env=env, sls=sls, **kws ) def test_state_declarations(self): result = self.render_sls(''' state('A').cmd.run('ls -la', cwd='/var/tmp') state().file.managed('myfile.txt', source='salt://path/to/file') state('X').cmd('run', 'echo hello world', cwd='/') a_cmd = state('A').cmd a_cmd.run(shell='/bin/bash') state('A').service.running(name='apache') ''') self.assertTrue('A' in result and 'X' in result) A_cmd = result['A']['cmd'] self.assertEqual(A_cmd[0], 'run') self.assertEqual(A_cmd[1]['name'], 'ls -la') self.assertEqual(A_cmd[2]['cwd'], '/var/tmp') self.assertEqual(A_cmd[3]['shell'], '/bin/bash') A_service = result['A']['service'] self.assertEqual(A_service[0], 'running') self.assertEqual(A_service[1]['name'], 'apache') X_cmd = result['X']['cmd'] self.assertEqual(X_cmd[0], 'run') self.assertEqual(X_cmd[1]['name'], 'echo hello world') self.assertEqual(X_cmd[2]['cwd'], '/') del result['A'] del result['X'] self.assertEqual(len(result), 2) # 2 rather than 1 because pydsl adds an extra no-op state # declaration. s_iter = result.itervalues() try: s = s_iter.next()['file'] except KeyError: s = s_iter.next()['file'] self.assertEqual(s[0], 'managed') self.assertEqual(s[1]['name'], 'myfile.txt') self.assertEqual(s[2]['source'], 'salt://path/to/file') def test_requisite_declarations(self): result = self.render_sls(''' state('X').cmd.run('echo hello') state('A').cmd.run('mkdir tmp', cwd='/var') state('B').cmd.run('ls -la', cwd='/var/tmp') \ .require(state('X').cmd) \ .require(cmd='A') \ .watch(service='G') state('G').service.running(name='collectd') state('G').service.watch_in(state('A').cmd) state('H').cmd.require_in(cmd='echo hello') state('H').cmd.run('echo world') ''') self.assertTrue(len(result), 6) self.assertTrue(set("X A B G H".split()).issubset(set(result.keys()))) b = result['B']['cmd'] self.assertEqual(b[0], 'run') self.assertEqual(b[1]['name'], 'ls -la') self.assertEqual(b[2]['cwd'], '/var/tmp') self.assertEqual(b[3]['require'][0]['cmd'], 'X') self.assertEqual(b[4]['require'][0]['cmd'], 'A') self.assertEqual(b[5]['watch'][0]['service'], 'G') self.assertEqual(result['G']['service'][2]['watch_in'][0]['cmd'], 'A') self.assertEqual( result['H']['cmd'][1]['require_in'][0]['cmd'], 'echo hello' ) def test_include_extend(self): result = self.render_sls(''' include( 'some.sls.file', 'another.sls.file', 'more.sls.file', delayed=True ) A = state('A').cmd.run('echo hoho', cwd='/') state('B').cmd.run('echo hehe', cwd='/') extend( A, state('X').cmd.run(cwd='/a/b/c'), state('Y').file('managed', name='a_file.txt'), state('Z').service.watch(file='A') ) ''') self.assertEqual(len(result), 4) self.assertEqual( result['include'], [{'base': sls} for sls in ('some.sls.file', 'another.sls.file', 'more.sls.file')] ) extend = result['extend'] self.assertEqual(extend['X']['cmd'][0], 'run') self.assertEqual(extend['X']['cmd'][1]['cwd'], '/a/b/c') self.assertEqual(extend['Y']['file'][0], 'managed') self.assertEqual(extend['Y']['file'][1]['name'], 'a_file.txt') self.assertEqual(len(extend['Z']['service']), 1) self.assertEqual(extend['Z']['service'][0]['watch'][0]['file'], 'A') self.assertEqual(result['B']['cmd'][0], 'run') self.assertTrue('A' not in result) self.assertEqual(extend['A']['cmd'][0], 'run') def test_cmd_call(self): result = self.HIGHSTATE.state.call_template_str('''#!pydsl state('A').cmd.run('echo this is state A', cwd='/') some_var = 12345 def do_something(a, b, *args, **kws): return dict(result=True, changes={'a': a, 'b': b, 'args': args, 'kws': kws, 'some_var': some_var}) state('C').cmd.call(do_something, 1, 2, 3, x=1, y=2) \ .require(state('A').cmd) state('G').cmd.wait('echo this is state G', cwd='/') \ .watch(state('C').cmd) ''') ret = (result[k] for k in result.keys() if 'do_something' in k).next() changes = ret['changes'] self.assertEqual( changes, dict(a=1, b=2, args=(3,), kws=dict(x=1, y=2), some_var=12345) ) ret = (result[k] for k in result.keys() if '-G_' in k).next() self.assertEqual(ret['changes']['stdout'], 'this is state G') def test_multiple_state_func_in_state_mod(self): with self.assertRaisesRegexp(PyDslError, 'Multiple state functions'): self.render_sls(''' state('A').cmd.run('echo hoho') state('A').cmd.wait('echo hehe') ''') def test_no_state_func_in_state_mod(self): with self.assertRaisesRegexp(PyDslError, 'No state function specified'): self.render_sls(''' state('B').cmd.require(cmd='hoho') ''') def test_load_highstate(self): result = self.render_sls(''' import yaml __pydsl__.load_highstate(yaml.load(""" A: cmd.run: - name: echo hello - cwd: / B: pkg: - installed service: - running - require: - pkg: B - watch: - cmd: A """)) state('A').cmd.run(name='echo hello world') ''') self.assertEqual(len(result), 3) self.assertEqual(result['A']['cmd'][0], 'run') self.assertEqual(result['A']['cmd'][1]['name'], 'echo hello') self.assertEqual(result['A']['cmd'][2]['cwd'], '/') self.assertEqual(result['A']['cmd'][3]['name'], 'echo hello world') self.assertEqual(len(result['B']['pkg']), 1) self.assertEqual(result['B']['pkg'][0], 'installed') self.assertEqual(result['B']['service'][0], 'running') self.assertEqual(result['B']['service'][1]['require'][0]['pkg'], 'B') self.assertEqual(result['B']['service'][2]['watch'][0]['cmd'], 'A') def test_ordered_states(self): result = self.render_sls(''' __pydsl__.set(ordered=True) A = state('A') state('B').cmd.run('echo bbbb') A.cmd.run('echo aaa') state('B').cmd.run(cwd='/') state('C').cmd.run('echo ccc') state('B').file.managed(source='/a/b/c') ''') self.assertEqual(len(result['B']['cmd']), 3) self.assertEqual(result['A']['cmd'][1]['require'][0]['cmd'], 'B') self.assertEqual(result['C']['cmd'][1]['require'][0]['cmd'], 'A') self.assertEqual(result['B']['file'][1]['require'][0]['cmd'], 'C') def test_pipe_through_stateconf(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'xxx.sls'), '''#!stateconf -os yaml . jinja .X: cmd.run: - name: echo X >> {0} - cwd: / .Y: cmd.run: - name: echo Y >> {1} - cwd: / .Z: cmd.run: - name: echo Z >> {2} - cwd: / '''.format(output, output, output)) write_to(os.path.join(dirpath, 'yyy.sls'), '''#!pydsl|stateconf -ps __pydsl__.set(ordered=True) state('.D').cmd.run('echo D >> {0}', cwd='/') state('.E').cmd.run('echo E >> {1}', cwd='/') state('.F').cmd.run('echo F >> {2}', cwd='/') '''.format(output, output, output)) write_to(os.path.join(dirpath, 'aaa.sls'), '''#!pydsl|stateconf -ps include('xxx', 'yyy') # make all states in xxx run BEFORE states in this sls. extend(state('.start').stateconf.require(stateconf='xxx::goal')) # make all states in yyy run AFTER this sls. extend(state('.goal').stateconf.require_in(stateconf='yyy::start')) __pydsl__.set(ordered=True) state('.A').cmd.run('echo A >> {0}', cwd='/') state('.B').cmd.run('echo B >> {1}', cwd='/') state('.C').cmd.run('echo C >> {2}', cwd='/') '''.format(output, output, output)) state_highstate({'base': ['aaa']}, dirpath) with open(output, 'r') as f: self.assertEqual(''.join(f.read().split()), "XYZABCDEF") finally: shutil.rmtree(dirpath, ignore_errors=True) def test_rendering_includes(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'aaa.sls'), '''#!pydsl|stateconf -ps include('xxx') yyy = include('yyy') # ensure states in xxx are run first, then those in yyy and then those in aaa last. extend(state('yyy::start').stateconf.require(stateconf='xxx::goal')) extend(state('.start').stateconf.require(stateconf='yyy::goal')) extend(state('yyy::Y2').cmd.run('echo Y2 extended >> {0}')) __pydsl__.set(ordered=True) yyy.hello('red', 1) yyy.hello('green', 2) yyy.hello('blue', 3) '''.format(output)) write_to(os.path.join(dirpath, 'xxx.sls'), '''#!stateconf -os yaml . jinja include: - yyy extend: yyy::start: stateconf.set: - require: - stateconf: .goal yyy::Y1: cmd.run: - name: 'echo Y1 extended >> {0}' .X1: cmd.run: - name: echo X1 >> {1} - cwd: / .X2: cmd.run: - name: echo X2 >> {2} - cwd: / .X3: cmd.run: - name: echo X3 >> {3} - cwd: / '''.format(output, output, output, output)) write_to(os.path.join(dirpath, 'yyy.sls'), '''#!pydsl|stateconf -ps include('xxx') __pydsl__.set(ordered=True) state('.Y1').cmd.run('echo Y1 >> {0}', cwd='/') state('.Y2').cmd.run('echo Y2 >> {1}', cwd='/') state('.Y3').cmd.run('echo Y3 >> {2}', cwd='/') def hello(color, number): state(color).cmd.run('echo hello '+color+' '+str(number)+' >> {3}', cwd='/') '''.format(output, output, output, output)) state_highstate({'base': ['aaa']}, dirpath) expected = ''' X1 X2 X3 Y1 extended Y2 extended Y3 hello red 1 hello green 2 hello blue 3 '''.lstrip() with open(output, 'r') as f: self.assertEqual(sorted(f.read()), sorted(expected)) finally: shutil.rmtree(dirpath, ignore_errors=True) def test_compile_time_state_execution(self): if not sys.stdin.isatty(): self.skipTest('Not attached to a TTY') dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) try: write_to(os.path.join(dirpath, 'aaa.sls'), '''#!pydsl __pydsl__.set(ordered=True) A = state('A') A.cmd.run('echo hehe > {0}/zzz.txt', cwd='/') A.file.managed('{1}/yyy.txt', source='salt://zzz.txt') A() A() state().cmd.run('echo hoho >> {2}/yyy.txt', cwd='/') A.file.managed('{3}/xxx.txt', source='salt://zzz.txt') A() '''.format(dirpath, dirpath, dirpath, dirpath)) state_highstate({'base': ['aaa']}, dirpath) with open(os.path.join(dirpath, 'yyy.txt'), 'r') as f: self.assertEqual(f.read(), 'hehe\nhoho\n') with open(os.path.join(dirpath, 'xxx.txt'), 'r') as f: self.assertEqual(f.read(), 'hehe\n') finally: shutil.rmtree(dirpath, ignore_errors=True) def test_nested_high_state_execution(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'aaa.sls'), '''#!pydsl __salt__['state.sls']('bbb') state().cmd.run('echo bbbbbb', cwd='/') ''') write_to(os.path.join(dirpath, 'bbb.sls'), ''' # {{ salt['state.sls']('ccc') test: cmd.run: - name: echo bbbbbbb - cwd: / ''') write_to(os.path.join(dirpath, 'ccc.sls'), ''' #!pydsl state().cmd.run('echo ccccc', cwd='/') ''') state_highstate({'base': ['aaa']}, dirpath) finally: shutil.rmtree(dirpath, ignore_errors=True)
def setUp(self): self.highstate = HighState(OPTS) self.highstate.push_active()
class PyDSLRendererTestCase(TestCase): def setUp(self): self.HIGHSTATE = HighState(OPTS) self.HIGHSTATE.push_active() def tearDown(self): self.HIGHSTATE.pop_active() def render_sls(self, content, sls='', env='base', **kws): return self.HIGHSTATE.state.rend['pydsl']( StringIO(content), env=env, sls=sls, **kws ) def test_state_declarations(self): result = self.render_sls(textwrap.dedent(''' state('A').cmd.run('ls -la', cwd='/var/tmp') state().file.managed('myfile.txt', source='salt://path/to/file') state('X').cmd('run', 'echo hello world', cwd='/') a_cmd = state('A').cmd a_cmd.run(shell='/bin/bash') state('A').service.running(name='apache') ''')) self.assertTrue('A' in result and 'X' in result) A_cmd = result['A']['cmd'] self.assertEqual(A_cmd[0], 'run') self.assertEqual(A_cmd[1]['name'], 'ls -la') self.assertEqual(A_cmd[2]['cwd'], '/var/tmp') self.assertEqual(A_cmd[3]['shell'], '/bin/bash') A_service = result['A']['service'] self.assertEqual(A_service[0], 'running') self.assertEqual(A_service[1]['name'], 'apache') X_cmd = result['X']['cmd'] self.assertEqual(X_cmd[0], 'run') self.assertEqual(X_cmd[1]['name'], 'echo hello world') self.assertEqual(X_cmd[2]['cwd'], '/') del result['A'] del result['X'] self.assertEqual(len(result), 2) # 2 rather than 1 because pydsl adds an extra no-op state # declaration. s_iter = result.itervalues() try: s = s_iter.next()['file'] except KeyError: s = s_iter.next()['file'] self.assertEqual(s[0], 'managed') self.assertEqual(s[1]['name'], 'myfile.txt') self.assertEqual(s[2]['source'], 'salt://path/to/file') def test_requisite_declarations(self): result = self.render_sls(textwrap.dedent(''' state('X').cmd.run('echo hello') state('A').cmd.run('mkdir tmp', cwd='/var') state('B').cmd.run('ls -la', cwd='/var/tmp') \ .require(state('X').cmd) \ .require(cmd='A') \ .watch(service='G') state('G').service.running(name='collectd') state('G').service.watch_in(state('A').cmd) state('H').cmd.require_in(cmd='echo hello') state('H').cmd.run('echo world') ''')) self.assertTrue(len(result), 6) self.assertTrue(set("X A B G H".split()).issubset(set(result.keys()))) b = result['B']['cmd'] self.assertEqual(b[0], 'run') self.assertEqual(b[1]['name'], 'ls -la') self.assertEqual(b[2]['cwd'], '/var/tmp') self.assertEqual(b[3]['require'][0]['cmd'], 'X') self.assertEqual(b[4]['require'][0]['cmd'], 'A') self.assertEqual(b[5]['watch'][0]['service'], 'G') self.assertEqual(result['G']['service'][2]['watch_in'][0]['cmd'], 'A') self.assertEqual( result['H']['cmd'][1]['require_in'][0]['cmd'], 'echo hello' ) def test_include_extend(self): result = self.render_sls(textwrap.dedent(''' include( 'some.sls.file', 'another.sls.file', 'more.sls.file', delayed=True ) A = state('A').cmd.run('echo hoho', cwd='/') state('B').cmd.run('echo hehe', cwd='/') extend( A, state('X').cmd.run(cwd='/a/b/c'), state('Y').file('managed', name='a_file.txt'), state('Z').service.watch(file='A') ) ''')) self.assertEqual(len(result), 4) self.assertEqual( result['include'], [{'base': sls} for sls in ('some.sls.file', 'another.sls.file', 'more.sls.file')] ) extend = result['extend'] self.assertEqual(extend['X']['cmd'][0], 'run') self.assertEqual(extend['X']['cmd'][1]['cwd'], '/a/b/c') self.assertEqual(extend['Y']['file'][0], 'managed') self.assertEqual(extend['Y']['file'][1]['name'], 'a_file.txt') self.assertEqual(len(extend['Z']['service']), 1) self.assertEqual(extend['Z']['service'][0]['watch'][0]['file'], 'A') self.assertEqual(result['B']['cmd'][0], 'run') self.assertTrue('A' not in result) self.assertEqual(extend['A']['cmd'][0], 'run') def test_cmd_call(self): result = self.HIGHSTATE.state.call_template_str(textwrap.dedent('''\ #!pydsl state('A').cmd.run('echo this is state A', cwd='/') some_var = 12345 def do_something(a, b, *args, **kws): return dict(result=True, changes={'a': a, 'b': b, 'args': args, 'kws': kws, 'some_var': some_var}) state('C').cmd.call(do_something, 1, 2, 3, x=1, y=2) \ .require(state('A').cmd) state('G').cmd.wait('echo this is state G', cwd='/') \ .watch(state('C').cmd) ''')) ret = (result[k] for k in result.keys() if 'do_something' in k).next() changes = ret['changes'] self.assertEqual( changes, dict(a=1, b=2, args=(3,), kws=dict(x=1, y=2), some_var=12345) ) ret = (result[k] for k in result.keys() if '-G_' in k).next() self.assertEqual(ret['changes']['stdout'], 'this is state G') def test_multiple_state_func_in_state_mod(self): with self.assertRaisesRegexp(PyDslError, 'Multiple state functions'): self.render_sls(textwrap.dedent(''' state('A').cmd.run('echo hoho') state('A').cmd.wait('echo hehe') ''')) def test_no_state_func_in_state_mod(self): with self.assertRaisesRegexp(PyDslError, 'No state function specified'): self.render_sls(textwrap.dedent(''' state('B').cmd.require(cmd='hoho') ''')) def test_load_highstate(self): result = self.render_sls(textwrap.dedent(''' import yaml __pydsl__.load_highstate(yaml.load(""" A: cmd.run: - name: echo hello - cwd: / B: pkg: - installed service: - running - require: - pkg: B - watch: - cmd: A """)) state('A').cmd.run(name='echo hello world') ''')) self.assertEqual(len(result), 3) self.assertEqual(result['A']['cmd'][0], 'run') self.assertEqual(result['A']['cmd'][1]['name'], 'echo hello') self.assertEqual(result['A']['cmd'][2]['cwd'], '/') self.assertEqual(result['A']['cmd'][3]['name'], 'echo hello world') self.assertEqual(len(result['B']['pkg']), 1) self.assertEqual(result['B']['pkg'][0], 'installed') self.assertEqual(result['B']['service'][0], 'running') self.assertEqual(result['B']['service'][1]['require'][0]['pkg'], 'B') self.assertEqual(result['B']['service'][2]['watch'][0]['cmd'], 'A') def test_ordered_states(self): result = self.render_sls(textwrap.dedent(''' __pydsl__.set(ordered=True) A = state('A') state('B').cmd.run('echo bbbb') A.cmd.run('echo aaa') state('B').cmd.run(cwd='/') state('C').cmd.run('echo ccc') state('B').file.managed(source='/a/b/c') ''')) self.assertEqual(len(result['B']['cmd']), 3) self.assertEqual(result['A']['cmd'][1]['require'][0]['cmd'], 'B') self.assertEqual(result['C']['cmd'][1]['require'][0]['cmd'], 'A') self.assertEqual(result['B']['file'][1]['require'][0]['cmd'], 'C') def test_pipe_through_stateconf(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'xxx.sls'), textwrap.dedent( '''#!stateconf -os yaml . jinja .X: cmd.run: - name: echo X >> {0} - cwd: / .Y: cmd.run: - name: echo Y >> {1} - cwd: / .Z: cmd.run: - name: echo Z >> {2} - cwd: / '''.format(output, output, output))) write_to(os.path.join(dirpath, 'yyy.sls'), textwrap.dedent('''\ #!pydsl|stateconf -ps __pydsl__.set(ordered=True) state('.D').cmd.run('echo D >> {0}', cwd='/') state('.E').cmd.run('echo E >> {1}', cwd='/') state('.F').cmd.run('echo F >> {2}', cwd='/') '''.format(output, output, output))) write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\ #!pydsl|stateconf -ps include('xxx', 'yyy') # make all states in xxx run BEFORE states in this sls. extend(state('.start').stateconf.require(stateconf='xxx::goal')) # make all states in yyy run AFTER this sls. extend(state('.goal').stateconf.require_in(stateconf='yyy::start')) __pydsl__.set(ordered=True) state('.A').cmd.run('echo A >> {0}', cwd='/') state('.B').cmd.run('echo B >> {1}', cwd='/') state('.C').cmd.run('echo C >> {2}', cwd='/') '''.format(output, output, output))) state_highstate({'base': ['aaa']}, dirpath) with open(output, 'r') as f: self.assertEqual(''.join(f.read().split()), "XYZABCDEF") finally: shutil.rmtree(dirpath, ignore_errors=True) def test_rendering_includes(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\ #!pydsl|stateconf -ps include('xxx') yyy = include('yyy') # ensure states in xxx are run first, then those in yyy and then those in aaa last. extend(state('yyy::start').stateconf.require(stateconf='xxx::goal')) extend(state('.start').stateconf.require(stateconf='yyy::goal')) extend(state('yyy::Y2').cmd.run('echo Y2 extended >> {0}')) __pydsl__.set(ordered=True) yyy.hello('red', 1) yyy.hello('green', 2) yyy.hello('blue', 3) '''.format(output))) write_to(os.path.join(dirpath, 'xxx.sls'), textwrap.dedent('''\ #!stateconf -os yaml . jinja include: - yyy extend: yyy::start: stateconf.set: - require: - stateconf: .goal yyy::Y1: cmd.run: - name: 'echo Y1 extended >> {0}' .X1: cmd.run: - name: echo X1 >> {1} - cwd: / .X2: cmd.run: - name: echo X2 >> {2} - cwd: / .X3: cmd.run: - name: echo X3 >> {3} - cwd: / '''.format(output, output, output, output))) write_to(os.path.join(dirpath, 'yyy.sls'), textwrap.dedent('''\ #!pydsl|stateconf -ps include('xxx') __pydsl__.set(ordered=True) state('.Y1').cmd.run('echo Y1 >> {0}', cwd='/') state('.Y2').cmd.run('echo Y2 >> {1}', cwd='/') state('.Y3').cmd.run('echo Y3 >> {2}', cwd='/') def hello(color, number): state(color).cmd.run('echo hello '+color+' '+str(number)+' >> {3}', cwd='/') '''.format(output, output, output, output))) state_highstate({'base': ['aaa']}, dirpath) expected = textwrap.dedent('''\ X1 X2 X3 Y1 extended Y2 extended Y3 hello red 1 hello green 2 hello blue 3 ''') with open(output, 'r') as f: self.assertEqual(sorted(f.read()), sorted(expected)) finally: shutil.rmtree(dirpath, ignore_errors=True) def test_compile_time_state_execution(self): if not sys.stdin.isatty(): self.skipTest('Not attached to a TTY') dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) try: write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\ #!pydsl __pydsl__.set(ordered=True) A = state('A') A.cmd.run('echo hehe > {0}/zzz.txt', cwd='/') A.file.managed('{1}/yyy.txt', source='salt://zzz.txt') A() A() state().cmd.run('echo hoho >> {2}/yyy.txt', cwd='/') A.file.managed('{3}/xxx.txt', source='salt://zzz.txt') A() '''.format(dirpath, dirpath, dirpath, dirpath))) state_highstate({'base': ['aaa']}, dirpath) with open(os.path.join(dirpath, 'yyy.txt'), 'r') as f: self.assertEqual(f.read(), 'hehe\nhoho\n') with open(os.path.join(dirpath, 'xxx.txt'), 'r') as f: self.assertEqual(f.read(), 'hehe\n') finally: shutil.rmtree(dirpath, ignore_errors=True) def test_nested_high_state_execution(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\ #!pydsl __salt__['state.sls']('bbb') state().cmd.run('echo bbbbbb', cwd='/') ''')) write_to(os.path.join(dirpath, 'bbb.sls'), textwrap.dedent( ''' # {{ salt['state.sls']('ccc') test: cmd.run: - name: echo bbbbbbb - cwd: / ''')) write_to(os.path.join(dirpath, 'ccc.sls'), textwrap.dedent( ''' #!pydsl state().cmd.run('echo ccccc', cwd='/') ''')) state_highstate({'base': ['aaa']}, dirpath) finally: shutil.rmtree(dirpath, ignore_errors=True) def test_repeat_includes(self): dirpath = tempfile.mkdtemp(dir=integration.SYS_TMP_DIR) if not os.path.isdir(dirpath): self.skipTest( 'The temporary directory {0!r} was not created'.format( dirpath ) ) output = os.path.join(dirpath, 'output') try: write_to(os.path.join(dirpath, 'b.sls'), textwrap.dedent('''\ #!pydsl include('c') include('d') ''')) write_to(os.path.join(dirpath, 'c.sls'), textwrap.dedent('''\ #!pydsl modtest = include('e') modtest.success ''')) write_to(os.path.join(dirpath, 'd.sls'), textwrap.dedent('''\ #!pydsl modtest = include('e') modtest.success ''')) write_to(os.path.join(dirpath, 'e.sls'), textwrap.dedent('''\ #!pydsl success = True ''')) state_highstate({'base': ['b']}, dirpath) state_highstate({'base': ['c', 'd']}, dirpath) finally: shutil.rmtree(dirpath, ignore_errors=True)
def test_pipe_through_stateconf(self): if sys.version_info < (2, 7) and not HAS_ORDERED_DICT: self.skipTest('OrderedDict is not available') dirpath = tempfile.mkdtemp() output = os.path.join(dirpath, 'output') try: xxx = os.path.join(dirpath, 'xxx.sls') with open(xxx, 'w') as xxx: xxx.write('''#!stateconf -os yaml . jinja .X: cmd.run: - name: echo X >> {0} - cwd: / .Y: cmd.run: - name: echo Y >> {1} - cwd: / .Z: cmd.run: - name: echo Z >> {2} - cwd: / '''.format(output, output, output)) yyy = os.path.join(dirpath, 'yyy.sls') with open(yyy, 'w') as yyy: yyy.write('''#!pydsl|stateconf -ps state('.D').cmd.run('echo D >> {0}', cwd='/') state('.E').cmd.run('echo E >> {1}', cwd='/') state('.F').cmd.run('echo F >> {2}', cwd='/') '''.format(output, output, output)) aaa = os.path.join(dirpath, 'aaa.sls') with open(aaa, 'w') as aaa: aaa.write('''#!pydsl|stateconf -ps include('xxx', 'yyy') # make all states in yyy run BEFORE states in this sls. extend(state('.start').stateconf.require(stateconf='xxx::goal')) # make all states in xxx run AFTER this sls. extend(state('.goal').stateconf.require_in(stateconf='yyy::start')) __pydsl__.set(ordered=True) state('.A').cmd.run('echo A >> {0}', cwd='/') state('.B').cmd.run('echo B >> {1}', cwd='/') state('.C').cmd.run('echo C >> {2}', cwd='/') '''.format(output, output, output)) OPTS['file_roots'] = dict(base=[dirpath]) HIGHSTATE = HighState(OPTS) HIGHSTATE.state.load_modules() sys.modules['salt.loaded.int.render.pydsl'].__salt__ = HIGHSTATE.state.functions high, errors = HIGHSTATE.render_highstate({'base': ['aaa']}) # import pprint # pprint.pprint(errors) # pprint.pprint(high) out = HIGHSTATE.state.call_high(high) # pprint.pprint(out) with open(output, 'r') as f: self.assertEqual(''.join(f.read().split()), "XYZABCDEF") finally: shutil.rmtree(dirpath, ignore_errors=True)