class TestPlumberyText(unittest.TestCase):

    def setUp(self):
        self.text = PlumberyText()

    def tearDown(self):
        pass

    def test_dictionary(self):

        template = 'little {{ test }} with multiple {{test}} and {{}} as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        expected = 'little toast with multiple toast and {{}} as well'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

    def test_engine(self):

        engine = PlumberyEngine()
        context = PlumberyContext(context=engine)

        template = "we are running plumbery {{ plumbery.version }}"
        expected = "we are running plumbery "+__version__
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        engine.set_user_name('fake_name')
        engine.set_user_password('fake_password')

        template = "{{ name.credentials }} {{ password.credentials }}"
        expected = engine.get_user_name()+" "+engine.get_user_password()
        self.assertEqual(
            self.text.expand_string(template, context), expected)

    def test_bad_parameters(self):

        with self.assertRaises(TypeError):
            self.text.expand_parameters(1234, {})
        with self.assertRaises(TypeError):
            self.text.expand_parameters({}, {})

        template = 'little {{ test with multiple {{test and {{ as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(
            self.text.expand_parameters(template, context), template)

        template = 'little {{ }} test and {{      }} as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(
            self.text.expand_parameters(template, context), template)

        template = "{{ parameter.is.unknown }}"
        context = PlumberyContext(dictionary={'test': 'toast'})
        with self.assertRaises(KeyError):
            self.text.expand_parameters(template, context)

    def test_bad_string(self):

        self.text.expand_string(1234, {})
        self.text.expand_string({}, {})

        template = 'little {{ test with multiple {{test and {{ as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(
            self.text.expand_string(template, context), template)

        template = 'little {{ }} test and {{      }} as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(
            self.text.expand_string(template, context), template)

        template = "{{ secret.is.unknown }}"
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(
            self.text.expand_string(template, context), template)

    def test_could_expand(self):

        template = 'little {{ test with multiple {{test and {{ as well'
        self.assertTrue(self.text.could_expand(template))

#        template = b'\x00\xFF\x00\xFF'
#        self.assertFalse(self.text.could_expand(template))

    def test_input1(self):

        context = PlumberyContext(dictionary={'node.private': '12.34.56.78'})
        self.assertEqual(
            self.text.expand_string(input1, context), expected1)

    def test_input2(self):

        context = PlumberyContext(dictionary={})
        transformed = yaml.load(self.text.expand_string(input2, context))
        unmatched = {o: (input2[o], transformed[o])
                     for o in input2.keys()
                     if input2[o] != transformed[o]}
        if unmatched != {}:
            print(unmatched)
        self.assertEqual(len(unmatched), 0)

        context = PlumberyContext(dictionary={'node.private': '12.34.56.78'})
        transformed = yaml.load(self.text.expand_string(input2, context))
        unmatched = {o: (expected2[o], transformed[o])
                     for o in expected2.keys()
                     if expected2[o] != transformed[o]}
        if unmatched != {}:
            print(unmatched)
        self.assertEqual(len(unmatched), 0)

    def test_input3(self):

        loaded = yaml.load(input3)
        context = PlumberyContext(dictionary={'node.public': '12.34.56.78'})
        transformed = yaml.load(self.text.expand_string(loaded, context))
        self.assertEqual(transformed, yaml.load(expected3))

    def test_input4(self):

        loaded = yaml.load(input4)
        context = PlumberyContext(dictionary={})
        transformed = yaml.load(self.text.expand_string(loaded, context))
        self.assertEqual(transformed, loaded)

    def test_input5(self):

        loaded = yaml.load(input5)
        context = PlumberyContext(dictionary={})
        transformed = yaml.load(self.text.expand_string(loaded, context))
        self.assertEqual(transformed, loaded)

    def test_input6(self):

        loaded = yaml.load(input6)
        context = PlumberyContext(dict6)
        transformed = self.text.expand_string(loaded, context)
        self.assertEqual(transformed.strip(), expected6.strip())

    def test_input7(self):

        loaded = yaml.load(input7)
        context = PlumberyContext(dict7)
        transformed = self.text.expand_string(loaded, context)
        self.assertEqual(transformed.strip(), expected7.strip())

    def test_input8(self):

        loaded = yaml.load(input8)
        context = PlumberyContext(dictionary={})
        expanded = self.text.expand_string(loaded, context)
        self.assertEqual(expanded.strip(), input8.strip())

    def test_input9(self):

        loaded = yaml.load(input9)
        context = PlumberyContext(context=PlumberyEngine())
        expanded = self.text.expand_string(loaded, context)
        self.assertEqual(('  - |' in expanded), False)

    def test_input10(self):

        loaded = yaml.load(input10)
        context = PlumberyContext(dictionary={})
        expanded = self.text.expand_string(loaded, context)
        self.assertEqual(expanded.strip(), input10.strip())

    def test_node1(self):

        template = "{{ mongo_mongos01.public }}"
        context = PlumberyNodeContext(node=FakeNode1())
        expected = '168.128.12.163'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        template = "{{mongo_mongos01.private }}"
        expected = '192.168.50.11'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos01}}"
        expected = '192.168.50.11'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos01.ipv6 }}"
        expected = '2a00:47c0:111:1136:47c9:5a6a:911d:6c7f'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

    def test_node2(self):

        template = "{{ mongo_mongos02.public }}"
        context = PlumberyNodeContext(node=FakeNode1(),
                                      container=FakeContainer())
        expected = '168.128.12.164'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos02.private }}"
        expected = '192.168.50.12'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos02 }}"
        expected = '192.168.50.12'
        self.assertEqual(
            self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos02.ipv6 }}"
        expected = '2a00:47c0:111:1136:47c9:5a6a:911d:6c7f'
        self.assertEqual(
            self.text.expand_string(template, context), expected)
Beispiel #2
0
    def _get_prepares(self, node, settings, container):
        """
        Defines the set of actions to be done on a node

        :param node: the node to be polished
        :type node: :class:`libcloud.compute.base.Node`

        :param settings: the fittings plan for this node
        :type settings: ``dict``

        :param container: the container of this node
        :type container: :class:`plumbery.PlumberyInfrastructure`

        :return: a list of actions to be performed, and related descriptions
        :rtype: a ``list`` of `{ 'description': ..., 'genius': ... }``

        """

        if not isinstance(settings, dict):
            return []

        environment = PlumberyNodeContext(node=node,
                                          container=container,
                                          context=self.facility)

        prepares = []

        for key_file in self.key_files:
            try:
                path = os.path.expanduser(key_file)

                with open(path) as stream:
                    key = stream.read()
                    stream.close()

                prepares.append({
                    'description': 'deploy SSH public key',
                    'genius': SSHKeyDeployment(key=key)
                })

            except IOError:
                plogging.warning("no ssh key in {}".format(key_file))

        if ('prepare' in settings and isinstance(settings['prepare'], list)
                and len(settings['prepare']) > 0):

            plogging.info('- using prepare commands')

            for script in settings['prepare']:

                tokens = script.split(' ')
                if len(tokens) == 1:
                    tokens.insert(0, 'run')

                if tokens[0] in ['run', 'run_raw']:  # send and run a script

                    script = tokens[1]
                    if len(tokens) > 2:
                        args = tokens[2:]
                    else:
                        args = []

                    plogging.debug("- {} {} {}".format(tokens[0], script,
                                                       ' '.join(args)))

                    try:
                        with open(script) as stream:
                            text = stream.read()

                            if (tokens[0] == 'run'
                                    and PlumberyText.could_expand(text)):

                                plogging.debug(
                                    "- expanding script '{}'".format(script))
                                text = PlumberyText.expand_string(
                                    text, environment)

                            if len(text) > 0:

                                plogging.info("- running '{}'".format(script))

                                prepares.append({
                                    'description':
                                    ' '.join(tokens),
                                    'genius':
                                    ScriptDeployment(script=text,
                                                     args=args,
                                                     name=script)
                                })

                            else:
                                plogging.error(
                                    "- script '{}' is empty".format(script))

                    except IOError:
                        plogging.error(
                            "- unable to read script '{}'".format(script))

                elif tokens[0] in ['put', 'put_raw']:  # send a file

                    file = tokens[1]
                    if len(tokens) > 2:
                        destination = tokens[2]
                    else:
                        destination = './' + file

                    plogging.debug("- {} {} {}".format(tokens[0], file,
                                                       destination))

                    try:
                        with open(file) as stream:
                            content = stream.read()

                            if (tokens[0] == 'put'
                                    and PlumberyText.could_expand(content)):

                                plogging.debug(
                                    "- expanding file '{}'".format(file))
                                content = PlumberyText.expand_string(
                                    content, environment)

                            plogging.info("- putting file '{}'".format(file))
                            prepares.append({
                                'description':
                                ' '.join(tokens),
                                'genius':
                                FileContentDeployment(content=content,
                                                      target=destination)
                            })

                    except IOError:
                        plogging.error(
                            "- unable to read file '{}'".format(file))

                else:  # echo a sensible message eventually

                    if tokens[0] == 'echo':
                        tokens.pop(0)
                    message = ' '.join(tokens)
                    message = PlumberyText.expand_string(message, environment)
                    plogging.info("- {}".format(message))

        if ('cloud-config' in settings
                and isinstance(settings['cloud-config'], dict)
                and len(settings['cloud-config']) > 0):

            plogging.info('- using cloud-config')

            # mandatory, else cloud-init will not consider user-data
            plogging.debug('- preparing meta-data')
            meta_data = 'instance_id: dummy\n'

            destination = '/var/lib/cloud/seed/nocloud-net/meta-data'
            prepares.append({
                'description':
                'put meta-data',
                'genius':
                FileContentDeployment(content=meta_data, target=destination)
            })

            plogging.debug('- preparing user-data')

            expanded = PlumberyText.expand_string(settings['cloud-config'],
                                                  environment)

            user_data = '#cloud-config\n' + expanded
            plogging.debug(user_data)

            destination = '/var/lib/cloud/seed/nocloud-net/user-data'
            prepares.append({
                'description':
                'put user-data',
                'genius':
                FileContentDeployment(content=user_data, target=destination)
            })

            plogging.debug('- preparing remote install of cloud-init')

            script = 'prepare.cloud-init.sh'
            try:
                path = os.path.dirname(__file__) + '/' + script
                with open(path) as stream:
                    text = stream.read()
                    if text:
                        prepares.append({
                            'description':
                            'run ' + script,
                            'genius':
                            ScriptDeployment(script=text, name=script)
                        })

            except IOError:
                raise PlumberyException(
                    "Error: cannot read '{}'".format(script))

            plogging.debug('- preparing reboot to trigger cloud-init')

            prepares.append({
                'description': 'reboot node',
                'genius': RebootDeployment(container=container)
            })

        return prepares
    def _get_prepares(self, node, settings, container):
        """
        Defines the set of actions to be done on a node

        :param node: the node to be polished
        :type node: :class:`libcloud.compute.base.Node`

        :param settings: the fittings plan for this node
        :type settings: ``dict``

        :param container: the container of this node
        :type container: :class:`plumbery.PlumberyInfrastructure`

        :return: a list of actions to be performed, and related descriptions
        :rtype: a ``list`` of `{ 'description': ..., 'genius': ... }``

        """

        if not isinstance(settings, dict):
            return []

        environment = PlumberyNodeContext(node=node,
                                          container=container,
                                          context=self.facility)

        prepares = []

        if self.key is not None:
            prepares.append({
                'description': 'deploy SSH public key',
                'genius': SSHKeyDeployment(self.key)})

        if ('prepare' in settings
                and isinstance(settings['prepare'], list)
                and len(settings['prepare']) > 0):

            plogging.info('- using prepare commands')

            for script in settings['prepare']:

                tokens = script.split(' ')
                if len(tokens) == 1:
                    tokens.insert(0, 'run')

                if tokens[0] in ['run', 'run_raw']:  # send and run a script

                    script = tokens[1]
                    if len(tokens) > 2:
                        args = tokens[2:]
                    else:
                        args = []

                    plogging.debug("- {} {} {}".format(
                        tokens[0], script, ' '.join(args)))

                    try:
                        with open(script) as stream:
                            text = stream.read()

                            if(tokens[0] == 'run'
                                    and PlumberyText.could_expand(text)):

                                plogging.debug("- expanding script '{}'"
                                              .format(script))
                                text = PlumberyText.expand_string(
                                    text, environment)

                            if len(text) > 0:

                                plogging.info("- running '{}'"
                                                  .format(script))

                                prepares.append({
                                    'description': ' '.join(tokens),
                                    'genius': ScriptDeployment(
                                        script=text,
                                        args=args,
                                        name=script)})

                            else:
                                plogging.error("- script '{}' is empty"
                                              .format(script))

                    except IOError:
                        plogging.error("- unable to read script '{}'"
                                      .format(script))

                elif tokens[0] in ['put', 'put_raw']:  # send a file

                    file = tokens[1]
                    if len(tokens) > 2:
                        destination = tokens[2]
                    else:
                        destination = './'+file

                    plogging.debug("- {} {} {}".format(
                        tokens[0], file, destination))

                    try:
                        with open(file) as stream:
                            content = stream.read()

                            if(tokens[0] == 'put'
                                    and PlumberyText.could_expand(content)):

                                plogging.debug("- expanding file '{}'"
                                              .format(file))
                                content = PlumberyText.expand_string(
                                    content, environment)

                            plogging.info("- putting file '{}'"
                                              .format(file))
                            prepares.append({
                                'description': ' '.join(tokens),
                                'genius': FileContentDeployment(
                                    content=content,
                                    target=destination)})

                    except IOError:
                        plogging.error("- unable to read file '{}'"
                                      .format(file))

                else:  # echo a sensible message eventually

                    if tokens[0] == 'echo':
                        tokens.pop(0)
                    message = ' '.join(tokens)
                    message = PlumberyText.expand_string(
                        message, environment)
                    plogging.info("- {}".format(message))

        if ('cloud-config' in settings
                and isinstance(settings['cloud-config'], dict)
                and len(settings['cloud-config']) > 0):

            plogging.info('- using cloud-config')

            # mandatory, else cloud-init will not consider user-data
            plogging.debug('- preparing meta-data')
            meta_data = 'instance_id: dummy\n'

            destination = '/var/lib/cloud/seed/nocloud-net/meta-data'
            prepares.append({
                'description': 'put meta-data',
                'genius': FileContentDeployment(
                    content=meta_data,
                    target=destination)})

            plogging.debug('- preparing user-data')

            expanded = PlumberyText.expand_string(
                settings['cloud-config'], environment)

            user_data = '#cloud-config\n'+expanded
            plogging.debug(user_data)

            destination = '/var/lib/cloud/seed/nocloud-net/user-data'
            prepares.append({
                'description': 'put user-data',
                'genius': FileContentDeployment(
                    content=user_data,
                    target=destination)})

            plogging.debug('- preparing remote install of cloud-init')

            script = 'prepare.cloud-init.sh'
            try:
                path = os.path.dirname(__file__)+'/'+script
                with open(path) as stream:
                    text = stream.read()
                    if text:
                        prepares.append({
                            'description': 'run '+script,
                            'genius': ScriptDeployment(
                                script=text,
                                name=script)})

            except IOError:
                raise PlumberyException("Error: cannot read '{}'"
                                        .format(script))

            plogging.debug('- preparing reboot to trigger cloud-init')

            prepares.append({
                'description': 'reboot node',
                'genius': RebootDeployment(
                    container=container)})

        return prepares
Beispiel #4
0
class TestPlumberyText(unittest.TestCase):
    def setUp(self):
        self.text = PlumberyText()

    def tearDown(self):
        pass

    def test_dictionary(self):

        template = 'little {{ test }} with multiple {{test}} and {{}} as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        expected = 'little toast with multiple toast and {{}} as well'
        self.assertEqual(self.text.expand_string(template, context), expected)

    def test_engine(self):

        engine = PlumberyEngine()
        context = PlumberyContext(context=engine)

        template = "we are running plumbery {{ plumbery.version }}"
        expected = "we are running plumbery " + __version__
        self.assertEqual(self.text.expand_string(template, context), expected)

        engine.set_user_name('fake_name')
        engine.set_user_password('fake_password')

        template = "{{ name.credentials }} {{ password.credentials }}"
        expected = engine.get_user_name() + " " + engine.get_user_password()
        self.assertEqual(self.text.expand_string(template, context), expected)

    def test_bad_parameters(self):

        with self.assertRaises(TypeError):
            self.text.expand_parameters(1234, {})
        with self.assertRaises(TypeError):
            self.text.expand_parameters({}, {})

        template = 'little {{ test with multiple {{test and {{ as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(self.text.expand_parameters(template, context),
                         template)

        template = 'little {{ }} test and {{      }} as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(self.text.expand_parameters(template, context),
                         template)

        template = "{{ parameter.is.unknown }}"
        context = PlumberyContext(dictionary={'test': 'toast'})
        with self.assertRaises(KeyError):
            self.text.expand_parameters(template, context)

    def test_bad_string(self):

        self.text.expand_string(1234, {})
        self.text.expand_string({}, {})

        template = 'little {{ test with multiple {{test and {{ as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(self.text.expand_string(template, context), template)

        template = 'little {{ }} test and {{      }} as well'
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(self.text.expand_string(template, context), template)

        template = "{{ secret.is.unknown }}"
        context = PlumberyContext(dictionary={'test': 'toast'})
        self.assertEqual(self.text.expand_string(template, context), template)

    def test_could_expand(self):

        template = 'little {{ test with multiple {{test and {{ as well'
        self.assertTrue(self.text.could_expand(template))

        template = b'\x00\xFF\x00\xFF'
        self.assertFalse(self.text.could_expand(template))

    def test_input1(self):

        context = PlumberyContext(dictionary={'node.private': '12.34.56.78'})
        self.assertEqual(self.text.expand_string(input1, context), expected1)

    def test_input2(self):

        context = PlumberyContext(dictionary={})
        transformed = yaml.load(self.text.expand_string(input2, context))
        unmatched = {
            o: (input2[o], transformed[o])
            for o in input2.keys() if input2[o] != transformed[o]
        }
        if unmatched != {}:
            print(unmatched)
        self.assertEqual(len(unmatched), 0)

        context = PlumberyContext(dictionary={'node.private': '12.34.56.78'})
        transformed = yaml.load(self.text.expand_string(input2, context))
        unmatched = {
            o: (expected2[o], transformed[o])
            for o in expected2.keys() if expected2[o] != transformed[o]
        }
        if unmatched != {}:
            print(unmatched)
        self.assertEqual(len(unmatched), 0)

    def test_input3(self):

        loaded = yaml.load(input3)
        context = PlumberyContext(dictionary={'node.public': '12.34.56.78'})
        transformed = yaml.load(self.text.expand_string(loaded, context))
        self.assertEqual(transformed, yaml.load(expected3))

    def test_input4(self):

        loaded = yaml.load(input4)
        context = PlumberyContext(dictionary={})
        transformed = yaml.load(self.text.expand_string(loaded, context))
        self.assertEqual(transformed, loaded)

    def test_input5(self):

        loaded = yaml.load(input5)
        context = PlumberyContext(dictionary={})
        transformed = yaml.load(self.text.expand_string(loaded, context))
        self.assertEqual(transformed, loaded)

    def test_input6(self):

        loaded = yaml.load(input6)
        context = PlumberyContext(dict6)
        transformed = self.text.expand_string(loaded, context)
        self.assertEqual(transformed.strip(), expected6.strip())

    def test_input7(self):

        loaded = yaml.load(input7)
        context = PlumberyContext(dict7)
        transformed = self.text.expand_string(loaded, context)
        self.assertEqual(transformed.strip(), expected7.strip())

    def test_input8(self):

        loaded = yaml.load(input8)
        context = PlumberyContext(dictionary={})
        expanded = self.text.expand_string(loaded, context)
        self.assertEqual(expanded.strip(), input8.strip())

    def test_input9(self):

        loaded = yaml.load(input9)
        context = PlumberyContext(context=PlumberyEngine())
        expanded = self.text.expand_string(loaded, context)
        self.assertEqual(('  - |' in expanded), False)

    def test_input10(self):

        loaded = yaml.load(input10)
        context = PlumberyContext(dictionary={})
        expanded = self.text.expand_string(loaded, context)
        self.assertEqual(expanded.strip(), input10.strip())

    def test_node1(self):

        template = "{{ mongo_mongos01.public }}"
        context = PlumberyNodeContext(node=FakeNode1())
        expected = '168.128.12.163'
        self.assertEqual(self.text.expand_string(template, context), expected)

        template = "{{mongo_mongos01.private }}"
        expected = '192.168.50.11'
        self.assertEqual(self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos01}}"
        expected = '192.168.50.11'
        self.assertEqual(self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos01.ipv6 }}"
        expected = '2a00:47c0:111:1136:47c9:5a6a:911d:6c7f'
        self.assertEqual(self.text.expand_string(template, context), expected)

    def test_node2(self):

        template = "{{ mongo_mongos02.public }}"
        context = PlumberyNodeContext(node=FakeNode1(),
                                      container=FakeContainer())
        expected = '168.128.12.164'
        self.assertEqual(self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos02.private }}"
        expected = '192.168.50.12'
        self.assertEqual(self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos02 }}"
        expected = '192.168.50.12'
        self.assertEqual(self.text.expand_string(template, context), expected)

        template = "{{ mongo_mongos02.ipv6 }}"
        expected = '2a00:47c0:111:1136:47c9:5a6a:911d:6c7f'
        self.assertEqual(self.text.expand_string(template, context), expected)