Example #1
0
def attach_volume(volume_id, device_path):
    set_region()
    ec2 = boto3.client("ec2")
    instance_id = InstanceInfo().instance_id()
    ec2.attach_volume(VolumeId=volume_id,
                      InstanceId=instance_id,
                      Device=device_path)
    wait_for_volume_status(volume_id, "attached")
Example #2
0
def create_empty_volume(size_gb, availability_zone=None):
    set_region()
    ec2 = boto3.client("ec2")
    args = {'Size': size_gb, 'VolumeType': 'gp2'}
    if not availability_zone:
        availability_zone = InstanceInfo().availability_zone()
    args['AvailabilityZone'] = availability_zone
    resp = ec2.create_volume(**args)
    wait_for_volume_status(resp['VolumeId'], "available")
    return resp['VolumeId']
Example #3
0
def delete_on_termination(device_path):
    set_region()
    ec2 = boto3.client("ec2")
    instance_id = InstanceInfo().instance_id()
    ec2.modify_instance_attribute(InstanceId=instance_id,
                                  BlockDeviceMappings=[{
                                      "DeviceName": device_path,
                                      "Ebs": {
                                          "DeleteOnTermination": True
                                      }
                                  }])
Example #4
0
def wait_for_volume_status(volume_id, status, timeout_sec=300):
    set_region()
    start = time.time()
    ec2 = boto3.client("ec2")
    volume = None
    while not match_volume_state(volume, status):
        time.sleep(2)
        if time.time() - start > timeout_sec:
            raise Exception("Failed waiting for status '" + status + "' for " +
                            volume_id + " (timeout: " + str(timeout_sec) + ")")
        resp = ec2.describe_volumes(VolumeIds=[volume_id])
        if "Volumes" in resp:
            volume = resp['Volumes'][0]
Example #5
0
def wait_for_snapshot_complete(snapshot_id, timeout_sec=900):
    set_region()
    start = time.time()
    ec2 = boto3.client("ec2")
    snapshot = None
    while not is_snapshot_complete(snapshot):
        time.sleep(2)
        if time.time() - start > timeout_sec:
            raise Exception("Failed waiting for status 'completed' for " +
                            snapshot_id + " (timeout: " + str(timeout_sec) +
                            ")")
        resp = ec2.describe_snapshots(SnapshotIds=[snapshot_id])
        if "Snapshots" in resp:
            snapshot = resp['Snapshots'][0]
Example #6
0
def get_latest_snapshot(tag_name, tag_value):
    """Get the latest snapshot with a given tag
    """
    set_region()
    ec2res = boto3.resource("ec2")
    snapshots = sorted(ec2res.snapshots.filter(Filters=[{
        'Name': 'tag:' + tag_name,
        'Values': [tag_value]
    }]),
                       key=lambda k: k.start_time,
                       reverse=True)
    if snapshots:
        return snapshots[0]
    else:
        return None
Example #7
0
def attached_devices(volume_id=None):
    set_region()
    ec2 = boto3.client("ec2")
    volumes = ec2.describe_volumes(
        Filters=[{
            "Name": "attachment.instance-id",
            "Values": [InstanceInfo().instance_id()]
        }, {
            "Name": "attachment.status",
            "Values": ["attached"]
        }])
    ret = []
    for volume in volumes['Volumes']:
        for attachment in volume['Attachments']:
            if (not volume_id) or volume['VolumeId'] == volume_id:
                ret.append(attachment['Device'])
    return ret
Example #8
0
def create_snapshot(tag_key,
                    tag_value,
                    mount_path,
                    wait=False,
                    tags={},
                    copytags=[]):
    set_region()
    create_tags = _create_tag_array(tag_key, tag_value, tags, copytags)
    device = device_from_mount_path(mount_path)
    with open(os.devnull, 'w') as devnull:
        subprocess.call(["sync", mount_path[0]],
                        stdout=devnull,
                        stderr=devnull)
    ec2 = boto3.client("ec2")
    volume_id = None
    if "/nvme" in device:
        proc = Popen(["nvme", "id-ctrl", device], stdout=PIPE, stderr=PIPE)
        out = proc.communicate()[0]
        for nvme_line in out.split("\n"):
            if nvme_line.startswith("sn"):
                volume_id = nvme_line.split()[2]
                if "vol-" not in volume_id:
                    volume_id = volume_id.replace("vol", "vol-")
                break
    else:
        instance_id = InstanceInfo().instance_id()
        volume = ec2.describe_volumes(Filters=[{
            "Name": "attachment.instance-id",
            "Values": [instance_id]
        }])
        for volume in volume['Volumes']:
            if volume['Attachments'][0]['Device'] == device:
                volume_id = volume['VolumeId']
    if volume_id:
        snap = ec2.create_snapshot(VolumeId=volume_id)
        ec2.create_tags(Resources=[snap['SnapshotId']], Tags=create_tags)
    else:
        raise Exception("Could not find volume for " + mount_path + "(" +
                        device + ")")
    if wait:
        wait_for_snapshot_complete(snap['SnapshotId'])
    return snap['SnapshotId']
Example #9
0
def clean_snapshots(days, tags):
    set_region()
    ec2 = boto3.client("ec2")
    account_id = resolve_account()
    newest_timestamp = datetime.utcnow() - timedelta(days=days)
    newest_timestamp = newest_timestamp.replace(tzinfo=None)
    paginator = ec2.get_paginator('describe_snapshots')
    for page in paginator.paginate(OwnerIds=[account_id],
                                   Filters=[{
                                       'Name': 'tag-value',
                                       'Values': tags
                                   }],
                                   PaginationConfig={'PageSize': 1000}):
        for snapshot in page['Snapshots']:
            tags = {}
            for tag in snapshot['Tags']:
                tags[tag['Key']] = tag['Value']
            print_time = snapshot['StartTime'].replace(
                tzinfo=tz.tzlocal()).timetuple()
            compare_time = snapshot['StartTime'].replace(tzinfo=None)
            if compare_time < newest_timestamp:
                print(
                    colored("Deleting " + snapshot['SnapshotId'], "yellow") +
                    " || " +
                    time.strftime("%a, %d %b %Y %H:%M:%S", print_time) +
                    " || " + json.dumps(tags))
                try:
                    ec2.delete_snapshot(SnapshotId=snapshot['SnapshotId'])
                    time.sleep(0.2)
                except ClientError as err:
                    print(
                        colored(
                            "Delete failed: " +
                            err.response['Error']['Message'], "red"))
            else:
                print(
                    colored("Skipping " + snapshot['SnapshotId'], "cyan") +
                    " || " +
                    time.strftime("%a, %d %b %Y %H:%M:%S", print_time) +
                    " || " + json.dumps(tags))
Example #10
0
def detach_volume(mount_path):
    set_region()
    device = device_from_mount_path(mount_path)
    if "/nvme" in device:
        proc = Popen(["nvme", "id-ctrl", device], stdout=PIPE, stderr=PIPE)
        out = proc.communicate()[0]
        for nvme_line in out.split("\n"):
            if nvme_line.startswith("sn"):
                volume_id = nvme_line.split()[2]
                if "vol-" not in volume_id:
                    volume_id = volume_id.replace("vol", "vol-")
                break
    else:
        ec2 = boto3.client("ec2")
        instance_id = InstanceInfo().instance_id()
        volume = ec2.describe_volumes(Filters=[{
            "Name": "attachment.device",
            "Values": [device]
        }, {
            "Name": "attachment.instance-id",
            "Values": [instance_id]
        }])
        volume_id = volume['Volumes'][0]['VolumeId']
    ec2.detach_volume(VolumeId=volume_id, InstanceId=instance_id)
Example #11
0
def volume_from_snapshot(tag_key,
                         tag_value,
                         mount_path,
                         availability_zone=None,
                         size_gb=None,
                         del_on_termination=True,
                         tags=[],
                         copytags=[]):
    set_region()
    snapshot = get_latest_snapshot(tag_key, tag_value)
    if snapshot:
        print("Found snapshot " + snapshot.id)
        volume = create_volume(snapshot.id,
                               availability_zone=availability_zone,
                               size_gb=size_gb)
    else:
        if not size_gb:
            size_gb = 32
        print("Creating empty volyme of size " + str(size_gb))
        volume = create_empty_volume(size_gb,
                                     availability_zone=availability_zone)
    tag_volume(volume, tag_key, tag_value, tags, copytags)
    device = first_free_device()
    print("Attaching volume " + volume + " to " + device)
    attach_volume(volume, device)
    local_device = map_local_device(volume, device)
    if del_on_termination:
        delete_on_termination(device)
    if not snapshot:
        # empty device
        if sys.platform.startswith('win'):
            # Windows format
            drive_letter = mount_path[0].upper()
            disk = wmic_disk_with_target_id(letter_to_target_id(device[-1:]))
            if not disk:
                disk = wmic_disk_with_volume_id(volume)
            disk_number = str(disk['Index'])
            subprocess.check_call([
                "powershell.exe", "Get-Disk", disk_number, "|", "Set-Disk",
                "-IsOffline", "$False"
            ])
            subprocess.check_call([
                "powershell.exe", "Initialize-Disk", disk_number,
                "-PartitionStyle", "MBR"
            ])
            subprocess.check_call([
                "powershell.exe", "New-Partition", "-DiskNumber", disk_number,
                "-UseMaximumSize", "-DriveLetter", drive_letter
            ])
            print("Formatting " + device + "(" + drive_letter + ":)")
            subprocess.check_call([
                "powershell.exe", "Format-Volume", "-DriveLetter",
                drive_letter, "-FileSystem", "NTFS", "-Force",
                "-Confirm:$False"
            ])
        else:
            # linux format
            print("Formatting " + local_device)
            subprocess.check_call(["mkfs.ext4", local_device])
    else:
        if sys.platform.startswith('win'):
            target_id = letter_to_target_id(device[-1:])
            drive_letter = mount_path[0].upper()
            disk = wmic_disk_with_target_id(target_id)
            if not disk:
                disk = wmic_disk_with_volume_id(volume)
            disk_number = str(disk['Index'])
            with open(os.devnull, 'w') as devnull:
                subprocess.call([
                    "powershell.exe", "Initialize-Disk", disk_number,
                    "-PartitionStyle", "MBR"
                ],
                                stderr=devnull,
                                stdout=devnull)
            subprocess.check_call([
                "powershell.exe", "Get-Disk", disk_number, "|", "Set-Disk",
                "-IsOffline", "$False"
            ])
            with open(os.devnull, 'w') as devnull:
                subprocess.check_call([
                    "powershell.exe", "Get-Partition", "-DiskNumber",
                    disk_number, "-PartitionNumber", "1"
                    "|", "Set-Partition", "-NewDriveLetter", drive_letter
                ],
                                      stdout=devnull,
                                      stderr=devnull)
            # resize win partition if necessary
            if size_gb and not size_gb == snapshot.volume_size:
                proc = subprocess.Popen([
                    "powershell.exe", "$((Get-PartitionSupportedSize -Dri" +
                    "veLetter " + drive_letter + ").SizeMax)"
                ],
                                        stdout=subprocess.PIPE)
                max_size = proc.communicate()[0]
                subprocess.check_call([
                    "powershell.exe", "Resize-Partition", "-DriveLetter",
                    drive_letter, "-Size", max_size
                ])
        else:
            if size_gb and not size_gb == snapshot.volume_size:
                print("Resizing " + local_device + " from " +
                      str(snapshot.volume_size) + "GB to " + str(size_gb))
                try:
                    subprocess.check_call(["e2fsck", "-f", "-p", local_device])
                except CalledProcessError as e:
                    print("Filesystem check returned " + str(e.returncode))
                    if e.returncode > 1:
                        raise Exception(
                            "Uncorrected filesystem errors - please fix manually"
                        )
                subprocess.check_call(["resize2fs", local_device])
    if not sys.platform.startswith('win'):
        if not os.path.isdir(mount_path):
            os.makedirs(mount_path)
        subprocess.check_call(["mount", local_device, mount_path])