Beispiel #1
0
def _check_docker_supports_mounts() -> CheckLevels:
    """
    Check to is to avoid:

    docker.errors.InvalidVersion: mounts param is not supported in API versions
    < 1.30
    """
    client = docker_client()
    mount = docker.types.Mount(source=None, target='/etc')
    # Any image will do, we use this for another test so using it here saves
    # pulling another image.
    tiny_image = 'luca3m/sleep'

    try:
        container = client.containers.run(
            image=tiny_image,
            mounts=[mount],
            detach=True,
        )
    except docker.errors.InvalidVersion as exc:
        if 'mounts param is not supported' in str(exc):
            message = (
                'The Docker API version must be >= 1.30. '
                'This is because this tool uses the ``mounts`` parameter.')
            error(message=message)
            return CheckLevels.ERROR
        raise

    container.stop()
    container.remove(v=True)

    return CheckLevels.NONE
Beispiel #2
0
def check_vagrant_plugin_versions() -> CheckLevels:
    """
    Error if `vagrant-vbguest` is not of at least version 0.17.2.
    """
    # We import Vagrant here instead of at the top of the file because, if
    # the Vagrant executable is not found, a warning is logged.
    #
    # We want to avoid that warning for users of other backends who do not
    # have the Vagrant executable.
    import vagrant

    client = vagrant.Vagrant()
    plugin_list = client.plugin_list()
    name = 'vagrant-vbguest'
    (plugin, ) = set(plugin for plugin in plugin_list if plugin.name == name)
    version_info = VersionInfo.parse(plugin.version)
    minimum_version = VersionInfo(0, 17, 2)
    # We require a minimum version to work around
    # https://github.com/dotless-de/vagrant-vbguest/issues/320.
    plugin_recent = version_info >= minimum_version
    if plugin_recent:
        return CheckLevels.NONE

    message = ('The "vagrant-vbguest" plugin version is {plugin_version}. '
               'The minimum supported version is 0.17.2. '
               'Run "vagrant plugin update".').format(
                   plugin_version=plugin.version)
    error(message=message)
    return CheckLevels.ERROR
Beispiel #3
0
def _check_systemd() -> CheckLevels:
    """
    Check that the host supports systemd.

    See https://jira.mesosphere.com/browse/DCOS_OSS-4475 for removing the need
    for this.
    """
    client = docker_client()
    tiny_image = 'luca3m/sleep'
    cgroup_mount = docker.types.Mount(
        source='/sys/fs/cgroup/systemd',
        target='/sys/fs/cgroup/systemd',
        read_only=True,
        type='bind',
    )
    try:
        client.containers.run(
            image=tiny_image,
            mounts=[cgroup_mount],
            detach=True,
        )
    except docker.errors.APIError as exc:
        expected = (
            'bind mount source path does not exist: /sys/fs/cgroup/systemd"')
        if expected in str(exc):
            message = 'systemd is required.'
            error(message=message)
            return CheckLevels.ERROR
        raise
    return CheckLevels.NONE
Beispiel #4
0
def _check_storage_driver() -> CheckLevels:
    """
    Warn if the Docker storage driver is not a recommended driver.
    """
    client = docker_client()
    host_driver = client.info()['Driver']
    storage_driver_url = (
        'https://docs.docker.com/storage/storagedriver/select-storage-driver/')
    # Any image will do, we use this for another test so using it here saves
    # pulling another image.
    tiny_image = 'luca3m/sleep'
    container = client.containers.run(
        image=tiny_image,
        tty=True,
        detach=True,
        privileged=True,
        volumes={'/proc': {
            'bind': '/host/proc',
            'mode': 'rw',
        }},
    )

    cmd = ['cat', '/host/proc/filesystems']
    _, output = container.exec_run(cmd=cmd)
    container.stop()
    container.remove(v=True)
    aufs_supported = bool(b'aufs' in output.split())
    supported_host_driver = bool(host_driver in DOCKER_STORAGE_DRIVERS)
    can_work = bool(aufs_supported or supported_host_driver)

    if not can_work:
        message = (
            "The host's Docker storage driver is \"{host_driver}\". "
            'aufs is not available. '
            'Change your storage driver to one of: {supported_drivers}. '
            'Alternatively try using the `--docker-storage-driver` option '
            'with `overlay` or `overlay2`. '
            'See {help_url}.').format(
                host_driver=host_driver,
                supported_drivers=', '.join(
                    sorted(DOCKER_STORAGE_DRIVERS.keys())),
                help_url=storage_driver_url,
            )
        error(message=message)
        return CheckLevels.ERROR

    if not supported_host_driver:
        message = ("The host's Docker storage driver is \"{host_driver}\". "
                   'We recommend that you use one of: {supported_drivers}. '
                   'See {help_url}.').format(
                       host_driver=host_driver,
                       supported_drivers=', '.join(
                           sorted(DOCKER_STORAGE_DRIVERS.keys())),
                       help_url=storage_driver_url,
                   )
        warn(message=message)
        return CheckLevels.WARNING

    return CheckLevels.NONE
Beispiel #5
0
def check_vagrant() -> CheckLevels:
    """
    Error if `vagrant` is not available on the path.
    """
    if shutil.which('vagrant') is None:
        error(message='`vagrant` must be available on the PATH.')
        return CheckLevels.ERROR
    return CheckLevels.NONE
Beispiel #6
0
def check_virtualbox() -> CheckLevels:
    """
    Error if VirtualBox is not installed.
    """
    if shutil.which('VBoxManage') is None:
        message = ('"VBoxManage" is not available on the PATH. '
                   'To resolve this, install VirtualBox from '
                   'https://www.virtualbox.org/wiki/Downloads.')
        error(message=message)
        return CheckLevels.ERROR
    return CheckLevels.NONE
Beispiel #7
0
def _check_mount_var() -> CheckLevels:
    """
    Check that `/var/folders` can be mounted.
    """
    source = Path('/var').resolve()
    client = docker_client()
    tiny_image = 'luca3m/sleep'
    var_mount = docker.types.Mount(
        source=str(source),
        target='/var',
        read_only=True,
        type='bind',
    )
    try:
        container = client.containers.run(
            image=tiny_image,
            mounts=[var_mount],
            detach=True,
        )
    except docker.errors.APIError as exc:
        expected = 'bind mount source path does not exist: {source}'.format(
            source=source, )
        expected_docker_machine = (
            'bind source path does not exist: {source}').format(source=source)
        if expected in str(exc) or expected_docker_machine in str(exc):
            message = ('There was an error mounting "{source}" '
                       'from the host into a Docker container. '
                       'This is required for multiple operations.').format(
                           source=source)

            operating_system_info = client.info()['OperatingSystem']
            boot2docker = bool('Boot2Docker' in operating_system_info)
            if boot2docker:
                message += (
                    '\n'
                    'It appears that you are using Boot2Docker or '
                    'docker-machine and this might be the cause of the '
                    'problem. '
                    'These are known to be incompatible with DC/OS E2E and '
                    'minidcos.')
            if sys.platform == 'darwin':
                message += (
                    '\n'
                    'Consider upgrading to Docker for Mac. '
                    'See https://docs.docker.com/docker-for-mac/install/.')
            error(message=message)
            return CheckLevels.ERROR
        raise

    container.stop()
    container.remove(v=True)

    return CheckLevels.NONE
Beispiel #8
0
def _check_selinux() -> CheckLevels:
    """
    Error if SELinux is enabled.
    This can cause problems such as mount problems for the installer.
    """
    if shutil.which('getenforce') is None:
        return CheckLevels.NONE

    result = subprocess.check_output(args=['getenforce'])
    if result == b'Enforcing':
        message = ('SELinux is in "Enforcing" mode. '
                   'SELinux must be in "Permissive" or "Disabled" mode.')
        error(message=message)
        return CheckLevels.ERROR

    return CheckLevels.NONE
Beispiel #9
0
def check_vagrant_plugins() -> CheckLevels:
    """
    Error if `vagrant-vbguest` is not installed.
    """
    # We import Vagrant here instead of at the top of the file because, if
    # the Vagrant executable is not found, a warning is logged.
    #
    # We want to avoid that warning for users of other backends who do not
    # have the Vagrant executable.
    import vagrant

    client = vagrant.Vagrant()
    if 'vagrant-vbguest' in set(plugin.name
                                for plugin in client.plugin_list()):
        return CheckLevels.NONE

    error(message='The `vagrant-vbguest` plugin must be installed.')
    return CheckLevels.ERROR
Beispiel #10
0
def _check_can_build() -> CheckLevels:
    """
    Check that the default cluster images can be built.
    """
    cluster_backend = Docker(docker_version=DockerVersion.v1_13_1)
    try:
        with Cluster(cluster_backend=cluster_backend):
            pass
    except docker.errors.BuildError as exc:
        message = ('There was an error building a Docker image. '
                   'The Docker logs follow.\n'
                   '\n')
        for item in exc.build_log:
            if 'stream' in item:
                message += '\t' + item['stream']
        error(message=message)
        return CheckLevels.ERROR

    return CheckLevels.NONE
Beispiel #11
0
def _check_systemd() -> CheckLevels:
    """
    Check that the host supports systemd.

    See https://jira.mesosphere.com/browse/DCOS_OSS-4475 for removing the need
    for this.
    """
    client = docker_client()
    tiny_image = 'luca3m/sleep'
    cgroup_mount = docker.types.Mount(
        source='/sys/fs/cgroup/systemd',
        target='/sys/fs/cgroup/systemd',
        read_only=True,
        type='bind',
    )
    try:
        container = client.containers.run(
            image=tiny_image,
            mounts=[cgroup_mount],
            detach=True,
        )
    except docker.errors.APIError as exc:
        expected = (
            'bind mount source path does not exist: /sys/fs/cgroup/systemd"')
        if expected in str(exc):
            message = (
                'Launching various applications requires ``/sys/fs/cgroup`` '
                'to be mounted from the host. '
                'This is because UCR applications require cgroup isolation. '
                'Therefore, by default, ``/sys/fs/cgroup`` is mounted from '
                'the host. '
                'It appears that this is not available on the host. '
                'Therefore, to launch a cluster you must use '
                '``--no-mount-sys-fs-cgroup``. '
                'Some applications will not work on the launched cluster.')
            error(message=message)
            return CheckLevels.WARNING
        raise

    container.stop()
    container.remove(v=True)

    return CheckLevels.NONE
Beispiel #12
0
def _check_mount_tmp() -> CheckLevels:
    """
    Error if it is not possible to mount the temporary directory.
    """
    highest_level = CheckLevels.NONE
    # Any image will do, we use this for another test so using it here saves
    # pulling another image.
    tiny_image = 'luca3m/sleep'
    client = docker_client()

    tmp_path = Path('/tmp').resolve()

    try:
        private_mount_container = client.containers.run(
            image=tiny_image,
            tty=True,
            detach=True,
            volumes={
                str(tmp_path): {
                    'bind': '/test',
                },
            },
        )
    except docker.errors.APIError as exc:
        message = ('There was an error mounting the temporary directory path '
                   '"{tmp_path}" in container: \n\n'
                   '{exception_detail}').format(
                       tmp_path=tmp_path,
                       exception_detail=exc.explanation.decode(
                           'ascii',
                           'backslashreplace',
                       ),
                   )
        error(message=message)
        highest_level = CheckLevels.ERROR

    private_mount_container.stop()
    private_mount_container.remove(v=True)
    return highest_level