Example #1
0
    def kill_instances(self, instances_to_kill):
        # type: (List[Dict[str, Any]]) -> None
        if not instances_to_kill:
            return

        if not self.force:
            print('Will kill the following instance{}:'.format(
                's' if len(instances_to_kill) else ''))
            for instance in instances_to_kill:
                if isinstance(instance, str):
                    print(instance)
                else:
                    print(format_instance(instance))

            try:
                res = input('Proceed? (y/n) ')[0].lower()
            except KeyboardInterrupt:
                print('Not killing.')
                return

            if res != 'y':
                print('Not killing.')
                return

        instance_ids = [
            instance if isinstance(instance, str) else instance['InstanceId']
            for instance in instances_to_kill
        ]
        args = ['aws', 'ec2', 'terminate-instances', '--instance-ids'
                ] + instance_ids
        subprocess.check_call(args)
def list_instances(instances):
    # type: (List[Dict[str, Any]]) -> None
    if not instances:
        print('No instances running!')
        return

    for i, instance in enumerate(instances):
        print(('{}) {}'.format(i + 1, format_instance(instance))))
Example #3
0
def interactively_kill_instances(instance_killer):
    # type: (InstanceKiller) -> None

    while True:
        instances = instance_killer.get_running_instances()
        if not instances:
            print('No instances to kill!')
            return

        print('Active instances:')
        for i, instance in enumerate(instances):
            print('{}) {}'.format(i + 1, format_instance(instance)))

        try:
            res = input(
                'Enter a number to kill that instance, "a" to kill all, or "q" to exit: '
            )
        except KeyboardInterrupt:
            return
        except EOFError:
            return

        if res[0].lower() == 'q':
            return
        elif res[0].lower() == 'a':
            instance_killer.kill_instances(instances)
        else:
            try:
                index_to_kill = int(res)
            except ValueError:
                print('"{}" is not an integer.'.format(res))
                continue

            if index_to_kill < 1 or index_to_kill > len(instances):
                print('{} is not between 1 and {}.'.format(
                    index_to_kill,
                    len(instances) + 1))
                continue

            instance_to_kill = instances[index_to_kill - 1]

            instance_killer.kill_instances([instance_to_kill])
Example #4
0
    def start_instance(self):
        # type: () -> None

        if not self.force:
            running_instances = self.get_running_instances()
            if running_instances:
                print('You already have {} running instances:'.format(
                    len(running_instances)))
                for instance in running_instances:
                    print(format_instance(instance))
                try:
                    res = input(
                        'Would you still like to continue? (y/n) ').lower()[0]
                except KeyboardInterrupt:
                    print('Not creating a new instance')
                    return

                if res[0] != 'y':
                    print('Not creating a new instance')
                    return

        name = 'Ithemal'
        if self.name:
            name += ': {}'.format(self.name)

        block_device_mappings = [{
            "DeviceName": "/dev/xvda",
            "Ebs": {
                "VolumeSize": 16
            }
        }]
        iam_profile_name = 'ithemal-ec2'
        iam_profile_struct = {'Name': iam_profile_name}

        if self.spot:
            launch_specification = {
                'InstanceType': self.instance_type,
                'SecurityGroupIds': ['sg-0780fe1760c00d96d'],
                'BlockDeviceMappings': block_device_mappings,
                'KeyName': self.identity,
                'ImageId': 'ami-0b59bfac6be064b78',
                'IamInstanceProfile': iam_profile_struct,
            }
            run_com = lambda com: json.loads(subprocess.check_output(com))[
                'SpotInstanceRequests'][0]
            com = [
                'aws', 'ec2', 'request-spot-instances',
                '--launch-specification',
                json.dumps(launch_specification)
            ]
            if self.spot > 0:
                com.extend(['--block-duration-minutes', str(self.spot * 60)])
            output = run_com(com)
            print('Submitted spot instance request')

            try:
                while 'InstanceId' not in output:
                    print('\rWaiting for spot request to be fulfilled ({})...'.
                          format(output['Status']['Code']),
                          end=' ' * 20 + '\r')

                    time.sleep(1)
                    output = run_com([
                        'aws',
                        'ec2',
                        'describe-spot-instance-requests',
                        '--spot-instance-request-ids',
                        output['SpotInstanceRequestId'],
                    ])

            except (KeyboardInterrupt, SystemExit):
                subprocess.check_call([
                    'aws',
                    'ec2',
                    'cancel-spot-instance-requests',
                    '--spot-instance-request-ids',
                    output['SpotInstanceRequestId'],
                ])
                sys.exit(1)

            print()  # clear status message

            instance_id = output['InstanceId']
            # set the name, since spot instances don't let us do that in the creation request
            subprocess.check_call([
                'aws', 'ec2', 'create-tags', '--resources', instance_id,
                '--tags', 'Key=Name,Value="{}"'.format(name)
            ])
        else:
            args = [
                'aws',
                'ec2',
                'run-instances',
                '--instance-type',
                self.instance_type,
                '--key-name',
                self.identity,
                '--image-id',
                'ami-0b59bfac6be064b78',
                '--tag-specifications',
                'ResourceType="instance",Tags=[{{Key="Name",Value="{}"}}]'.
                format(name),
                '--security-group-ids',
                'sg-0780fe1760c00d96d',
                '--block-device-mappings',
                json.dumps(block_device_mappings),
                '--iam-instance-profile',
                json.dumps(iam_profile_struct),
            ]
            output = subprocess.check_output(args)
            parsed_output = json.loads(output)
            instance = parsed_output['Instances'][0]
            instance_id = instance['InstanceId']

        print('Started instance! Waiting for connection...')

        subprocess.check_call([
            'aws', 'ec2', 'wait', 'instance-running', '--instance-ids',
            instance_id
        ])

        instance = next(instance for instance in self.get_running_instances()
                        if instance['InstanceId'] == instance_id)
        ssh_address = 'ec2-user@{}'.format(instance['PublicDnsName'])

        # wait for SSH to actually become available
        while subprocess.call(
            [
                'ssh', '-oStrictHostKeyChecking=no', '-i', self.pem_key,
                ssh_address, 'exit'
            ],
                stdout=open(os.devnull, 'w'),
                stderr=open(os.devnull, 'w'),
        ):
            time.sleep(1)

        git_root = subprocess.check_output(
            ['git', 'rev-parse', '--show-toplevel'], cwd=_DIRNAME).strip()
        ls_files = subprocess.Popen(['git', 'ls-files'],
                                    cwd=git_root,
                                    stdout=subprocess.PIPE)
        tar = subprocess.Popen(['tar', 'Tcz', '-'],
                               cwd=git_root,
                               stdin=ls_files.stdout,
                               stdout=subprocess.PIPE)

        aws_credentials = json.loads(
            subprocess.check_output(['aws', 'ecr',
                                     'get-authorization-token']).strip())
        authorization_datum = aws_credentials['authorizationData'][0]
        aws_authorization = base64.b64decode(
            authorization_datum['authorizationToken'])
        aws_authorization_user = aws_authorization[:aws_authorization.index(':'
                                                                            )]
        aws_authorization_token = aws_authorization[aws_authorization.
                                                    index(':') + 1:]
        aws_endpoint = authorization_datum['proxyEndpoint']

        region = subprocess.check_output(['aws', 'configure', 'get',
                                          'region']).strip()

        mysql_credentials_dict = json.loads(
            subprocess.check_output([
                'aws', 'secretsmanager', 'get-secret-value', '--secret-id',
                'ithemal/mysql-{}'.format(self.db)
            ]).strip())
        mysql_credentials = json.loads(mysql_credentials_dict['SecretString'])
        mysql_user = mysql_credentials['username']
        mysql_password = mysql_credentials['password']
        mysql_host = mysql_credentials['host']
        mysql_port = mysql_credentials['port']

        initialization_command = 'mkdir ithemal; cd ithemal; cat | tar xz; aws/aws_utils/remote_setup.sh {}'.format(
            ' '.join(
                map(str, [
                    aws_authorization_user,
                    aws_authorization_token,
                    aws_endpoint,
                    mysql_user,
                    mysql_password,
                    mysql_host,
                    mysql_port,
                    region,
                ])))

        ssh = subprocess.Popen([
            'ssh', '-oStrictHostKeyChecking=no', '-i', self.pem_key,
            ssh_address, initialization_command
        ],
                               stdin=tar.stdout)
        ls_files.wait()
        tar.wait()
        ssh.wait()

        if self.queue_name:
            self.start_queue_on_instance(instance, ssh_address)

        if not self.no_connect:
            os.execlp(sys.executable, sys.executable,
                      os.path.join(_DIRNAME, 'connect_instance.py'),
                      self.identity, instance['InstanceId'])