Esempio n. 1
0
def test_env_secret():
    app = {
        "id": "foobarify",
        "env": {
            "FOO": {
                "secret": "bar"
            }
        },
        "secrets": {
            "bar": {
                "source": "/deadbeef/baz"
            }
        },
    }

    settings = app_translator.Settings(
        app_translator.ContainerDefaults(image="lazybox", working_dir=None),
        app_secret_mapping=TrackingAppSecretMapping(app['id'], app['secrets']),
    )

    translated = app_translator.translate_app(app, settings)
    env = translated.deployment['spec']['template']['spec']['containers'][0]['env']

    assert env == [{
        'name': 'FOO',
        'valueFrom': {
            'secretKeyRef': {
                'name': 'marathonsecret-foobarify',
                'key': 'deadbeef.baz',
            }
        }
    }]
def new_settings(image: str = "busybox"):
    return app_translator.Settings(
        app_translator.ContainerDefaults(
            image=image,
            working_dir=".",
        ),
        app_secret_mapping=DummyAppSecretMapping(),
    )
Esempio n. 3
0
def test_fetch_fails_without_working_dir():
    settings = app_translator.Settings(
        app_translator.ContainerDefaults(
            image="busybox",
            working_dir=None,
        ),
        app_secret_mapping=DummyAppSecretMapping(),
    )

    fields = {"id": "app", "fetch": [{"uri": "http://foobar.baz/0xdeadbeef"}]}

    with pytest.raises(app_translator.AdditionalFlagNeeded,
                       match=r'.*?--container-working-dir.*?'):
        app_translator.translate_app(fields, settings)
Esempio n. 4
0
def test_generated_fetch_layout():
    """
    Tests generation of volume and init container for `fetch`.
    NOTE: This neither tests the generation of the fetch script that runs in
    the init container, nor ensures that this script itself actually works!
    """
    settings = app_translator.Settings(
        app_translator.ContainerDefaults(
            image="busybox",
            working_dir="/fetched_artifacts",
        ),
        app_secret_mapping=DummyAppSecretMapping(),
    )

    fields = {"id": "app", "fetch": [{"uri": "http://foobar.baz/0xdeadbeef"}]}

    translated = app_translator.translate_app(fields, settings)

    template_spec = translated.deployment['spec']['template']['spec']

    # The volume for fetching artifacts should be an empty dir.
    fetch_volume_name = template_spec['volumes'][0]['name']
    assert template_spec['volumes'] == [{
        'emptyDir': {},
        'name': fetch_volume_name
    }]

    # Ensure that the fetch volume will be mounted into the main container as a working dir.
    assert template_spec['containers'][0]['volumeMounts'] ==\
        [{'name': fetch_volume_name, 'mountPath': settings.container_defaults.working_dir}]

    # The fetcher itself should be implemented as a SINGLE init container.
    assert len(template_spec['initContainers']) == 1
    fetch_container = template_spec['initContainers'][0]

    assert fetch_container['volumeMounts'] == \
        [{'name': fetch_volume_name, 'mountPath': fetch_container['workingDir']}]

    # TODO (asekretenko): Write an integration test for the fetch command!
    assert isinstance(fetch_container['command'], list)
Esempio n. 5
0
import pytest

from dcos_migrate.plugins.marathon import app_translator

from .common import DummyAppSecretMapping

EMPTY_SETTINGS = app_translator.Settings(
    app_translator.ContainerDefaults(
        image="busybox",
        working_dir=None,
    ),
    app_secret_mapping=DummyAppSecretMapping(),
)


def test_command_health_check_with_all_fields_set():
    app = {
        "id":
        "/healthy",
        "healthChecks": [{
            "protocol": "COMMAND",
            "command": {
                "value": "exit 0"
            },
            "gracePeriodSeconds": 123,
            "intervalSeconds": 45,
            "timeoutSeconds": 99,
            "maxConsecutiveFailures": 333
        }],
    }
def test_host_path_volume_with_fetch():
    """
    Tests that emitting a volume for fetch artifacts does not interfere
    with a hostPath volume translation.
    """
    settings = app_translator.Settings(
        app_translator.ContainerDefaults(
            image=None,
            working_dir="/sandbox",
        ),
        app_secret_mapping=DummyAppSecretMapping(),
    )

    app = {
        "id": "app",
        "container": {
            "docker": {
                "image": "python"
            },
            "volumes": [
                {
                    "containerPath": "/ro",
                    "hostPath": "/volumes/ro",
                    "mode": "RO"
                },
            ],
        },
        "fetch": [{
            "uri": "http://foobar.baz/0xdeadbeef"
        }],
    }

    translated = app_translator.translate_app(app, settings)
    template_spec = translated.deployment['spec']['template']['spec']
    volumes = sorted(template_spec['volumes'], key=lambda v: v['name'])
    assert volumes == [
        {
            "name": "fetch-artifacts",
            'emptyDir': {}
        },
        {
            "name": "volume-0",
            'hostPath': {
                "path": "/volumes/ro"
            }
        },
    ]

    mounts = sorted(template_spec['containers'][0]['volumeMounts'],
                    key=lambda v: v['name'])
    assert mounts == [
        {
            "name": "fetch-artifacts",
            "mountPath": "/sandbox"
        },
        {
            "name": "volume-0",
            "mountPath": "/ro",
            "readOnly": True
        },
    ]
def test_host_path_volumes():
    settings = app_translator.Settings(
        app_translator.ContainerDefaults(
            image=None,
            working_dir=None,
        ),
        app_secret_mapping=DummyAppSecretMapping(),
    )

    app = {
        "id": "app",
        "container": {
            "docker": {
                "image": "python"
            },
            "volumes": [
                {
                    "containerPath": "/rw",
                    "hostPath": "/volumes/rw",
                    "mode": "RW"
                },
                {
                    "containerPath": "/ro",
                    "hostPath": "/volumes/ro",
                    "mode": "RO"
                },
                {
                    "containerPath": "/foo",
                    "hostPath": "relative_to_sandbox",
                    "mode": "RO"
                },
                {
                    "containerPath":
                    "foo",  # we cannot fully translate this persistent volume because there is no mapping into the container
                    "persistent": {
                        "size": 1024,
                        "type": "root"
                    },
                    "mode": "RO"
                },
            ],
        },
    }

    translated = app_translator.translate_app(app, settings)

    template_spec = translated.deployment['spec']['template']['spec']
    volumes = sorted(template_spec['volumes'], key=lambda v: v['name'])

    assert volumes == [{
        'name': 'volume-0',
        'hostPath': {
            'path': '/volumes/rw'
        }
    }, {
        'name': 'volume-1',
        'hostPath': {
            'path': '/volumes/ro'
        }
    }]

    mounts = sorted(template_spec['containers'][0]['volumeMounts'],
                    key=lambda v: v['name'])
    assert mounts == [
        {
            "name": "volume-0",
            "mountPath": "/rw",
            "readOnly": False
        },
        {
            "name": "volume-1",
            "mountPath": "/ro",
            "readOnly": True
        },
    ]

    # For now, we do not translate volumes with a "hostPath" relative to
    # Mesos sandbox (which typically are a part of a persistent volume setup).
    # Persistent volumes themselves aren't translated either.
    volume_warnings = [
        w for w in translated.warnings if "Cannot translate a volume" in w
    ]
    assert len(volume_warnings) == 2
    assert any("relative_to_sandbox" in w for w in volume_warnings)
    assert any("persistent" in w for w in volume_warnings)
def test_multiple_secret_volumes():
    """
    Tests a secret volume.
    One of the main things covered is non-interference between
    generating secret and host path volumes.
    """
    app = {
        "id": "foobarify",
        "container": {
            "docker": {
                "image": "python"
            },
            "volumes": [
                {
                    "containerPath": "/etc/foo",
                    "secret": "foo-secret"
                },
                {
                    "containerPath": "/run/bar",
                    "secret": "bar-secret"
                },
                {
                    "containerPath": "/var/baz",
                    "secret": "baz-secret"
                },
            ],
        },
        "secrets": {
            "foo-secret": {
                "source": "foo"
            },
            "bar-secret": {
                "source": "bar"
            },
            "baz-secret": {
                "source": "baz"
            },
        },
    }

    settings = app_translator.Settings(
        app_translator.ContainerDefaults(image=None, working_dir=None),
        app_secret_mapping=TrackingAppSecretMapping(app['id'], app['secrets']),
    )

    translated = app_translator.translate_app(app, settings)

    template_spec = translated.deployment['spec']['template']['spec']

    volumes = sorted(template_spec['volumes'], key=lambda v: v['name'])
    assert volumes == [{
        "name": "secrets-marathonsecret-foobarify",
        "secret": {
            "secretName":
            "marathonsecret-foobarify",
            "items": [
                {
                    "key": "foo",
                    "path": "foo",
                    "mode": 0o777
                },
                {
                    "key": "bar",
                    "path": "bar",
                    "mode": 0o777
                },
                {
                    "key": "baz",
                    "path": "baz",
                    "mode": 0o777
                },
            ],
        }
    }]

    name = volumes[0]['name']

    mounts = sorted(template_spec['containers'][0]['volumeMounts'],
                    key=lambda v: v['name'])
    assert mounts == [
        {
            "name": name,
            "mountPath": "/etc/foo",
            "subPath": "foo",
            "readOnly": True
        },
        {
            "name": name,
            "mountPath": "/run/bar",
            "subPath": "bar",
            "readOnly": True
        },
        {
            "name": name,
            "mountPath": "/var/baz",
            "subPath": "baz",
            "readOnly": True
        },
    ]