Ejemplo n.º 1
0
def test_sat_matcher_with_labels():

    expected_results = [[
        DeploymentEntity(name='test-deployment-1', memory=1024, cpu=2)
    ], [
        DeploymentEntity(name='test-deployment-2', memory=512, cpu=1),
    ],
                        [
                            DeploymentEntity(name='test-deployment-3',
                                             memory=256,
                                             cpu=0.5,
                                             labels={'node': '3'})
                        ]]

    deployments = list()
    for node in expected_results:
        for deployment in node:
            deployments.append(deployment)

    matcher = Greedy(deployments, [
        ResourceEntity(name='test-node-1', memory=1024, cpu=8),
        ResourceEntity(name='test-node-2', memory=1024, cpu=3),
        ResourceEntity(
            name='test-node-3', memory=1024, cpu=1, labels={'node': '3'}),
    ])
    matcher.match()
    resources_matched = matcher.get_resources()

    for i, res in enumerate(resources_matched):
        for exp_deploy in expected_results[i]:
            assert exp_deploy in res.get_deployments()
Ejemplo n.º 2
0
def test_upper_bound_cpu_detection():
    matcher = Solver(
        [DeploymentEntity(name='test-deployment', memory=1024, cpu=2)],
        [ResourceEntity(name='test-node', memory=512, cpu=1)])

    with pytest.raises(SolverError) as e:
        matcher.match()
    assert e.type == SolverError
Ejemplo n.º 3
0
    def _add_hostname_label(hostname, deployment: DeploymentEntity):
        """Adds Kubernetes hostname label to deployments

        :param hostname: node hostname, content of added label
        :type hostname: str
        :param deployment: deployment objects to add hostname label to
        :type deployment: :class:`continuum_deployer.resources.deployment.DeploymentEntity`
        :return: deployment object with added labels
        :rtype: :class:`continuum_deployer.resources.deployment.DeploymentEntity`
        """

        KUBE_HOSTNAME_LABEL_KEY = 'kubernetes.io/hostname'
        result = deployment.yaml
        result.get('spec').get('template').get('spec')['nodeSelector'] = {
            KUBE_HOSTNAME_LABEL_KEY: hostname
        }
        deployment.yaml = result
        return deployment
Ejemplo n.º 4
0
    def parse(self, dsl_input):
        """Does the actual parsing of the provided DSL input

        :param dsl_input: already parsed plain DSL input
        :type dsl_input: str
        """

        # see default loader deprecation
        # https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation
        docs = yaml.load_all(dsl_input, Loader=yaml.SafeLoader)

        spinner = Spinner('Parsing DSL ')

        for doc in docs:

            spinner.next()

            if doc is None:
                continue
            if doc['kind'] in self.K8S_OBJECTS:

                deployment = DeploymentEntity()
                # save YAML doc representation
                deployment.yaml = doc
                _name = doc.get('metadata', None).get('name', None)
                if _name != None:
                    deployment.name = _name
                else:
                    # https://kubernetes.io/docs/concepts/overview/working-with-objects/names/
                    click.echo(click.style(
                        '[Error] No name provided in object metadata',
                        fg='red'),
                               err=True)
                    exit(1)

                _labels = doc['spec']['template']['spec'].get(
                    'nodeSelector', None)
                if _labels is not None:
                    deployment.labels = _labels

                for container in doc['spec']['template']['spec']['containers']:
                    if 'resources' in container:
                        if container['resources'] is not None:
                            _request = container.get('resources', None).get(
                                'requests', None)
                            if _request != None:
                                deployment.memory = Helm.parse_k8s_memory_value(
                                    _request.get('memory', 0))
                                deployment.cpu = Helm.parse_k8s_cpu_value(
                                    _request.get('cpu', 0))
                            else:
                                click.echo(
                                    click.style((
                                        '\n[Warning] No resource request provided for module {}. This can result '
                                        'in suboptimal deployment placement.'
                                    ).format(_name),
                                                fg='yellow'))

                            _limits = container.get('resources',
                                                    None).get('limits', None)
                            if _limits != None and _limits != {}:
                                deployment.memory_limit = Helm.parse_k8s_memory_value(
                                    _limits.get('memory', 0))
                                deployment.cpu_limit = Helm.parse_k8s_cpu_value(
                                    _limits.get('cpu', 0))
                            else:
                                # as this is not an hard error just pass
                                pass
                    else:
                        click.echo(
                            click.style((
                                '\n[Warning] No resource request provided for module {}. This can result '
                                'in suboptimal deployment placement.'
                            ).format(_name),
                                        fg='yellow'))

                # check if we have a scalable controller
                if doc['kind'] in Helm.K8S_SCALE_CONTROLLER:
                    _number_replicas = doc['spec'].get('replicas', 1)

                    # check if we need to scale higher than 1
                    # case 'is None': empty replicas field in yaml
                    if _number_replicas == 1 or _number_replicas is None:
                        self.app_modules.append(deployment)
                    else:
                        _deployment_name = deployment.name
                        for i in range(_number_replicas):
                            # extent deployment name with replica number
                            deployment.name = '{}-{}'.format(
                                _deployment_name, i)
                            # we need deepcopy to create new objects here in order to call append multiple times
                            self.app_modules.append(copy.deepcopy(deployment))
                else:
                    self.app_modules.append(deployment)