Ejemplo n.º 1
0
def clean() -> None:
    """
    Remove containers, volumes and networks created by this tool.
    """

    client = docker_client()

    filters = {
        'label': [
            '{key}={value}'.format(
                key=NODE_TYPE_LABEL_KEY,
                value=NODE_TYPE_LOOPBACK_SIDECAR_LABEL_VALUE,
            ),
        ],
    }
    loopback_sidecars = client.containers.list(filters=filters)
    for loopback_sidecar in loopback_sidecars:
        DockerLoopbackVolume.destroy(container=loopback_sidecar)

    node_filters = {'name': Docker().container_name_prefix}
    network_filters = {'name': Docker().container_name_prefix}

    node_containers = client.containers.list(filters=node_filters, all=True)

    for container in node_containers:
        container.stop()
        container.remove(v=True)

    networks = client.networks.list(filters=network_filters)
    for network in networks:
        network.remove()
Ejemplo n.º 2
0
    def test_default(self) -> None:
        """
        The default Linux distribution is CentOS 7.

        This test does not wait for DC/OS and we do not test DC/OS Enterprise
        because these are covered by other tests which use the default
        settings.
        """
        with Cluster(
                cluster_backend=Docker(),
                masters=1,
                agents=0,
                public_agents=0,
        ) as cluster:
            (master, ) = cluster.masters
            node_distribution = _get_node_distribution(node=master)

        assert node_distribution == Distribution.CENTOS_7

        with Cluster(
                # The distribution is also CentOS 7 if it is explicitly set.
                cluster_backend=Docker(
                    linux_distribution=Distribution.CENTOS_7),
                masters=1,
                agents=0,
                public_agents=0,
        ) as cluster:
            (master, ) = cluster.masters
            node_distribution = _get_node_distribution(node=master)

        assert node_distribution == Distribution.CENTOS_7
Ejemplo n.º 3
0
 def test_docker_exec_transport(
     self,
     docker_network: Network,
     tmpdir: local,
 ) -> None:
     """
     ``Node`` operations with the Docker exec transport work even if the
     node is on a custom network.
     """
     with Cluster(
         cluster_backend=Docker(
             network=docker_network,
             transport=Transport.DOCKER_EXEC,
         ),
         agents=0,
         public_agents=0,
     ) as cluster:
         (master, ) = cluster.masters
         content = str(uuid.uuid4())
         local_file = tmpdir.join('example_file.txt')
         local_file.write(content)
         random = uuid.uuid4().hex
         master_destination_dir = '/etc/{random}'.format(random=random)
         master_destination_path = Path(master_destination_dir) / 'file.txt'
         master.send_file(
             local_path=Path(str(local_file)),
             remote_path=master_destination_path,
             transport=Transport.DOCKER_EXEC,
         )
         args = ['cat', str(master_destination_path)]
         result = master.run(args=args, transport=Transport.DOCKER_EXEC)
         assert result.stdout.decode() == content
Ejemplo n.º 4
0
    def test_custom_docker_network(
        self,
        docker_network: Network,
    ) -> None:
        """
        When a network is specified on the Docker backend, each container is
        connected to the default bridge network ``docker0`` and in addition it
        also connected to the custom network.

        The ``Node``'s IP addresses correspond to the custom network.
        """
        with Cluster(
            cluster_backend=Docker(
                network=docker_network,
                transport=Transport.DOCKER_EXEC,
            ),
            agents=0,
            public_agents=0,
        ) as cluster:
            (master, ) = cluster.masters
            container = _get_container_from_node(node=master)
            networks = container.attrs['NetworkSettings']['Networks']
            assert networks.keys() == set(['bridge', docker_network.name])
            custom_network_ip = networks[docker_network.name]['IPAddress']
            assert custom_network_ip == str(master.public_ip_address)
            assert custom_network_ip == str(master.private_ip_address)
Ejemplo n.º 5
0
def _oss_distribution_test(
    distribution: Distribution,
    oss_artifact: Path,
) -> None:
    """
    Assert that given a ``linux_distribution``, an open source DC/OS
    ``Cluster`` with the Linux distribution is started.

    We use this rather than pytest parameterization so that we can separate
    the tests in ``.travis.yml``.
    """
    with Cluster(
            cluster_backend=Docker(linux_distribution=distribution),
            masters=1,
            agents=0,
            public_agents=0,
    ) as cluster:
        cluster.install_dcos_from_path(
            build_artifact=oss_artifact,
            dcos_config=cluster.base_config,
            log_output_live=True,
        )
        cluster.wait_for_dcos_oss()
        (master, ) = cluster.masters
        node_distribution = _get_node_distribution(node=master)

    assert node_distribution == distribution
Ejemplo n.º 6
0
    def test_custom_version(self, docker_version: DockerVersion) -> None:
        """
        It is possible to set a custom version of Docker.

        Running this test requires ``aufs`` to be available.
        Depending on your system, it may be possible to make ``aufs`` available
        using the following commands:

        .. code

           $ apt-get install linux-image-extra-$(uname -r)
           $ modprobe aufs
        """
        # We specify the storage driver because `overlay2` is not compatible
        # with old versions of Docker.
        with Cluster(
                cluster_backend=Docker(
                    docker_version=docker_version,
                    storage_driver=DockerStorageDriver.AUFS,
                ),
                masters=1,
                agents=0,
                public_agents=0,
        ) as cluster:
            (master, ) = cluster.masters
            node_docker_version = self._get_docker_version(node=master)

        assert docker_version == node_docker_version
Ejemplo n.º 7
0
    def test_one_master_host_port_map(self) -> None:
        """
        It is possible to expose admin router to a host port.
        """

        with Cluster(
                cluster_backend=Docker(
                    one_master_host_port_map={'80/tcp': 8000}),
                masters=3,
                agents=0,
                public_agents=0,
        ) as cluster:
            masters_containers = [
                _get_container_from_node(node=node) for node in cluster.masters
            ]

            masters_ports_settings = [
                container.attrs['HostConfig']['PortBindings']
                for container in masters_containers
            ]

            masters_ports_settings.remove(None)
            masters_ports_settings.remove(None)

            [master_port_settings] = masters_ports_settings
            expected_master_port_settings = {
                '80/tcp': [{
                    'HostIp': '',
                    'HostPort': '8000',
                }],
            }
            assert master_port_settings == expected_master_port_settings
Ejemplo n.º 8
0
 def docker_network(self) -> Iterator[Network]:
     """
     Return a Docker network.
     """
     client = docker.from_env(version='auto')
     ipam_pool = docker.types.IPAMPool(
         subnet='172.28.0.0/16',
         iprange='172.28.0.0/24',
         gateway='172.28.0.254',
     )
     # We use the default container prefix so that the
     # ``minidcos docker clean`` command cleans this up.
     prefix = Docker().container_name_prefix
     random = uuid.uuid4()
     name = '{prefix}-network-{random}'.format(prefix=prefix, random=random)
     network = client.networks.create(
         name=name,
         driver='bridge',
         ipam=docker.types.IPAMConfig(pool_configs=[ipam_pool]),
         attachable=False,
     )
     try:
         yield network
     finally:
         network.remove()
Ejemplo n.º 9
0
def node_transport_option(command: Callable[..., None]) -> Callable[..., None]:
    """
    An option decorator for node transport options.
    """
    transports = {
        'ssh': Transport.SSH,
        'docker-exec': Transport.DOCKER_EXEC,
    }

    backend_default = Docker().transport
    [default_option] = [
        transport for transport in transports
        if transports[transport] == backend_default
    ]

    function = click.option(
        '--transport',
        type=click.Choice(sorted(transports.keys())),
        callback=lambda ctx, param, value: transports[value],
        default=default_option,
        show_default=True,
        envvar='MINIDCOS_DOCKER_TRANSPORT',
        help=(
            'The communication transport to use. '
            'On macOS the SSH transport requires IP routing to be set up. '
            'See "minidcos docker setup-mac-network". '
            'It also requires the "ssh" command to be available. '
            'This can be provided by setting the `MINIDCOS_DOCKER_TRANSPORT` '
            'environment variable. '
            'When using a TTY, different transports may use different line '
            'endings.'),
    )(command)  # type: Callable[..., None]
    return function
Ejemplo n.º 10
0
def _oss_distribution_test(
    distribution: Distribution,
    oss_installer: Path,
) -> None:
    """
    Assert that given a ``linux_distribution``, an open source DC/OS
    ``Cluster`` with the Linux distribution is started.

    We use this rather than pytest parameterization so that we can separate
    the tests in ``.travis.yml``.
    """
    cluster_backend = Docker(linux_distribution=distribution)
    with Cluster(
            cluster_backend=cluster_backend,
            masters=1,
            agents=0,
            public_agents=0,
    ) as cluster:
        cluster.install_dcos_from_path(
            dcos_installer=oss_installer,
            dcos_config=cluster.base_config,
            output=Output.CAPTURE,
            ip_detect_path=cluster_backend.ip_detect_path,
        )
        cluster.wait_for_dcos_oss()
        (master, ) = cluster.masters
        node_distribution = _get_node_distribution(node=master)

    assert node_distribution == distribution
Ejemplo n.º 11
0
def docker_backend() -> Docker:
    """
    Creates a common Docker backend configuration that works within the pytest
    environment directory.
    """
    tmp_dir_path = Path(os.environ['DCOS_E2E_TMP_DIR_PATH'])
    assert tmp_dir_path.exists() and tmp_dir_path.is_dir()

    return Docker(workspace_dir=tmp_dir_path)
Ejemplo n.º 12
0
    def base_config(self) -> Dict[str, Any]:
        """
        Return a base configuration for installing DC/OS OSS.
        """
        backend = Docker()

        return {
            **self.cluster.base_config,
            **backend.base_config,
        }
Ejemplo n.º 13
0
 def test_install_dcos_from_url(self, oss_installer_url: str) -> None:
     """
     It is possible to install DC/OS on a cluster with a Docker backend.
     """
     cluster_backend = Docker()
     with Cluster(cluster_backend=cluster_backend) as cluster:
         cluster.install_dcos_from_url(
             dcos_installer=oss_installer_url,
             dcos_config=cluster.base_config,
             ip_detect_path=cluster_backend.ip_detect_path,
             output=Output.LOG_AND_CAPTURE,
         )
         cluster.wait_for_dcos_oss()
Ejemplo n.º 14
0
 def test_install_dcos_from_url(self, oss_artifact_url: str) -> None:
     """
     It is possible to install DC/OS on a cluster with a Docker backend.
     """
     # We use a specific version of Docker on the nodes because else we may
     # hit https://github.com/opencontainers/runc/issues/1175.
     cluster_backend = Docker(docker_version=DockerVersion.v17_12_1_ce)
     with Cluster(cluster_backend=cluster_backend) as cluster:
         cluster.install_dcos_from_url(
             build_artifact=oss_artifact_url,
             dcos_config=cluster.base_config,
         )
         cluster.wait_for_dcos_oss()
Ejemplo n.º 15
0
    def test_custom(self) -> None:
        """
        It is possible to set node Docker container labels.
        """
        cluster_key = uuid.uuid4().hex
        cluster_value = uuid.uuid4().hex
        cluster_labels = {cluster_key: cluster_value}

        master_key = uuid.uuid4().hex
        master_value = uuid.uuid4().hex
        master_labels = {master_key: master_value}

        agent_key = uuid.uuid4().hex
        agent_value = uuid.uuid4().hex
        agent_labels = {agent_key: agent_value}

        public_agent_key = uuid.uuid4().hex
        public_agent_value = uuid.uuid4().hex
        public_agent_labels = {public_agent_key: public_agent_value}

        with Cluster(
                cluster_backend=Docker(
                    docker_container_labels=cluster_labels,
                    docker_master_labels=master_labels,
                    docker_agent_labels=agent_labels,
                    docker_public_agent_labels=public_agent_labels,
                ),
                masters=1,
                agents=1,
                public_agents=1,
        ) as cluster:
            for node in cluster.masters:
                node_labels = self._get_labels(node=node)
                assert node_labels[cluster_key] == cluster_value
                assert node_labels[master_key] == master_value
                assert agent_key not in node_labels
                assert public_agent_key not in node_labels

            for node in cluster.agents:
                node_labels = self._get_labels(node=node)
                assert node_labels[cluster_key] == cluster_value
                assert node_labels[agent_key] == agent_value
                assert master_key not in node_labels
                assert public_agent_key not in node_labels

            for node in cluster.public_agents:
                node_labels = self._get_labels(node=node)
                assert node_labels[cluster_key] == cluster_value
                assert node_labels[public_agent_key] == public_agent_value
                assert master_key not in node_labels
                assert agent_key not in node_labels
Ejemplo n.º 16
0
    def test_default(self, host_driver: str) -> None:
        """
        By default, the Docker storage driver is the same as the host's
        storage driver, if that driver is supported.
        """
        client = docker.from_env(version='auto')
        info = {**client.info(), **{'Driver': host_driver}}

        with Mocker(real_http=True) as mock:
            mock.get(url=self._docker_info_endpoint, json=info)
            cluster_backend = Docker()

        storage_driver = cluster_backend.docker_storage_driver
        assert storage_driver == self.DOCKER_STORAGE_DRIVERS[host_driver]
Ejemplo n.º 17
0
    def test_default(self) -> None:
        """
        By default, the Docker version is 1.13.1.
        """
        with Cluster(
                cluster_backend=Docker(),
                masters=1,
                agents=0,
                public_agents=0,
        ) as cluster:
            (master, ) = cluster.masters
            docker_version = self._get_docker_version(node=master)

        assert docker_version == DockerVersion.v1_13_1
Ejemplo n.º 18
0
def _check_can_mount_in_docker() -> CheckLevels:
    """
    Check for an incompatibility between some systemd versions and some
    versions of Docker.
    """
    docker_client()

    cluster_backend = Docker(docker_version=DockerVersion.v1_13_1)
    args = ['docker', 'run', '-v', '/foo', 'alpine']

    error_message_substring = 'no subsystem for mount'
    with Cluster(cluster_backend=cluster_backend) as cluster:
        (public_agent, ) = cluster.public_agents
        try:
            public_agent.run(args=args)
        except subprocess.CalledProcessError as exc:
            if error_message_substring not in exc.stderr.decode():
                raise

            message = (
                'An issue has been detected which means that, for some '
                'versions of Docker inside DC/OS nodes, it will not be '
                'possible to create containers with mounts. '
                'Some functionality may be affected by this, for example '
                'extracting the DC/OS installer on a node.'
                '\n'
                'This issue is likely because the host\'s version of systemd '
                'is greater than version 232, which causes the following '
                'known issue: '
                'https://github.com/opencontainers/runc/issues/1175.'
                '\n'
                'Newer versions of Docker, work well with new versions of '
                'systemd. '
                'To avoid issues caused by this incompatibility, do one of '
                'the following:'
                '\n* Set ``systemd.legacy_systemd_cgroup_controller=yes`` as '
                'a kernel parameter on your host.'
                '\n* Use versions of Docker newer than 1.13.1 inside the '
                'DC/OS nodes.'
                ' To do this in the ``dcos-docker`` CLI, use the '
                '``--docker-version`` option on ``dcos-docker create``.'
                ' To do this in the Python library, pass a '
                '``docker_version`` parameter to the ``Docker`` backend class.'
            )
            warn(message=message)
            return CheckLevels.WARNING

    return CheckLevels.NONE
Ejemplo n.º 19
0
 def test_default(self) -> None:
     """
     By default, the only network a container is in is the Docker default
     bridge network.
     """
     with Cluster(
         cluster_backend=Docker(),
         agents=0,
         public_agents=0,
     ) as cluster:
         (master, ) = cluster.masters
         container = _get_container_from_node(node=master)
         networks = container.attrs['NetworkSettings']['Networks']
         assert networks.keys() == set(['bridge'])
         bridge_ip_address = networks['bridge']['IPAddress']
         assert bridge_ip_address == str(master.public_ip_address)
         assert bridge_ip_address == str(master.private_ip_address)
Ejemplo n.º 20
0
    def test_custom(
        self,
        host_driver: str,
        custom_driver: DockerStorageDriver,
    ) -> None:
        """
        A custom storage driver can be used.
        """
        client = docker.from_env(version='auto')
        info = {**client.info(), **{'Driver': host_driver}}

        with Mocker(real_http=True) as mock:
            mock.get(url=self._docker_info_endpoint, json=info)
            cluster_backend = Docker(storage_driver=custom_driver)

        storage_driver = cluster_backend.docker_storage_driver
        assert storage_driver == custom_driver
Ejemplo n.º 21
0
def _enterprise_distribution_test(
    distribution: Distribution,
    enterprise_artifact: Path,
    license_key_contents: str,
) -> None:
    """
    Assert that given a ``linux_distribution``, a DC/OS Enterprise ``Cluster``
    with the Linux distribution is started.

    We use this rather than pytest parameterization so that we can separate
    the tests in ``.travis.yml``.
    """
    superuser_username = str(uuid.uuid4())
    superuser_password = str(uuid.uuid4())
    config = {
        'superuser_username': superuser_username,
        'superuser_password_hash': sha512_crypt.hash(superuser_password),
        'fault_domain_enabled': False,
        'license_key_contents': license_key_contents,
    }

    cluster_backend = Docker(linux_distribution=distribution)
    with Cluster(
            cluster_backend=cluster_backend,
            masters=1,
            agents=0,
            public_agents=0,
    ) as cluster:
        cluster.install_dcos_from_path(
            build_artifact=enterprise_artifact,
            dcos_config={
                **cluster.base_config,
                **config,
            },
            ip_detect_path=cluster_backend.ip_detect_path,
            log_output_live=True,
        )
        cluster.wait_for_dcos_ee(
            superuser_username=superuser_username,
            superuser_password=superuser_password,
        )
        (master, ) = cluster.masters
        node_distribution = _get_node_distribution(node=master)

    assert node_distribution == distribution
Ejemplo n.º 22
0
def dcos_node(request: SubRequest) -> Iterator[Node]:
    """
    Return a ``Node``.

    This is module scoped as we do not intend to modify the cluster in ways
    that make tests interfere with one another.
    """
    # We use the Docker backend because it is currently the only one which
    # supports all transports.
    cluster_backend = Docker(transport=request.param)
    with Cluster(
        cluster_backend=cluster_backend,
        masters=1,
        agents=0,
        public_agents=0,
    ) as cluster:
        (master, ) = cluster.masters
        yield master
Ejemplo n.º 23
0
 def test_pass_bridge(self) -> None:
     """
     If the bridge network is given, the only network a container is in
     is the Docker default bridge network.
     """
     client = docker.from_env(version='auto')
     network = client.networks.get(network_id='bridge')
     with Cluster(
         cluster_backend=Docker(network=network),
         agents=0,
         public_agents=0,
     ) as cluster:
         (master, ) = cluster.masters
         container = _get_container_from_node(node=master)
         networks = container.attrs['NetworkSettings']['Networks']
         assert networks.keys() == set(['bridge'])
         bridge_ip_address = networks['bridge']['IPAddress']
         assert bridge_ip_address == str(master.public_ip_address)
         assert bridge_ip_address == str(master.private_ip_address)
Ejemplo n.º 24
0
def test_windows_agents(
    workspace_dir: Path,
    artifact_path: Path,
    request: SubRequest,
    log_dir: Path,
) -> None:
    """
    Enabling Windows agents creates additional configuration package
    and does not break Linux installation.
    """
    docker_backend = Docker(workspace_dir=workspace_dir)

    config = {
        'enable_windows_agents': True,
    }
    with Cluster(
            cluster_backend=docker_backend,
            agents=0,
            public_agents=0,
    ) as cluster:
        cluster.install_dcos_from_path(
            dcos_installer=artifact_path,
            dcos_config={
                **cluster.base_config,
                **config,
            },
            output=Output.LOG_AND_CAPTURE,
            ip_detect_path=docker_backend.ip_detect_path,
        )

        # Check that dcos-config-win.tar.xz was created
        paths = []
        for root, _, files in os.walk(str(workspace_dir)):
            for file in files:
                if file.startswith('dcos-config-win--setup_'):
                    paths.append(Path(root) / file)
        assert len(paths) == 1

        wait_for_dcos_oss(
            cluster=cluster,
            request=request,
            log_dir=log_dir,
        )
Ejemplo n.º 25
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
Ejemplo n.º 26
0
 def test_install_dcos_from_path(self, oss_artifact: Path) -> None:
     """
     It is possible to install DC/OS on a node from a path.
     """
     # We use a specific version of Docker on the nodes because else we may
     # hit https://github.com/opencontainers/runc/issues/1175.
     cluster_backend = Docker(docker_version=DockerVersion.v17_12_1_ce)
     with Cluster(cluster_backend=cluster_backend) as cluster:
         for nodes, role in (
             (cluster.masters, Role.MASTER),
             (cluster.agents, Role.AGENT),
             (cluster.public_agents, Role.PUBLIC_AGENT),
         ):
             for node in nodes:
                 node.install_dcos_from_path(
                     build_artifact=oss_artifact,
                     dcos_config=cluster.base_config,
                     role=role,
                 )
         cluster.wait_for_dcos_oss()
Ejemplo n.º 27
0
 def test_install_dcos_from_path(self, oss_installer: Path) -> None:
     """
     It is possible to install DC/OS on a node from a path.
     """
     cluster_backend = Docker()
     with Cluster(cluster_backend=cluster_backend) as cluster:
         for nodes, role in (
             (cluster.masters, Role.MASTER),
             (cluster.agents, Role.AGENT),
             (cluster.public_agents, Role.PUBLIC_AGENT),
         ):
             for node in nodes:
                 node.install_dcos_from_path(
                     dcos_installer=oss_installer,
                     dcos_config=cluster.base_config,
                     ip_detect_path=cluster_backend.ip_detect_path,
                     role=role,
                     output=Output.LOG_AND_CAPTURE,
                 )
         cluster.wait_for_dcos_oss()
Ejemplo n.º 28
0
    def test_install_dcos_from_url(self, oss_artifact_url: str) -> None:
        """
        The Docker backend requires a build artifact in order
        to launch a DC/OS cluster.
        """
        with Cluster(
            cluster_backend=Docker(),
            masters=1,
            agents=0,
            public_agents=0,
        ) as cluster:
            with pytest.raises(NotImplementedError) as excinfo:
                cluster.install_dcos_from_url(oss_artifact_url)

        expected_error = (
            'The Docker backend does not support the installation of DC/OS '
            'by build artifacts passed via URL string. This is because a more '
            'efficient installation method exists in `install_dcos_from_path`.'
        )

        assert str(excinfo.value) == expected_error
Ejemplo n.º 29
0
    def test_host_driver_not_supported(self) -> None:
        """
        If the host's storage driver is not supported, `aufs` is used.
        """
        client = docker.from_env(version='auto')
        info = {**client.info(), **{'Driver': 'not_supported'}}

        with Mocker(real_http=True) as mock:
            mock.get(url=self._docker_info_endpoint, json=info)
            backend = Docker()

        assert backend.docker_storage_driver == DockerStorageDriver.AUFS

        with Cluster(
                cluster_backend=backend,
                masters=1,
                agents=0,
                public_agents=0,
        ) as cluster:
            (master, ) = cluster.masters
            node_driver = self._get_storage_driver(node=master)

        assert node_driver == DockerStorageDriver.AUFS
Ejemplo n.º 30
0
def create(
    ctx: click.core.Context,
    agents: int,
    installer: Path,
    cluster_id: str,
    docker_storage_driver: Optional[DockerStorageDriver],
    docker_version: DockerVersion,
    extra_config: Dict[str, Any],
    linux_distribution: Distribution,
    masters: int,
    public_agents: int,
    license_key: Optional[Path],
    security_mode: Optional[str],
    copy_to_master: List[Tuple[Path, Path]],
    genconf_dir: Optional[Path],
    workspace_dir: Path,
    custom_volume: List[Mount],
    custom_master_volume: List[Mount],
    custom_agent_volume: List[Mount],
    custom_public_agent_volume: List[Mount],
    variant: str,
    transport: Transport,
    wait_for_dcos: bool,
    network: Network,
    one_master_host_port_map: Dict[str, int],
    mount_sys_fs_cgroup: bool,
) -> None:
    """
    Create a DC/OS cluster.
    """
    check_cluster_id_unique(
        new_cluster_id=cluster_id,
        existing_cluster_ids=existing_cluster_ids(),
    )

    http_checks = bool(transport == Transport.SSH)
    wait_command_name = command_path(sibling_ctx=ctx, command=wait)
    doctor_command_name = command_path(sibling_ctx=ctx, command=doctor)
    doctor_message = get_doctor_message(
        doctor_command_name=doctor_command_name, )
    public_key_path = workspace_dir / 'id_rsa.pub'
    private_key_path = workspace_dir / 'id_rsa'
    write_key_pair(
        public_key_path=public_key_path,
        private_key_path=private_key_path,
    )

    dcos_variant = get_install_variant(
        given_variant=variant,
        installer_path=installer,
        workspace_dir=workspace_dir,
        doctor_message=doctor_message,
    )

    # This is useful for some people to identify containers.
    container_name_prefix = Docker().container_name_prefix + '-' + cluster_id

    cluster_backend = Docker(
        container_name_prefix=container_name_prefix,
        custom_container_mounts=custom_volume,
        custom_master_mounts=custom_master_volume,
        custom_agent_mounts=custom_agent_volume,
        custom_public_agent_mounts=custom_public_agent_volume,
        linux_distribution=linux_distribution,
        docker_version=docker_version,
        storage_driver=docker_storage_driver,
        docker_container_labels={
            CLUSTER_ID_LABEL_KEY: cluster_id,
            WORKSPACE_DIR_LABEL_KEY: str(workspace_dir),
        },
        docker_master_labels={
            NODE_TYPE_LABEL_KEY: NODE_TYPE_MASTER_LABEL_VALUE,
        },
        docker_agent_labels={NODE_TYPE_LABEL_KEY: NODE_TYPE_AGENT_LABEL_VALUE},
        docker_public_agent_labels={
            NODE_TYPE_LABEL_KEY: NODE_TYPE_PUBLIC_AGENT_LABEL_VALUE,
        },
        workspace_dir=workspace_dir,
        transport=transport,
        network=network,
        one_master_host_port_map=one_master_host_port_map,
        mount_sys_fs_cgroup=mount_sys_fs_cgroup,
    )

    cluster = create_cluster(
        cluster_backend=cluster_backend,
        masters=masters,
        agents=agents,
        public_agents=public_agents,
        doctor_message=doctor_message,
    )

    cluster_containers = ClusterContainers(
        cluster_id=cluster_id,
        transport=transport,
    )
    private_ssh_key_path = cluster_containers.ssh_key_path
    private_ssh_key_path.parent.mkdir(parents=True)
    private_key_path.replace(private_ssh_key_path)

    add_authorized_key(cluster=cluster, public_key_path=public_key_path)

    for node in cluster.masters:
        for path_pair in copy_to_master:
            local_path, remote_path = path_pair
            node.send_file(
                local_path=local_path,
                remote_path=remote_path,
            )

    dcos_config = get_config(
        cluster_representation=cluster_containers,
        extra_config=extra_config,
        dcos_variant=dcos_variant,
        security_mode=security_mode,
        license_key=license_key,
    )

    install_dcos_from_path(
        cluster_representation=cluster_containers,
        dcos_config=dcos_config,
        ip_detect_path=cluster_backend.ip_detect_path,
        doctor_message=doctor_message,
        dcos_installer=installer,
        local_genconf_dir=genconf_dir,
    )

    run_post_install_steps(
        cluster=cluster,
        cluster_id=cluster_id,
        dcos_config=dcos_config,
        doctor_command_name=doctor_command_name,
        http_checks=http_checks,
        wait_command_name=wait_command_name,
        wait_for_dcos=wait_for_dcos,
    )