예제 #1
0
    def test_failed_pre_install_hooks_fail_chart_installation(
            self, configMock, helmClientMock, yamlLoadMock, sysMock, repoMock,
            hookCallMock, chartConfigMock):
        """Test that the chart isn't installed when the pre_install hooks return any non-zero responses. This also assures we don't raise python errors with hook errors."""
        c = configMock()
        c.continue_on_error = False
        c.helm_args = ['provided args']
        chartConfig = chartConfigMock()
        chartConfig.course_base_directory = '.'
        chartConfig.dryrun = False
        chartConfig.create_namespace = True
        chartConfig.cluster_namespaces = []

        h = helmClientMock(c.helm_args)
        h.client_version = '0.0.1'

        yamlLoadMock.load.return_value = {
            'charts': {
                'first-chart': {
                    'hooks': {
                        'pre_install': [
                            'run a failed command here',
                        ]
                    }
                }
            }
        }

        course = Course(None)
        results = course.plot(['first-chart'])

        self.assertEqual(
            len([result for result in results if result.failed]), 1,
            "We should have only one failed chart install due to hook failure."
        )
예제 #2
0
    def test_failed_pre_install_hooks_fail_chart_installation(self, configMock, helmClientMock, yamlLoadMock, sysMock, repoMock, chartCallMock):
        """Test that the chart isn't installed when the pre_install hooks return any non-zero responses. This also assures we don't raise python errors with hook errors."""
        c = configMock()
        c.helm_args = ['provided args']
        c.local_development = False

        h = helmClientMock()
        h.client_version = '0.0.1'

        yamlLoadMock.load.return_value = {
            'charts': {
                'first-chart': {
                    'hooks': {
                        'pre_install': [
                            'run a failed command here',
                        ]
                    }
                }
            }
        }

        chartCallMock.return_value = Response(exitcode=1, command_string='mocked', stderr=' ', stdout=' ')

        course = Course(None)
        course.plot(['first-chart'])

        self.assertEqual(chartCallMock.call_count, 1)
        self.assertEqual(len(course.failed_charts), 1, "We should have only one failed chart install due to hook failure.")
예제 #3
0
class TestCourse(TestBase):

    @mock.patch('reckoner.course.get_helm_client', autospec=True)
    def setUp(self, mock_helm_client_course_scope, autospec=True):
        mock_helm_client_course_instance = mock_helm_client_course_scope([])
        mock_helm_client_course_instance.version = '100.100.100'
        super(type(self), self).setUp()
        self.configure_subprocess_mock(test_repo_update_return_string, '', 0)
        with open(test_course) as f:
            self.c = Course(f)

        self.test_repository = Repository(test_repository_dict, None)

    def test_config_instance(self):
        self.assertIsInstance(self.c.config, Config)

    def test_course_values(self):
        self.assertIsInstance(self.c, Course)
        self.assertEqual([chart._release_name for chart in self.c.charts], test_release_names)
        self.assertNotEqual([chart.name for chart in self.c.charts], test_release_names,
                            msg="All the release names match the chart names, this may happen if you've edited the "
                                "test_course.yml and not provided an example with a different chart_name and chart.")
        self.assertEqual(self.c.repositories[0].name, test_repository_dict['name'])
        self.assertEqual(self.c.repositories[0].url, test_repository_dict['url'])
        self.assertEqual(list(self.c.minimum_versions.keys()), test_minimum_versions)
        self.assertIsInstance(self.c.repositories, list)

    def test_plot_course(self):
        self.configure_subprocess_mock('', '', 0)  # TODO: Lots of work do do here on installation of the list of charts
        self.c.plot(list(self.c._dict['charts']))
        self.assertEqual(self.c._charts_to_install, self.c.charts)
예제 #4
0
    def setUp(self):
        super(type(self), self).setUp()
        self.configure_subprocess_mock(test_repo_update_return_string, '', 0)
        with open(test_course) as f:
            self.c = Course(f)

        self.test_repository = Repository(test_repository_dict, None)
예제 #5
0
    def setUp(self, mock_helm_client_course_scope, autospec=True):
        mock_helm_client_course_instance = mock_helm_client_course_scope([])
        mock_helm_client_course_instance.version = '100.100.100'
        super(type(self), self).setUp()
        self.configure_subprocess_mock(test_repo_update_return_string, '', 0)
        with open(test_course) as f:
            self.c = Course(f)

        self.test_repository = Repository(test_repository_dict, None)
예제 #6
0
    def test_course_namespace_and_management_handling(self, mockHook, mockGetHelm, mockYAML):
        """Assure that course replaces strings with object settings for chart repository settings"""
        course = mockYAML.load.return_value = self.course_yaml
        course['namespace'] = "test-namespace"
        course['namespace_management'] = {
            "default": {
                "metadata": {
                    "annotations": {
                        "a-one": "a1",
                        "a-two": "a2"
                    },
                    "labels": {
                        "l-one": "l1",
                        "l-two": "l2",
                    }
                },
                "settings": {
                    "overwrite": True
                }
            }
        }

        # Mock out the repository helm client
        with mock.patch('reckoner.repository.HelmClient', mockGetHelm):
            # Run the course to convert the chart['first-chart']['repository'] reference
            c = Course(None)

        # Assert the chart namespace is string
        self.assertIsInstance(course['namespace'], str)

        # Assert that the dict for the namespace manager is the same after course loads
        self.assertDictEqual(
            c.namespace_management,
            {
                "metadata": {
                    "annotations": {
                        "a-one": "a1",
                        "a-two": "a2"
                    },
                    "labels": {
                        "l-one": "l1",
                        "l-two": "l2",
                    }
                },
                "settings": {
                    "overwrite": True
                }
            }
        )
        # expect the first chart install to bubble up an error
        chart = mock.MagicMock()
        c.install_charts([chart])
        chart.install.assert_called_with(
            context=c.context,
            default_namespace=c.namespace,
            default_namespace_management=c.namespace_management
        )
예제 #7
0
    def test_course_raises_errors_on_bad_client_response(self, mockHook, mockGetHelm, mockYAML, *args):
        """Make sure course wraps get_helm_client exceptions as ReckonerExceptions"""
        # Load the course "yaml"
        mockYAML.load.return_value = self.course_yaml

        # Check helm client exception checking command
        mockGetHelm.side_effect = HelmClientException('broken')
        with self.assertRaises(ReckonerException):
            Course(None)
        mockGetHelm.assert_called_once()
        mockGetHelm.reset_mock()

        mockGetHelm.side_effect = Exception("it's a mock: had an error starting helm client")
        with self.assertRaises(ReckonerException):
            Course(None)
예제 #8
0
    def test_secret_error_with_get_value(self, mockHook, mockGetHelm, mockYAML):

        course_with_secrets = self.course_yaml.copy()
        course_with_secrets['secrets'] = [
            {
                'name': 'TEST_SECRET',
                'backend': 'ShellExecutor',
                'script': 'false'
            }
        ]

        mockYAML.load.return_value = course_with_secrets
        with self.assertRaises(ReckonerCommandException):
            course = Course(None)
            course.merge_secrets_into_environment()
예제 #9
0
    def test_init_error_fails_min_version_reckoner(self, configMock,
                                                   helmClientMock,
                                                   yamlLoadMock, sysMock,
                                                   repoMock):
        """Tests that minimum version will throw an exit."""
        c = configMock()
        c.helm_args = ['provided args']

        yamlLoadMock.load.return_value = {
            'repositories': {
                'name': {},
            },
            'helm_args': None,
            'minimum_versions': {
                'reckoner': '1000.1000.1000',  # minimum version needed
                # find the version of reckoner at meta.py __version__
            }
        }

        sysMock.exit.return_value = None

        Course(None)

        sysMock.exit.assert_called_once
        return True
예제 #10
0
    def test_init_error_fails_min_version_helm(self, configMock,
                                               helmClientMock, yamlLoadMock,
                                               sysMock, repoMock):
        """Tests that minimum version will throw an exit."""
        c = configMock()
        c.helm_args = ['provided args']

        h = helmClientMock(c.helm_args)
        h.version = '0.0.1'

        yamlLoadMock.load.return_value = {
            'repositories': {
                'name': {},
            },
            'helm_args': None,
            'minimum_versions': {
                'helm': '1000.1000.1000',  # minimum version needed
            }
        }

        sysMock.exit.return_value = None

        Course(None)

        sysMock.exit.assert_called_once
        return True
예제 #11
0
    def test_chart_install_logic(self, mockHook, mockGetHelm, mockYAML):
        mockYAML.load.return_value = {
            'charts': {
                'first-chart': {},
                'second-chart': {}
            }
        }

        # expect the first chart install to bubble up an error
        chart = mock.MagicMock()
        chart.result = None
        chart.install.side_effect = Exception("Second command has an error")

        course = Course(None)
        self.assertEqual(len(course.install_charts([chart, chart])), 1)

        course.config.continue_on_error = True
        self.assertEqual(len(course.install_charts([chart, chart])), 2)
예제 #12
0
    def test_hooks_parsed(self, mockHook, mockGetHelm, mockYAML):
        mockYAML.load.return_value = self.course_yaml
        course = Course(None)

        self.assertIsInstance(course.hooks, (dict))
        self.assertIsInstance(course.pre_install_hook, (Hook))
        self.assertIsInstance(course.post_install_hook, (Hook))

        self.assertEqual(course.pre_install_hook.commands, ['command1', 'command2'])
        self.assertEqual(course.post_install_hook.commands, ['command3', 'command4'])
예제 #13
0
class TestCourse(TestBase):
    def setUp(self):
        super(type(self), self).setUp()
        self.configure_subprocess_mock(test_repo_update_return_string, '', 0)
        with open(test_course) as f:
            self.c = Course(f)

        self.test_repository = Repository(test_repository_dict)

    def test_config_instance(self):
        self.assertIsInstance(self.c.config, Config)

    def test_course_values(self):
        self.assertIsInstance(self.c, Course)
        self.assertEqual([chart._release_name for chart in self.c.charts],
                         test_release_names)
        self.assertNotEqual(
            [chart.name for chart in self.c.charts],
            test_release_names,
            msg=
            "All the release names match the chart names, this may happen if you've edited the "
            "test_course.yml and not provided an example with a different chart_name and chart."
        )
        self.assertEqual(self.c.repositories[0].name,
                         test_repository_dict['name'])
        self.assertEqual(self.c.repositories[0].url,
                         test_repository_dict['url'])
        self.assertEqual(self.c.minimum_versions.keys(), test_minimum_versions)
        self.assertIsInstance(self.c.repositories, list)

    def test_minimum_version(self):
        self.configure_subprocess_mock(test_helm_version_return_string, '', 0)
        self.c.minimum_versions['reckoner'] = test_reckoner_version
        self.assertRaises(MinimumVersionException,
                          self.c._compare_required_versions)

    def test_plot_course(self):
        self.configure_subprocess_mock(
            '', '', 0
        )  # TODO: Lots of work do do here on installation of the list of charts
        self.c.plot(list(self.c._dict['charts']))
        self.assertEqual(self.c._charts_to_install, self.c.charts)
예제 #14
0
    def test_course_namespace_and_without_namespace_management_handling(
            self, mockHook, mockGetHelm, mockYAML):
        """Assure that course replaces strings with object settings for chart repository settings"""
        course = mockYAML.load.return_value = self.course_yaml
        course['namespace'] = "test-namespace"

        # Mock out the repository helm client
        with mock.patch('reckoner.repository.HelmClient', mockGetHelm):
            # Run the course to convert the chart['first-chart']['repository'] reference
            c = Course(None)

        # Assert the chart namespace is string
        self.assertIsInstance(course['namespace'], str)

        # Assert that the dict for the namespace manager is the same after course loads
        # expect the first chart install to bubble up an error
        chart = mock.MagicMock()
        c.install_charts([chart])
        chart.install.assert_called_with(
            context=c.context,
            default_namespace=c.namespace,
            default_namespace_management=c.namespace_management)
예제 #15
0
    def test_course_git_repository_handling(self, mockHook, mockGetHelm,
                                            mockYAML):
        """Assure that course replaces strings with object settings for chart repository settings"""
        course = mockYAML.load.return_value = self.course_yaml
        # Add repositories configuration to the course
        course['repositories'] = {
            'some-git-repo': {
                'git': 'https://git.com/my-chart.git',
                'path': 'charts',
            },
            'stablez': {
                'url': 'https://fake.url.com',
            }
        }
        # Add first chart reference to the repositories settings
        course['charts']['first-chart']['repository'] = 'some-git-repo'
        # Add second chart referencing a missing chart (current behavior is to keep the string)
        course['charts']['second-chart'] = {
            'repository': 'missingfromrepos',
            'chart': 'my-chart',
        }
        # Add a third chart referring to a non-git repo
        course['charts']['third-chart'] = {
            'chart': 'my-chart',
            'repository': 'stablez',
        }

        self.assertIsInstance(course['charts']['first-chart']['repository'],
                              str)

        # Mock out the repository helm client
        with mock.patch('reckoner.repository.HelmClient', mockGetHelm):
            # Run the course to convert the chart['first-chart']['repository'] reference
            Course(None)

        # Assert the chart repo setting went from string to dict
        self.assertIsInstance(course['charts']['first-chart']['repository'],
                              dict)

        # Assert that the dict for the repositories settings is the same as the charts repository setting after course loads
        self.assertDictEqual(course['charts']['first-chart']['repository'],
                             course['repositories']['some-git-repo'])

        # Assert that second-chart is left alone since it is not in repositories
        self.assertEqual(course['charts']['second-chart']['repository'],
                         'missingfromrepos')

        # Assert that third-chart is reconciled to settings from repositories block
        self.assertDictEqual(course['charts']['third-chart']['repository'],
                             course['repositories']['stablez'])
예제 #16
0
    def test_secrets_parsed(self, mockHook, mockGetHelm, mockYAML):

        course_with_secrets = self.course_yaml.copy()
        # Doing this because the way secrets get injected into the environment
        # there was a naming collision every subsequent time this loaded
        course_with_secrets['secrets'] = [
            {
                'name': 'TEST_SECRET',
                'backend': 'ShellExecutor',
                'script': 'echo foo'
            }
        ]

        mockYAML.load.return_value = course_with_secrets
        course = Course(None)

        self.assertIsInstance(course.secrets, (list))
        self.assertIsInstance(course.secrets[0], (Secret))
예제 #17
0
 def test_plot(self, mockHook, mockGetHelm, mockYAML):
     mockYAML.load.return_value = self.course_yaml
     course = Course(None)
     assert course.plot(['first-chart'])
예제 #18
0
 def test_str_output(self, mockHook, mockGetHelm, mockYAML):
     mockYAML.load.return_value = self.course_yaml
     assert Course(None).__str__()