示例#1
0
def _snapshot_root_volume(aws_svc, instance, image_id):
    """ Snapshot the root volume of the given AMI.

    :except SnapshotError if the snapshot goes into an error state
    """
    log.info(
        'Stopping instance %s in order to create snapshot', instance.id)
    aws_svc.stop_instance(instance.id)
    wait_for_instance(aws_svc, instance.id, state='stopped')

    # Snapshot root volume.
    instance = aws_svc.get_instance(instance.id)
    root_dev = instance.root_device_name
    bdm = instance.block_device_mapping

    if root_dev not in bdm:
        # try stripping partition id
        root_dev = string.rstrip(root_dev, string.digits)
    root_vol = bdm[root_dev]
    vol = aws_svc.get_volume(root_vol.volume_id)
    aws_svc.create_tags(
        root_vol.volume_id,
        name=NAME_ORIGINAL_VOLUME % {'image_id': image_id}
    )

    snapshot = aws_svc.create_snapshot(
        vol.id,
        name=NAME_ORIGINAL_SNAPSHOT,
        description=DESCRIPTION_ORIGINAL_SNAPSHOT % {'image_id': image_id}
    )
    log.info(
        'Creating snapshot %s of root volume for instance %s',
        snapshot.id, instance.id
    )

    try:
        wait_for_snapshots(aws_svc, snapshot.id)

        # Now try to detach the root volume.
        log.info('Detaching root volume %s from %s',
                 root_vol.volume_id, instance.id)
        aws_svc.detach_volume(
            root_vol.volume_id,
            instance_id=instance.id,
            force=True
        )
        aws_service.wait_for_volume(aws_svc, root_vol.volume_id)
        # And now delete it
        log.info('Deleting root volume %s', root_vol.volume_id)
        aws_svc.delete_volume(root_vol.volume_id)
    except:
        clean_up(aws_svc, snapshot_ids=[snapshot.id])
        raise

    ret_values = (
        snapshot.id, root_dev, vol.size, vol.type, root_vol.iops)
    log.debug('Returning %s', str(ret_values))
    return ret_values
示例#2
0
    def test_wait_for_volume(self):
        aws_svc, encryptor_image, guest_image = build_aws_service()

        # Create a dummy volume.
        volume = Volume()
        volume.size = 8
        volume.id = new_id()
        volume.status = 'detaching'
        aws_svc.volumes[volume.id] = volume

        def transition_to_available(callback_volume):
            self.num_calls += 1
            self.assertEqual(volume, callback_volume)
            self.assertFalse(self.num_calls > 5)

            if self.num_calls == 5:
                volume.status = 'available'

        aws_svc.get_volume_callback = transition_to_available
        result = aws_service.wait_for_volume(aws_svc, volume.id)
        self.assertEqual(volume, result)
示例#3
0
def register_ami(aws_svc, encryptor_instance, encryptor_image, name,
                 description, mv_bdm=None, legacy=False, guest_instance=None,
                 mv_root_id=None):
    if not mv_bdm:
        mv_bdm = BlockDeviceMapping()
    # Register the new AMI.
    if legacy:
        # The encryptor instance may modify its volume attachments while
        # running, so we update the encryptor instance's local attributes
        # before reading them.
        encryptor_instance = aws_svc.get_instance(encryptor_instance.id)
        guest_id = encryptor_instance.id
        # Explicitly detach/delete all but root drive
        bdm = encryptor_instance.block_device_mapping
        for d in ['/dev/sda2', '/dev/sda3', '/dev/sda4',
                  '/dev/sda5', '/dev/sdf', '/dev/sdg']:
            if not bdm.get(d):
                continue
            aws_svc.detach_volume(
                bdm[d].volume_id,
                instance_id=encryptor_instance.id,
                force=True
            )
            aws_service.wait_for_volume(aws_svc, bdm[d].volume_id)
            aws_svc.delete_volume(bdm[d].volume_id)
    else:
        guest_id = guest_instance.id
        root_device_name = guest_instance.root_device_name
        # Explicitly attach new mv root to guest instance
        log.info('Attaching %s to %s', mv_root_id, guest_instance.id)
        aws_svc.attach_volume(
            mv_root_id,
            guest_instance.id,
            root_device_name,
        )
        instance = wait_for_volume_attached(
            aws_svc, guest_instance.id, root_device_name)
        bdm = instance.block_device_mapping
        mv_bdm[root_device_name] = bdm[root_device_name]
        mv_bdm[root_device_name].delete_on_termination = True

    # Legacy:
    #   Create AMI from (stopped) MV instance
    # Non-legacy:
    #   Create AMI from original (stopped) guest instance. This
    #   preserves any billing information found in
    #   the identity document (i.e. billingProduct)
    ami = aws_svc.create_image(
        guest_id,
        name,
        description=description,
        no_reboot=True,
        block_device_mapping=mv_bdm
    )

    if not legacy:
        log.info("Deleting volume %s" % (mv_root_id,))
        aws_svc.detach_volume(
            mv_root_id,
            instance_id=guest_instance.id,
            force=True
        )
        aws_service.wait_for_volume(aws_svc, mv_root_id)
        aws_svc.delete_volume(mv_root_id)

    log.info('Registered AMI %s based on the snapshots.', ami)
    wait_for_image(aws_svc, ami)
    image = aws_svc.get_image(ami, retry=True)
    if encryptor_image.virtualization_type == 'paravirtual':
        name = NAME_METAVISOR_GRUB_SNAPSHOT
    else:
        name = NAME_METAVISOR_ROOT_SNAPSHOT
    snap = image.block_device_mapping[image.root_device_name]
    aws_svc.create_tags(
        snap.snapshot_id,
        name=name,
        description=description
    )
    aws_svc.create_tags(ami)

    ami_info = {}
    ami_info['volume_device_map'] = []
    result_image = aws_svc.get_image(ami, retry=True)
    for attach_point, bdt in result_image.block_device_mapping.iteritems():
        if bdt.snapshot_id:
            bdt_snapshot = aws_svc.get_snapshot(bdt.snapshot_id)
            device_details = {
                'attach_point': attach_point,
                'description': bdt_snapshot.tags.get('Name', ''),
                'size': bdt_snapshot.volume_size
            }
            ami_info['volume_device_map'].append(device_details)

    ami_info['ami'] = ami
    ami_info['name'] = name
    return ami_info
示例#4
0
def snapshot_encrypted_instance(aws_svc, enc_svc_cls, encryptor_instance,
                       encryptor_image, image_id=None, vol_type='', iops=None,
                       legacy=False, save_encryptor_logs=True,
                       status_port=encryptor_service.ENCRYPTOR_STATUS_PORT):
    # First wait for encryption to complete
    host_ips = []
    if encryptor_instance.ip_address:
        host_ips.append(encryptor_instance.ip_address)
    if encryptor_instance.private_ip_address:
        host_ips.append(encryptor_instance.private_ip_address)
        log.info('Adding %s to NO_PROXY environment variable' %
                 encryptor_instance.private_ip_address)
        if os.environ.get('NO_PROXY'):
            os.environ['NO_PROXY'] += "," + \
                encryptor_instance.private_ip_address
        else:
            os.environ['NO_PROXY'] = encryptor_instance.private_ip_address

    enc_svc = enc_svc_cls(host_ips, port=status_port)
    try:
        log.info('Waiting for encryption service on %s (port %s on %s)',
             encryptor_instance.id, enc_svc.port, ', '.join(host_ips))
        encryptor_service.wait_for_encryptor_up(enc_svc, Deadline(600))
        log.info('Creating encrypted root drive.')
        encryptor_service.wait_for_encryption(enc_svc)
    except (BracketError, encryptor_service.EncryptionError) as e:
        # Stop the encryptor instance, to make the console log available.
        stop_and_wait(aws_svc, encryptor_instance.id)

        log_exception_console(aws_svc, e, encryptor_instance.id)
        if save_encryptor_logs:
            log.info('Saving logs from encryptor instance in snapshot')
            log_snapshot = snapshot_log_volume(aws_svc, encryptor_instance.id)
            log.info('Encryptor logs saved in snapshot %(snapshot_id)s. '
                     'Run `brkt share-logs --region %(region)s '
                     '--snapshot-id %(snapshot_id)s` '
                     'to share this snapshot with Bracket support' %
                     {'snapshot_id': log_snapshot.id,
                      'region': aws_svc.region})
        raise

    log.info('Encrypted root drive is ready.')
    # The encryptor instance may modify its volume attachments while running,
    # so we update the encryptor instance's local attributes before reading
    # them.
    encryptor_instance = aws_svc.get_instance(encryptor_instance.id)
    encryptor_bdm = encryptor_instance.block_device_mapping

    # Stop the encryptor instance.
    log.info('Stopping encryptor instance %s', encryptor_instance.id)
    aws_svc.stop_instance(encryptor_instance.id)
    wait_for_instance(aws_svc, encryptor_instance.id, state='stopped')

    description = DESCRIPTION_SNAPSHOT % {'image_id': image_id}

    # Set up new Block Device Mappings
    log.debug('Creating block device mapping')
    new_bdm = BlockDeviceMapping()
    if not vol_type or vol_type == '':
        vol_type = 'gp2'

    # Snapshot volumes.
    if encryptor_image.virtualization_type == 'paravirtual':
        snap_guest = aws_svc.create_snapshot(
            encryptor_bdm['/dev/sda5'].volume_id,
            name=NAME_ENCRYPTED_ROOT_SNAPSHOT,
            description=description
        )
        snap_bsd = aws_svc.create_snapshot(
            encryptor_bdm['/dev/sda2'].volume_id,
            name=NAME_METAVISOR_ROOT_SNAPSHOT,
            description=description
        )
        snap_log = aws_svc.create_snapshot(
            encryptor_bdm['/dev/sda3'].volume_id,
            name=NAME_METAVISOR_LOG_SNAPSHOT,
            description=description
        )
        log.info(
            'Creating snapshots for the new encrypted AMI: %s, %s, %s',
            snap_guest.id, snap_bsd.id, snap_log.id)

        wait_for_snapshots(
            aws_svc, snap_guest.id, snap_bsd.id, snap_log.id)

        if vol_type is None:
            vol_type = "gp2"
        dev_guest_root = EBSBlockDeviceType(volume_type=vol_type,
                                    snapshot_id=snap_guest.id,
                                    iops=iops,
                                    delete_on_termination=True)
        mv_root_id = encryptor_bdm['/dev/sda1'].volume_id

        dev_mv_root = EBSBlockDeviceType(volume_type='gp2',
                                  snapshot_id=snap_bsd.id,
                                  delete_on_termination=True)
        dev_log = EBSBlockDeviceType(volume_type='gp2',
                                 snapshot_id=snap_log.id,
                                 delete_on_termination=True)
        new_bdm['/dev/sda2'] = dev_mv_root
        new_bdm['/dev/sda3'] = dev_log
        new_bdm['/dev/sda5'] = dev_guest_root
    else:
        # HVM instance type
        snap_guest = aws_svc.create_snapshot(
            encryptor_bdm['/dev/sdg'].volume_id,
            name=NAME_ENCRYPTED_ROOT_SNAPSHOT,
            description=description
        )
        log.info(
            'Creating snapshots for the new encrypted AMI: %s' % (
                    snap_guest.id)
        )
        wait_for_snapshots(aws_svc, snap_guest.id)
        dev_guest_root = EBSBlockDeviceType(volume_type=vol_type,
                                    snapshot_id=snap_guest.id,
                                    iops=iops,
                                    delete_on_termination=True)
        mv_root_id = encryptor_bdm['/dev/sda1'].volume_id
        new_bdm['/dev/sdf'] = dev_guest_root

    if not legacy:
        log.info("Detaching new guest root %s" % (mv_root_id,))
        aws_svc.detach_volume(
            mv_root_id,
            instance_id=encryptor_instance.id,
            force=True
        )
        aws_service.wait_for_volume(aws_svc, mv_root_id)
        aws_svc.create_tags(
            mv_root_id, name=NAME_METAVISOR_ROOT_VOLUME)

    if image_id:
        log.debug('Getting image %s', image_id)
        guest_image = aws_svc.get_image(image_id)
        if guest_image is None:
            raise BracketError("Can't find image %s" % image_id)

        # Propagate any ephemeral drive mappings to the soloized image
        guest_bdm = guest_image.block_device_mapping
        for key in guest_bdm.keys():
            guest_vol = guest_bdm[key]
            if guest_vol.ephemeral_name:
                log.info('Propagating block device mapping for %s at %s' %
                         (guest_vol.ephemeral_name, key))
                new_bdm[key] = guest_vol

    return mv_root_id, new_bdm