Example #1
0
def create_efs(config):
    """Create and configure EFS

    Args:
        config (aws_ml_helper.config.Config): Configuration
    """
    efs = boto.client('efs', config)

    print('Creating EFS')
    token = f'{config.vpc_name}-efs'
    response = efs.create_file_system(CreationToken=token)
    efs_id = response['FileSystemId']
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    efs.create_tags(FileSystemId=efs_id,
                    Tags=[{
                        'Key': 'Name',
                        'Value': token
                    }])
    # Wait until it's in the available state
    while True:
        response = efs.describe_file_systems(FileSystemId=efs_id)
        if response['FileSystems'][0]['LifeCycleState'] == 'available':
            break
    efs.create_mount_target(FileSystemId=efs_id,
                            SubnetId=config.subnet_id,
                            SecurityGroups=[config.efs_security_group_id])
    config.efs_id = efs_id
    config.save()
Example #2
0
def generate_key_pair(config, path):
    """Generate key pair and save it to the keys subdirectory

    Args:
        config (aws_ml_helper.config.Config): Configuration
        path (str): Path to the directory where the access key should be saved
    """
    ec2 = boto.client('ec2', config)

    print('Generating key-pair')
    full_name = f'access-key-{config.vpc_name}'
    response = ec2.create_key_pair(KeyName=full_name)
    if not os.path.isdir(path):
        os.makedirs(path)
    key_path = os.path.join(path, f'{full_name}.pem')
    with io.open(key_path, 'w') as f:
        f.write(response['KeyMaterial'])
    os.chmod(key_path, 0o400)
    config.access_key = key_path
    config.save()
Example #3
0
def spot_price(config, days=7, instance_type=None, value='all'):
    """Show information about spot instance prices in the last n days

    Args:
        config (aws_ml_helper.config.Config): Configuration
        days (int): Show information for the last n days
        instance_type (str): Select instance type. If not provided function
            will use the value in the configuration.
        value (str): Pick which value to show. Default all.
    """
    end_time = datetime.now()
    start_time = end_time - timedelta(days=days)

    ec2 = boto.client('ec2', config)

    r = ec2.describe_spot_price_history(
        StartTime=start_time,
        EndTime=end_time,
        InstanceTypes=[instance_type or config.instance_type],
    )

    prices = [float(p['SpotPrice']) for p in r['SpotPriceHistory']]

    if value == 'all':
        print(tabulate([
            ['Min', min(prices)],
            ['Max', max(prices)],
            ['Mean', sum(prices) / len(prices)],
            ['Median', median(prices)]
        ], tablefmt=config.table_format, floatfmt='.3f'))
    elif value == 'min':
        print(min(prices))
    elif value == 'max':
        print(max(prices))
    elif value == 'mean':
        print(sum(prices) / len(prices))
    elif value == 'median':
        print(median(prices))
Example #4
0
def start_spot_instance(config, name, bid_price, ami_id=None,
                        instance_type=None, snapshot_name=None,
                        mount_point=None):
    """Starts a spot instance.

    Args:
        config (aws_ml_helper.config.Config): Configuration
        name (str): Spot instance name
        bid_price (int): Bidding price for the instance
        ami_id (str): AMI id to use. If not provided, value form the
            configuration will be used
        instance_type (str): Instance type to use. If not provided, value from
            the configuration will be used.
        snapshot_name (str): Name of the snapshot from which the attached
            volume will be created
        mount_point (str): Path where the volume should be mounted
    """
    ec2 = boto.client('ec2', config)
    response = ec2.request_spot_instances(
        InstanceCount=1,
        Type='one-time',
        LaunchSpecification={
            'ImageId': ami_id or config.ami_id,
            'InstanceType': instance_type or config.instance_type,
            'KeyName': f'access-key-{config.vpc_name}',
            'EbsOptimized': True,
            'Placement': {
                'AvailabilityZone': config.availability_zone,
            },
            # 'BlockDeviceMappings': [
            #     {
            #         'DeviceName': '/dev/sda1',
            #         'Ebs': {
            #             'DeleteOnTermination': False,
            #             'VolumeSize': 128,
            #             'VolumeType': 'gp2'
            #         },
            #     },
            # ],

            'Monitoring': {'Enabled': True},
            'NetworkInterfaces': [
                {
                    'DeviceIndex': 0,
                    'AssociatePublicIpAddress': True,
                    'Groups': [config.ec2_security_group_id],
                    'SubnetId': config.subnet_id
                },
            ],
        },
        SpotPrice=f'{bid_price}',
        InstanceInterruptionBehavior='terminate'
    )
    click.echo('Spot instance request created.')
    request_id = response['SpotInstanceRequests'][0]['SpotInstanceRequestId']
    waiter = ec2.get_waiter('spot_instance_request_fulfilled')
    waiter.wait(SpotInstanceRequestIds=[request_id])
    response = ec2.describe_spot_instance_requests(
        SpotInstanceRequestIds=[request_id]
    )
    instance_id = response['SpotInstanceRequests'][0]['InstanceId']
    waiter = ec2.get_waiter('instance_running')
    waiter.wait(InstanceIds=[instance_id])
    click.echo(f'Spot Instance ID: {instance_id}')
    ec2.create_tags(Resources=[instance_id],
                    Tags=[{'Key': 'Name', 'Value': name}])
    response = ec2.describe_instances(
        InstanceIds=[instance_id],
        Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]
    )
    instance_ip = (
        response['Reservations'][0]['Instances'][0]['PublicIpAddress']
    )
    click.echo(f'Spot Instance IP: {instance_ip}')

    mount_point = mount_point or config.mount_point
    if mount_point in ('', None):
        # Mount point is not defined we don't know where to mount the volume
        return

    ec2 = boto.resource('ec2', config)
    # Search for a volume with the same name
    volume = get_volume(config, name)
    if volume is not None:
        click.echo(f'Volume "{name}" found - attaching')
        # Attach the volume
        volume_attach(config, name, name, device='xvdh')
        run(config, name, f'sudo mount /dev/xvdh {mount_point}')
    else:
        if snapshot_name is not None:
            snapshot = get_snapshot(config, snapshot_name)
        elif config.snapshot_id not in ('', None):
            snapshot = ec2.Snapshot(config.snapshot_id)
            snapshot_name = name_from_tags(snapshot.tags)
        else:
            # Snapshot not found return
            return
        click.echo(f'Creating volume "{name}" from snapshot "{snapshot_name}"')
        volume_create(config, name, size=snapshot.volume_size,
                      snapshot_name=snapshot_name, wait=True)
        click.echo(f'Attaching volume "{name}"')
        volume_attach(config, name, name, device='xvdh')
        run(config, name, f'sudo mount /dev/xvdh {mount_point}')
Example #5
0
def create_vpc(config,
               name,
               network_range='10.0.0.0/16',
               allowed_ip='0.0.0.0/32',
               availability_zone='us-east-1a'):
    """Creates a VPC

    Args:
        config (aws_ml_helper.config.Config): Configuration object
        name (str): VPC name
        network_range (str): The IPv4 network range for the VPC, in CIDR
            notation. For example, 10.0.0.0/16
        allowed_ip (str): Public IP address from which the VPC instances will
            be accessible in CIDR notation.
        availability_zone: VPC availability zone
    """

    ec2 = boto.client('ec2', config)

    print('Create VPC')
    response = ec2.create_vpc(CidrBlock=network_range)
    vpc_id = response['Vpc']['VpcId']
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    ec2.create_tags(Resources=[vpc_id], Tags=[{'Key': 'Name', 'Value': name}])
    ec2.modify_vpc_attribute(VpcId=vpc_id, EnableDnsHostnames={'Value': True})
    ec2.modify_vpc_attribute(VpcId=vpc_id, EnableDnsSupport={'Value': True})

    print('Create the gateway')
    response = ec2.create_internet_gateway()
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    gateway_id = response['InternetGateway']['InternetGatewayId']
    ec2.create_tags(Resources=[gateway_id],
                    Tags=[{
                        'Key': 'Name',
                        'Value': f'{name}-gateway'
                    }])
    ec2.attach_internet_gateway(VpcId=vpc_id, InternetGatewayId=gateway_id)

    print('Create subnet')
    response = ec2.create_subnet(VpcId=vpc_id,
                                 CidrBlock=network_range,
                                 AvailabilityZone=availability_zone)
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    subnet_id = response['Subnet']['SubnetId']
    ec2.create_tags(Resources=[subnet_id],
                    Tags=[{
                        'Key': 'Name',
                        'Value': f'{name}-subnet'
                    }])

    print('Create routing table')
    response = ec2.create_route_table(VpcId=vpc_id)
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    route_table_id = response['RouteTable']['RouteTableId']
    ec2.create_tags(Resources=[route_table_id],
                    Tags=[{
                        'Key': 'Name',
                        'Value': f'{name}-route-table'
                    }])
    ec2.associate_route_table(RouteTableId=route_table_id, SubnetId=subnet_id)
    ec2.create_route(RouteTableId=route_table_id,
                     GatewayId=gateway_id,
                     DestinationCidrBlock='0.0.0.0/0')

    print('Create security group for instances')
    response = ec2.create_security_group(
        VpcId=vpc_id,
        GroupName=f'{name}-ec2-security-group',
        Description=f'Security Group for {name} VPC instances')
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    ec2_security_group_id = response['GroupId']
    # Open port for ssh
    ec2.authorize_security_group_ingress(GroupId=ec2_security_group_id,
                                         IpProtocol='tcp',
                                         FromPort=22,
                                         ToPort=22,
                                         CidrIp=allowed_ip)
    # Open port for tensorboard
    ec2.authorize_security_group_ingress(GroupId=ec2_security_group_id,
                                         IpProtocol='tcp',
                                         FromPort=6006,
                                         ToPort=6006,
                                         CidrIp=allowed_ip)
    # Open port for jupyter notebook
    ec2.authorize_security_group_ingress(GroupId=ec2_security_group_id,
                                         IpProtocol='tcp',
                                         FromPort=8888,
                                         ToPort=8888,
                                         CidrIp=allowed_ip)

    print('Create security group for EFS')
    response = ec2.create_security_group(
        VpcId=vpc_id,
        GroupName=f'{name}-efs-security-group',
        Description=f'Security Group for {name} VPC EFS')
    # Sleep for a second because the the object is created asynchronously. It's
    # not created when the response comes back from the server.
    time.sleep(1)
    efs_security_group_id = response['GroupId']
    ec2.authorize_security_group_ingress(GroupId=efs_security_group_id,
                                         IpPermissions=[
                                             {
                                                 'FromPort':
                                                 2049,
                                                 'IpProtocol':
                                                 'tcp',
                                                 'ToPort':
                                                 2049,
                                                 'UserIdGroupPairs': [{
                                                     'GroupId':
                                                     ec2_security_group_id
                                                 }]
                                             },
                                         ])

    config.vpc_id = vpc_id
    config.vpc_name = name
    config.subnet_id = subnet_id
    config.ec2_security_group_id = ec2_security_group_id
    config.efs_security_group_id = efs_security_group_id
    config.save()

    return {
        'vpc_id': vpc_id,
        'vpc_name': name,
        'subnet': subnet_id,
        'ec2_security_group': ec2_security_group_id,
        'efs_security_group': efs_security_group_id
    }