def test_get_container_name(patch, story, line, reusable, name):
    patch.object(Containers, 'is_service_reusable', return_value=reusable)
    story.app.app_id = 'my_app'
    story.app.version = 'v2'
    ret = Containers.get_container_name(story.app, story.name, line, name)
    if reusable:
        assert ret == f'alpine-{Containers.hash_service_name(story.app, name)}'
    else:
        h = Containers.hash_service_name_and_story_line(
            story.app, story.name, line, name)
        assert ret == f'alpine-{h}'
Exemple #2
0
def test_containers_format_command(story):
    """
    Ensures a simple resolve can be performed
    """
    story_text = 'alpine echo msg:"foo"\n'
    story.context = {}
    story.app.services = {
        'alpine': {
            ServiceConstants.config: {
                'actions': {
                    'echo': {
                        'arguments': {
                            'msg': {
                                'type': 'string'
                            }
                        }
                    }
                }
            }
        }
    }

    story.tree = storyscript.Api.loads(story_text).result()['tree']
    assert Containers.format_command(story, story.line('1'), 'alpine',
                                     'echo') == ['echo', '{"msg":"foo"}']
Exemple #3
0
def test_containers_format_command(story):
    """
    Ensures a simple resolve can be performed
    """
    story_text = 'yaml parse data:"foo"\n'
    story.context = {}
    story.app.services = {
        'yaml': {
            ServiceConstants.config: {
                'actions': {
                    'parse': {
                        'arguments': {
                            'data': {
                                'type': 'string'
                            }
                        }
                    }
                }
            }
        }
    }

    story.tree = storyscript.Api.loads(story_text).result().output()['tree']
    assert Containers.format_command(story, story.line('1'), 'yaml',
                                     'parse') == ['parse', '{"data":"foo"}']
def test_service_name(patch, story):
    story.app.version = 'v2'
    patch.object(hashlib, 'sha1')
    ret = Containers.hash_service_name(story.app, 'alpine')

    hashlib.sha1.assert_called_with(f'alpine-v2'.encode('utf-8'))
    assert ret == hashlib.sha1().hexdigest()
def test_format_command_no_format(logger, app, echo_service, echo_line):
    story = Stories.story(app, logger, 'echo.story')
    app.services = echo_service

    config = app.services['alpine'][ServiceConstants.config]
    config['actions']['echo']['format'] = None

    cmd = Containers.format_command(story, echo_line, 'alpine', 'echo')
    assert ['echo', '{"msg":"foo"}'] == cmd
def test_format_command_no_args(logger, app, echo_service, echo_line):
    story = Stories.story(app, logger, 'echo.story')
    app.services = echo_service

    echo_service['alpine'][
        ServiceConstants.config]['actions']['echo']['arguments'] = None

    cmd = Containers.format_command(story, echo_line, 'alpine', 'echo')
    assert ['echo'] == cmd
def test_service_name_and_story_line(patch, story):
    patch.object(hashlib, 'sha1')
    story.name = 'story_name'
    story.app.version = 'v29'
    ret = Containers.hash_service_name_and_story_line(story.app, story.name,
                                                      {'ln': '1'}, 'alpine')

    hashlib.sha1.assert_called_with(
        f'alpine-v29-{story.name}-1'.encode('utf-8'))
    assert ret == hashlib.sha1().hexdigest()
def test_format_command_with_format(patch, logger, app, echo_service,
                                    echo_line):
    story = Stories.story(app, logger, 'echo.story')
    patch.object(story, 'argument_by_name', return_value='asyncy')
    app.services = echo_service

    config = app.services['alpine'][ServiceConstants.config]
    config['actions']['echo']['format'] = 'echo {msg}'

    cmd = Containers.format_command(story, echo_line, 'alpine', 'echo')
    assert ['echo', 'asyncy'] == cmd
def test_get_containerconfig_name(app):
    app.version = 'v1'
    config = ContainerConfig(
        name='name_with_special_!!!_characters',
        data={'auths': {
            'registry_url': {
                'auth': 'base64_string'
            }
        }})
    r = Containers.get_containerconfig_name(app, config.name)
    assert r == 'namewithspecialchara-95b9733c79792f385564973c20be433f6f6832e9'
def test_is_service_reusable(story):
    story.app.services = {
        'alpine': {
            'configuration': {
                'actions': {
                    'echo': {
                        'run': 'foo'
                    }
                }
            }
        }
    }

    line = {LineConstants.service: 'alpine', LineConstants.command: 'echo'}

    assert Containers.is_service_reusable(story.app, line) is False
    story.app.services['alpine']['configuration']['actions']['echo'][
        'run'] = None

    assert Containers.is_service_reusable(story.app, line) is True
def test_hash_volume_name(patch, story, line, reusable):
    line['ln'] = '1'
    patch.object(Containers, 'is_service_reusable', return_value=reusable)
    name = 'my_volume'
    service = 'foo'
    key = name + '-' + service
    if not reusable:
        key = f'{key}-{line["ln"]}'

    expected = f'myvolume-' + hashlib.sha1(key.encode('utf-8')).hexdigest()
    assert Containers.hash_volume_name(story.app, line, service, name) == \
        expected
Exemple #12
0
def test_containers_format_command_no_arguments(story):
    story_text = 'uuid generate\n'
    story.context = {}
    story.app.services = {
        'uuid': {
            ServiceConstants.config: {
                'actions': {
                    'generate': {}
                }
            }
        }
    }
    story.tree = storyscript.Api.loads(story_text).result().output()['tree']
    assert Containers.format_command(story, story.line('1'), 'uuid',
                                     'generate') == ['generate']
Exemple #13
0
def test_containers_format_command_no_arguments(story):
    story_text = 'alpine echo\n'
    story.context = {}
    story.app.services = {
        'alpine': {
            ServiceConstants.config: {
                'actions': {
                    'echo': {}
                }
            }
        }
    }
    story.tree = storyscript.Api.loads(story_text).result()['tree']
    assert Containers.format_command(story, story.line('1'), 'alpine',
                                     'echo') == ['echo']
async def test_expose_service(app, patch, async_mock):
    container_name = 'container_name'
    patch.object(Containers, 'get_container_name', return_value=container_name)

    patch.object(Containers, 'create_and_start', new=async_mock())
    patch.object(Kubernetes, 'create_ingress', new=async_mock())

    e = Forward(service='service',
                service_forward_name='expose_name',
                http_path='expose_path')

    ingress_name = Containers.hash_ingress_name(e)
    hostname = f'{app.app_dns}--{Containers.get_simple_name(e.service)}'

    await Containers.expose_service(app, e)

    Containers.create_and_start.mock.assert_called_with(
        app, None, e.service, container_name)

    Kubernetes.create_ingress.mock.assert_called_with(ingress_name,
                                                      app,
                                                      e,
                                                      container_name,
                                                      hostname=hostname)
def test_get_registry_url_official(image):
    ret = Containers.get_registry_url(image)
    assert ret == 'https://index.docker.io/v1/'
def test_get_registry_url_custom():
    image = 'cloud.canister.io:5000/repository/image'
    ret = Containers.get_registry_url(image)
    assert ret == 'cloud.canister.io:5000'
def test_format_command(logger, app, echo_service, echo_line):
    story = Stories.story(app, logger, 'echo.story')
    app.services = echo_service

    cmd = Containers.format_command(story, echo_line, 'alpine', 'echo')
    assert ['echo', '{"msg":"foo"}'] == cmd
def test_hash_ingress_name():
    e = Forward(service='service',
                service_forward_name='expose_name',
                http_path='expose_path')
    ret = Containers.hash_ingress_name(e)
    assert ret == 'exposename-0cf994f170f9d213bb814f74baca87ea149f7536'
def test_format_command_no_spec(logger, app, echo_line):
    story = Stories.story(app, logger, 'echo.story')
    app.services = {}
    with pytest.raises(ContainerSpecNotRegisteredError):
        Containers.format_command(story, echo_line, 'alpine', 'echo')
async def test_start(patch, story, async_mock, missing_required_var,
                     run_command, with_volumes):
    line = {
        LineConstants.service: 'alpine',
        LineConstants.command: 'echo',
        'ln': '1'
    }

    patch.object(Kubernetes, 'create_pod', new=async_mock())

    story.app.services = {
        'alpine': {
            ServiceConstants.config: {
                'uuid': '0c6299fe-7d38-4fde-a1cf-7b6ce610cb2d',
                'actions': {
                    'echo': {}
                },
                'volumes': {
                    'db': {
                        'persist': True,
                        'target': '/db'
                    },
                    'tmp': {
                        'persist': False,
                        'target': '/tmp'
                    }
                },
                'environment': {
                    'param_1': {
                        'required': True
                    },
                    'alpine_only': {}
                }
            }
        }
    }

    if not with_volumes:
        del story.app.services['alpine'][ServiceConstants.config]['volumes']

    if run_command is not None:
        story.app.services['alpine'][
            ServiceConstants.config]['actions']['echo'] = {
                'run': {
                    'command': run_command
                }
            }

    story.app.environment = {
        'alpine': {
            'alpine_only': True,
            'param_1': 'hello_world'
        },
        'global': 'yes'
    }

    if missing_required_var:
        story.app.environment['alpine']['param_1'] = None

    patch.object(Containers,
                 'get_container_name',
                 return_value='asyncy-alpine')

    patch.object(Database,
                 'get_container_configs',
                 new=async_mock(return_value=[]))

    expected_volumes = []
    if with_volumes:
        hash_db = Containers.hash_volume_name(story.app, line, 'alpine', 'db')
        hash_tmp = Containers.hash_volume_name(story.app, line, 'alpine',
                                               'tmp')
        expected_volumes = [
            Volume(persist=True, name=hash_db, mount_path='/db'),
            Volume(persist=False, name=hash_tmp, mount_path='/tmp'),
        ]

    if missing_required_var:
        with pytest.raises(EnvironmentVariableNotFound):
            await Containers.start(story, line)
        return
    else:
        await Containers.start(story, line)

    Kubernetes.create_pod.mock.assert_called_with(
        app=story.app,
        service_name='alpine',
        service_uuid='0c6299fe-7d38-4fde-a1cf-7b6ce610cb2d',
        image='alpine',
        container_name='asyncy-alpine',
        start_command=run_command or ['tail', '-f', '/dev/null'],
        shutdown_command=None,
        env={
            'alpine_only': True,
            'param_1': 'hello_world'
        },
        volumes=expected_volumes,
        container_configs=[])