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))))
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])
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'])