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)
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()