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
Beispiel #2
0
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!')
Beispiel #6
0
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']})
Beispiel #7
0
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()
Beispiel #8
0
    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)
Beispiel #10
0
    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
Beispiel #11
0
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']})
Beispiel #12
0
    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
Beispiel #13
0
    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()
Beispiel #14
0
    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
Beispiel #15
0
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()
Beispiel #16
0
    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
Beispiel #17
0
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()
Beispiel #18
0
    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()
Beispiel #19
0
    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
Beispiel #20
0
    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()
Beispiel #21
0
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']})
Beispiel #22
0
    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()
Beispiel #23
0
 def setUp(self):
     self.HIGHSTATE = HighState(OPTS)
     self.HIGHSTATE.push_active()
Beispiel #24
0
 def get_render_stack(cls):
     return HighState.get_active()._pydsl_render_stack
Beispiel #25
0
 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', [{}])]))
Beispiel #27
0
 def setUp(self):
     self.HIGHSTATE = HighState(OPTS)
     self.HIGHSTATE.push_active()
Beispiel #28
0
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)
Beispiel #29
0
 def setUp(self):
     self.highstate = HighState(OPTS)
     self.highstate.push_active()
Beispiel #30
0
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)
Beispiel #31
0
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', [{}])]))
Beispiel #32
0
 def setUp(self):
     self.highstate = HighState(OPTS)
     self.highstate.push_active()
Beispiel #33
0
 def get_render_stack(cls):
     return HighState.get_active()._pydsl_render_stack
Beispiel #34
0
 def get_all_decls(cls):
     return HighState.get_active()._pydsl_all_decls
Beispiel #35
0
    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)