示例#1
0
    def create_or_update_stack(self, managed_policy_arns: list, output: AbstractOutputWriter, tags: list):
        """Creates or updates an instance profile.
        It was moved to a separate stack because creating of an instance profile resource takes 2 minutes.
        """
        # check that policies exist
        iam = boto3.client('iam', region_name=self._region)
        for policy_arn in managed_policy_arns:
            # if the policy doesn't exist, an error will be raised
            iam.get_policy(PolicyArn=policy_arn)

        template = prepare_instance_profile_template(managed_policy_arns)

        stack = Stack.get_by_name(self._cf, self._stack_name)
        try:
            if stack:
                # update the stack and wait until it will be updated
                self._update_stack(template, output, tags)
            else:
                # create the stack and wait until it will be created
                self._create_stack(template, output, tags)

            stack = Stack.get_by_name(self._cf, self._stack_name)
        except WaiterError:
            stack = None

        if not stack or stack.status not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']:
            raise ValueError('Stack "%s" was not created.\n'
                             'Please, see CloudFormation logs for the details.' % self._stack_name)

        profile_arn = [row['OutputValue'] for row in stack.outputs if row['OutputKey'] == 'ProfileArn'][0]

        return profile_arn
示例#2
0
    def delete_stack(self, output: AbstractOutputWriter, stack_id=None):
        """Deletes an AMI stack.

        Args:
            output: output writer
            stack_id: ID of the stack to delete (for older versions of Spotty)
        """
        # delete the image
        stack = Stack.get_by_name(self._cf,
                                  stack_id) if stack_id else self.get_stack()
        stack.delete()

        output.write('Waiting for the AMI to be deleted...')

        # wait for the deletion to be completed
        with output.prefix('  '):
            stack = stack.wait_status_changed(
                waiting_status='DELETE_IN_PROGRESS',
                resource_messages=[],
                resource_success_status='DELETE_COMPLETE',
                output=output)

        if stack.status == 'DELETE_COMPLETE':
            output.write('\n'
                         '-----------------------------\n'
                         'AMI was successfully deleted.\n'
                         '-----------------------------')
        else:
            raise ValueError(
                'Stack "%s" not deleted.\n'
                'See CloudFormation and CloudWatch logs for details.' %
                stack_id)
    def _create_stack(self, template: str, output: AbstractOutputWriter):
        """Creates the stack and waits until it will be created."""
        output.write('Creating IAM role for the instance...')

        stack = Stack.create_stack(
            cf=self._cf,
            StackName=self._stack_name,
            TemplateBody=template,
            Capabilities=['CAPABILITY_IAM'],
            OnFailure='DELETE',
        )

        # wait for the stack to be created
        stack.wait_stack_created(delay=15)
    def _update_stack(self, template: str, output: AbstractOutputWriter):
        """Updates the stack and waits until it will be updated."""
        try:
            updated_stack = Stack.update_stack(
                cf=self._cf,
                StackName=self._stack_name,
                TemplateBody=template,
                Capabilities=['CAPABILITY_IAM'],
            )
        except ClientError as e:
            # the stack was not updated because there are no changes
            updated_stack = None
            error_code = e.response.get('Error', {}).get('Code', 'Unknown')
            if error_code != 'ValidationError':
                raise e

        if updated_stack:
            # wait for the stack to be updated
            output.write('Updating IAM role for the instance...')
            updated_stack.wait_stack_updated(delay=15)
示例#5
0
    def create_stack(self, template: str, parameters: dict, debug_mode: bool,
                     output: AbstractOutputWriter):
        """Creates an AMI stack and waits for the AMI to be created.

        Args:
            template: CloudFormation template
            parameters: parameters for the template
            debug_mode: if "True", NVIDIA Docker will be installed, but an AMI will not be created and the instance
                        will not be terminated, so the user can connect to the instance for debugging.
            output: output writer
        """
        stack = Stack.create_stack(
            cf=self._cf,
            StackName=self._stack_name,
            TemplateBody=template,
            Parameters=[{
                'ParameterKey': key,
                'ParameterValue': value
            } for key, value in parameters.items()],
            Capabilities=['CAPABILITY_IAM'],
            OnFailure='DO_NOTHING' if debug_mode else 'DELETE',
        )

        output.write('Waiting for the AMI to be created...')

        resource_messages = [
            ('InstanceProfile', 'creating IAM role for the instance'),
            ('Instance', 'launching the instance'),
            ('InstanceReadyWaitCondition', 'installing NVIDIA Docker'),
            ('AMICreatedWaitCondition',
             'creating AMI and terminating the instance'),
        ]

        # wait for the stack to be created
        with output.prefix('  '):
            stack = stack.wait_status_changed(
                waiting_status='CREATE_IN_PROGRESS',
                resource_messages=resource_messages,
                resource_success_status='CREATE_COMPLETE',
                output=output)

        if stack.status != 'CREATE_COMPLETE':
            raise ValueError(
                'Stack "%s" was not created.\n'
                'Please, see CloudFormation logs for the details.' %
                self._stack_name)

        if debug_mode:
            output.write('Stack "%s" was created in debug mode.' %
                         self._stack_name)
        else:
            ami_id = [
                row['OutputValue'] for row in stack.outputs
                if row['OutputKey'] == 'NewAMI'
            ][0]
            output.write('\n'
                         '--------------------------------------------------\n'
                         'AMI "%s" (ID=%s) was successfully created.\n'
                         'Use the "spotty start" command to run an instance.\n'
                         '--------------------------------------------------' %
                         (parameters['ImageName'], ami_id))
示例#6
0
 def get_stack(self) -> Stack:
     return Stack.get_by_name(self._cf, self._stack_name)