예제 #1
0
    def __init__(
        self,
        masters: int,
        agents: int,
        public_agents: int,
        cluster_backend: AWS,
    ) -> None:
        """
        Create an AWS cluster.

        Args:
            masters: The number of master nodes to create.
            agents: The number of agent nodes to create.
            public_agents: The number of public agent nodes to create.
            cluster_backend: Details of the specific AWS backend to use.

        """
        unique = 'dcos-e2e-{random}'.format(random=str(uuid.uuid4()))

        self._path = cluster_backend.workspace_dir / unique
        self._path.mkdir(exist_ok=True)
        self._path = self._path.resolve() / unique
        self._path.mkdir(exist_ok=True)
        self._ip_detect_path = cluster_backend.ip_detect_path

        ssh_user = {
            Distribution.CENTOS_7: 'centos',
            Distribution.COREOS: 'core',
            Distribution.RHEL_7: 'ec2-user',
        }

        install_prereqs = {
            Distribution.COREOS:
            True,
            # There is a bug hit when using ``install_prereqs`` with some
            # distributions.
            # See https://jira.mesosphere.com/browse/DCOS-40894.
            Distribution.CENTOS_7:
            False,
            Distribution.RHEL_7:
            False,
        }[cluster_backend.linux_distribution]

        prereqs_script_filename = {
            Distribution.CENTOS_7: 'install_prereqs.sh',
            Distribution.COREOS: 'run_coreos_prereqs.sh',
            Distribution.RHEL_7: 'install_prereqs.sh',
        }[cluster_backend.linux_distribution]
        self._default_user = ssh_user[cluster_backend.linux_distribution]

        self.cluster_backend = cluster_backend
        self.dcos_launcher = None  # type: Optional[AbstractLauncher]

        aws_distros = {
            Distribution.CENTOS_7: 'cent-os-7-dcos-prereqs',
            Distribution.COREOS: 'coreos',
            Distribution.RHEL_7: 'rhel-7-dcos-prereqs',
        }

        deployment_name = (cluster_backend.aws_cloudformation_stack_name
                           or unique)
        launch_config = {
            'admin_location': cluster_backend.admin_location,
            'aws_region': cluster_backend.aws_region,
            'deployment_name': deployment_name,
            # Supply a valid URL to the preliminary config.
            # This is replaced later before the DC/OS installation.
            'installer_url': 'https://example.com',
            'instance_type': cluster_backend.aws_instance_type,
            'launch_config_version': 1,
            'num_masters': masters,
            'num_private_agents': agents,
            'num_public_agents': public_agents,
            'os_name': aws_distros[cluster_backend.linux_distribution],
            'platform': 'aws',
            'provider': 'onprem',
            'install_prereqs': install_prereqs,
            'prereqs_script_filename': prereqs_script_filename,
        }

        if cluster_backend.aws_key_pair is None:
            launch_config['key_helper'] = True
        else:
            aws_key_name, local_key_path = cluster_backend.aws_key_pair
            launch_config['ssh_private_key_filename'] = str(local_key_path)
            launch_config['aws_key_name'] = aws_key_name

        # First we create a preliminary dcos-config inside the
        # dcos-launch config to pass the config validation step.
        launch_config['dcos_config'] = self.cluster_backend.base_config

        # Validate the preliminary dcos-launch config.
        # This also fills in blanks in the dcos-launch config.
        validated_launch_config = config.get_validated_config(
            user_config=launch_config,
            config_dir=str(self._path),
        )

        # Get a OnpremLauncher object
        self.launcher = get_launcher(  # type: ignore
            config=validated_launch_config, )

        # Create the AWS stack from the DcosCloudformationLauncher.
        # Get the AWS SSH key information from this.
        cluster_create_info = self.launcher.create()
        private_key = cluster_create_info['ssh_private_key']

        # Store the generated AWS SSH key to the file system.
        self._ssh_key_path = self._path / 'id_rsa'
        self._ssh_key_path.write_bytes(private_key.encode())
        self._ssh_key_path.chmod(mode=stat.S_IRUSR)

        # Wait for the AWS stack setup completion.
        self.launcher.wait()

        # Update the cluster_info with AWS stack information:
        # ``describe`` fetches the latest information for the stack.
        # This makes node IP addresses available to ``cluster_info``.
        # This also inserts bootstrap node information into ``cluster_info``.
        self.cluster_info = self.launcher.describe()
        ec2 = boto3.resource('ec2', region_name=cluster_backend.aws_region)

        for nodes, tags in (
            (self.masters, cluster_backend.master_ec2_instance_tags),
            (self.agents, cluster_backend.agent_ec2_instance_tags),
            (
                self.public_agents,
                cluster_backend.public_agent_ec2_instance_tags,
            ),
        ):
            node_public_ips = set(
                str(node.public_ip_address) for node in nodes)
            ec2_instances = ec2.instances.filter(Filters=[
                {
                    'Name': 'ip-address',
                    'Values': list(node_public_ips),
                },
            ], )
            instance_ids = [instance.id for instance in ec2_instances]

            node_tags = {**cluster_backend.ec2_instance_tags, **tags}

            if not nodes:
                continue

            if not node_tags:
                continue

            ec2_tags = [{
                'Key': key,
                'Value': value,
            } for key, value in node_tags.items()]

            ec2.create_tags(Resources=instance_ids, Tags=ec2_tags)
예제 #2
0
    def __init__(
        self,
        masters: int,
        agents: int,
        public_agents: int,
        files_to_copy_to_installer: Dict[Path, Path],
        cluster_backend: AWS,
    ) -> None:
        """
        Create an AWS cluster.

        Args:
            masters: The number of master nodes to create.
            agents: The number of agent nodes to create.
            public_agents: The number of public agent nodes to create.
            files_to_copy_to_installer: Pairs of host paths to paths on the
                installer node. This must be empty as it is not currently
                supported.
            cluster_backend: Details of the specific AWS backend to use.

        Raises:
            NotImplementedError: ``files_to_copy_to_installer`` includes files
                to copy to the installer.
        """
        if files_to_copy_to_installer:
            # Copying files to the installer is not yet supported.
            # https://jira.mesosphere.com/browse/DCOS-21894
            message = (
                'Copying files to the installer is currently not supported by '
                'the AWS backend.'
            )
            raise NotImplementedError(message)

        unique = 'dcos-e2e-{}'.format(str(uuid.uuid4()))

        self._path = cluster_backend.workspace_dir / unique
        self._path.mkdir(exist_ok=True)
        self._path = self._path.resolve() / unique
        self._path.mkdir(exist_ok=True)

        ssh_user = {
            Distribution.CENTOS_7: 'centos',
            Distribution.COREOS: 'core',
        }
        self._default_user = ssh_user[cluster_backend.linux_distribution]

        self.cluster_backend = cluster_backend
        self.dcos_launcher = None  # type: Optional[AbstractLauncher]
        self.cluster_info = {}  # type: Dict[str, Any]

        aws_distros = {
            Distribution.CENTOS_7: 'cent-os-7-dcos-prereqs',
            Distribution.COREOS: 'coreos',
        }

        launch_config = {
            'admin_location': cluster_backend.admin_location,
            'aws_region': cluster_backend.aws_region,
            'deployment_name': unique,
            # Supply a valid URL to the preliminary config.
            # This is replaced later before the DC/OS installation.
            'installer_url': 'https://example.com',
            'instance_type': 'm4.large',
            'launch_config_version': 1,
            'num_masters': masters,
            'num_private_agents': agents,
            'num_public_agents': public_agents,
            'os_name': aws_distros[cluster_backend.linux_distribution],
            'platform': 'aws',
            'provider': 'onprem',
        }

        if cluster_backend.aws_key_pair is None:
            launch_config['key_helper'] = True
        else:
            aws_key_name, local_key_path = cluster_backend.aws_key_pair
            launch_config['ssh_private_key_filename'] = str(local_key_path)
            launch_config['aws_key_name'] = aws_key_name

        # Work around ``ip_detect_public_filename`` being ignored.
        # https://jira.mesosphere.com/browse/DCOS-21960
        detect_ip_public = (
            '"#!/bin/bash\\n '
            'curl -fsSL '
            'http://169.254.169.254/latest/meta-data/public-ipv4"'
        )

        # First we create a preliminary dcos-config inside the
        # dcos-launch config to pass the config validation step.
        launch_config['dcos_config'] = {
            'cluster_name': unique,
            'resolvers': ['10.10.0.2', '8.8.8.8'],
            'master_discovery': 'static',
            'exhibitor_storage_backend': 'static',
            'ip_detect_public_contents': detect_ip_public,
        }

        # Validate the preliminary dcos-launch config.
        # This also fills in blanks in the dcos-launch config.
        validated_launch_config = config.get_validated_config(
            user_config=launch_config,
            config_dir=str(self._path),
        )

        # Get a OnpremLauncher object
        self.launcher = get_launcher(  # type: ignore
            config=validated_launch_config,
        )

        # Create the AWS stack from the DcosCloudformationLauncher.
        # Update ``cluster_info`` with the AWS SSH key information.
        self.cluster_info = self.launcher.create()

        # Store the generated AWS SSH key to the file system.
        self._ssh_key_path = self._path / 'id_rsa'
        private_key = self.cluster_info['ssh_private_key']
        self._ssh_key_path.write_bytes(private_key.encode())

        # Wait for the AWS stack setup completion.
        self.launcher.wait()

        # Update the cluster_info with AWS stack information:
        # ``describe`` fetches the latest information for the stack.
        # This makes node IP addresses available to ``cluster_info``.
        # This also inserts bootstrap node information into ``cluster_info``.
        self.cluster_info = self.launcher.describe()