예제 #1
0
    def test_poll_deployment_timeout(self):
        core_v1_mock = MagicMock()
        ext_v1_mock = MagicMock()

        pod_mock = MagicMock()

        status_mock = MagicMock()
        status_mock.restart_count = 0
        condition_mock = MagicMock()
        condition_mock.type = 'Ready'
        condition_mock.status = 'True'

        pod_mock.status.conditions = [
            condition_mock,
        ]
        states_mock = MagicMock()
        states_mock.state.waiting = None

        pod_mock.status.container_statuses = [
            states_mock,
        ]

        with patch('apsconnectcli.cluster.sleep'), \
            patch('apsconnectcli.cluster.sys'), \
            patch('apsconnectcli.cluster.datetime') as datetime_mock, \
                patch('apsconnectcli.cluster.timedelta') as timedelta_mock:
            datetime_mock.now.side_effect = [0, 100]
            timedelta_mock.return_value = 0
            ext_v1_mock.read_namespaced_deployment.return_value.status.available_replicas = False
            core_v1_mock.list_namespaced_pod.return_value.items = [pod_mock]
            result = poll_deployment(core_v1_mock, ext_v1_mock, 'namespace',
                                     'name')

        self.assertFalse(result.available)
        self.assertTrue('Timed out' in result.message)
예제 #2
0
    def test_poll_deployment_waiting_unexpected(self):
        core_v1_mock = MagicMock()
        ext_v1_mock = MagicMock()

        pod_mock = MagicMock()

        status_mock = MagicMock()
        status_mock.restart_count = 0
        condition_mock = MagicMock()
        condition_mock.type = 'Ready'
        condition_mock.status = 'True'

        pod_mock.status.conditions = [
            condition_mock,
        ]
        states_mock = MagicMock()
        states_mock.state.waiting.reason = 'SomeWeirdError'
        states_mock.state.waiting.message = 'SomeErrorMessage'

        pod_mock.status.container_statuses = [
            states_mock,
        ]

        with patch('apsconnectcli.cluster.get_log') as log_mock:
            log_mock.return_value = 'LOG'
            ext_v1_mock.read_namespaced_deployment.return_value.status.available_replicas = False
            core_v1_mock.list_namespaced_pod.return_value.items = [pod_mock]
            result = poll_deployment(core_v1_mock, ext_v1_mock, 'namespace',
                                     'name')

        self.assertFalse(result.available)
        self.assertTrue('Unexpected error' in result.message)
        self.assertTrue('SomeWeirdError' in result.message)
        self.assertTrue('SomeErrorMessage' in result.message)
예제 #3
0
    def test_poll_deployment_too_many_restarts(self):
        core_v1_mock = MagicMock()
        ext_v1_mock = MagicMock()

        pod_mock = MagicMock()
        status_mock = MagicMock()
        status_mock.restart_count = 10
        condition_mock = MagicMock()
        condition_mock.type = 'Ready'
        condition_mock.status = 'False'
        condition_mock.reason = 'ContainersNotReady'

        pod_mock.status.conditions = [
            condition_mock,
        ]
        pod_mock.status.container_statuses = [
            status_mock,
        ]

        with patch('apsconnectcli.cluster.get_log') as log_mock:
            log_mock.return_value = 'LOG'
            ext_v1_mock.read_namespaced_deployment.return_value.status.available_replicas = False
            core_v1_mock.list_namespaced_pod.return_value.items = [pod_mock]
            result = poll_deployment(core_v1_mock, ext_v1_mock, 'namespace',
                                     'name')

        self.assertFalse(result.available)
        self.assertTrue('Readiness check failed' in result.message)
        self.assertTrue('LOG' in result.message)
예제 #4
0
    def test_poll_deployment_ok(self):
        core_v1_mock = MagicMock()
        ext_v1_mock = MagicMock()

        result = poll_deployment(core_v1_mock, ext_v1_mock, 'namespace',
                                 'name')

        self.assertTrue(result.available)
        self.assertEqual(result.message,
                         'Deployment has just become available')
예제 #5
0
    def test_poll_deployment_no_containers(self):
        core_v1_mock = MagicMock()
        ext_v1_mock = MagicMock()

        with patch(
                'apsconnectcli.cluster.check_containers_exist') as exist_mock:
            exist_mock.return_value = False
            ext_v1_mock.read_namespaced_deployment.return_value.status.available_replicas = False
            result = poll_deployment(core_v1_mock, ext_v1_mock, 'namespace',
                                     'name')

        self.assertFalse(result.available)
        self.assertTrue('No containers available' in result.message)
예제 #6
0
def _create_deployment(name,
                       image,
                       api,
                       image_pull_secret=None,
                       healthcheck_path='/',
                       replicas=2,
                       namespace='default',
                       force=False,
                       core_api=None):
    template = {
        'apiVersion': 'extensions/v1beta1',
        'kind': 'Deployment',
        'metadata': {
            'name': name,
        },
        'spec': {
            'replicas': replicas,
            'template': {
                'metadata': {
                    'labels': {
                        'name': name,
                    },
                },
                'spec': {
                    'containers': [
                        {
                            'name':
                            name,
                            'image':
                            image,
                            'env': [
                                {
                                    'name': 'CONFIG_FILE',
                                    'value': '/config/config.yml',
                                },
                            ],
                            'livenessProbe': {
                                'httpGet': {
                                    'path': healthcheck_path,
                                    'port': 80,
                                },
                            },
                            'readinessProbe': {
                                'httpGet': {
                                    'path': healthcheck_path,
                                    'port': 80,
                                },
                            },
                            'ports': [
                                {
                                    'containerPort': 80,
                                    'name': 'http-server',
                                },
                            ],
                            'resources': {
                                'requests': {
                                    'cpu': '100m',
                                    'memory': '128Mi',
                                },
                                # TODO need more limits by default?
                                'limits': {
                                    'cpu': '200m',
                                    'memory': '256Mi',
                                },
                            },
                            'volumeMounts': [
                                {
                                    'mountPath': '/config',
                                    'name': 'config-volume',
                                },
                            ],
                        },
                    ],
                    'volumes': [
                        {
                            'name': 'config-volume',
                            'secret': {
                                'secretName': name,
                            },
                        },
                    ],
                },
            },
        },
    }

    if image_pull_secret:
        image_pull_secret_tag = [{'name': image_pull_secret}]
        template['spec']['template']['spec'][
            'imagePullSecrets'] = image_pull_secret_tag

    if force:
        _delete_deployment(name,
                           api=api,
                           namespace=namespace,
                           core_api=core_api)

    api.create_namespaced_deployment(namespace=namespace, body=template)

    # Check deployment availability
    sys.stdout.write("Waiting for deployment to become ready...")
    sys.stdout.flush()
    poll_result = poll_deployment(core_v1=core_api,
                                  ext_v1=api,
                                  namespace=namespace,
                                  name=name)
    print()
    if not poll_result.available:
        print(poll_result.message)
        sys.exit(1)