Exemple #1
0
    def create_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        image_id = resource_node.value.id
        bank_section = checkpoint.get_resource_bank_section(image_id)

        resource_definition = {"resource_id": image_id}
        glance_client = self._glance_client(cntxt)

        LOG.info(_LI("creating image backup, image_id: %s."), image_id)
        try:
            bank_section.create_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)
            image_info = glance_client.images.get(image_id)
            image_metadata = {
                "disk_format": image_info.disk_format,
                "container_format": image_info.container_format
            }
            resource_definition["image_metadata"] = image_metadata
            resource_definition["backup_id"] = image_id

            bank_section.create_object("metadata", resource_definition)
        except Exception as err:
            LOG.error(_LE("create image backup failed, image_id: %s."),
                      image_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=image_id,
                resource_type=constants.IMAGE_RESOURCE_TYPE)

        self._add_to_threadpool(self._create_backup, glance_client,
                                bank_section, image_id)
    def on_main(self, checkpoint, resource, context, parameters, **kwargs):
        image_id = resource.id
        bank_section = checkpoint.get_resource_bank_section(image_id)

        resource_definition = {"resource_id": image_id}
        glance_client = ClientFactory.create_client('glance', context)
        LOG.info("Creating image backup, image_id: %s.", image_id)
        try:
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)
            image_info = glance_client.images.get(image_id)
            if image_info.status != "active":
                is_success = status_poll(partial(get_image_status,
                                                 glance_client, image_info.id),
                                         interval=self._interval,
                                         success_statuses={'active'},
                                         ignore_statuses={'queued', 'saving'},
                                         failure_statuses={
                                             'killed', 'deleted',
                                             'pending_delete', 'deactivated',
                                             'NotFound'
                                         })
                if is_success is not True:
                    LOG.error("The status of image (id: %s) is invalid.",
                              image_id)
                    raise exception.CreateBackupFailed(
                        reason="The status of image is invalid.",
                        resource_id=image_id,
                        resource_type=constants.IMAGE_RESOURCE_TYPE)

            image_metadata = {
                "disk_format": image_info.disk_format,
                "container_format": image_info.container_format,
                "checksum": image_info.checksum
            }
            resource_definition["image_metadata"] = image_metadata

            bank_section.update_object("metadata", resource_definition)
        except Exception as err:
            LOG.error("Create image backup failed, image_id: %s.", image_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=image_id,
                resource_type=constants.IMAGE_RESOURCE_TYPE)
        self._create_backup(glance_client, bank_section, image_id)
    def _create_backup(self, glance_client, bank_section, image_id):
        try:
            image_response = glance_client.images.data(image_id,
                                                       do_checksum=True)
            bank_chunk_num = int(self._data_block_size_bytes / 65536)
            LOG.debug("Creating image backup, bank_chunk_num: %s.",
                      bank_chunk_num)

            # backup the data of image
            image_chunks_num = 0
            chunks_num = 1
            image_response_data = BytesIO()
            for chunk in image_response:
                image_response_data.write(chunk)
                image_chunks_num += 1
                if image_chunks_num == bank_chunk_num:
                    image_chunks_num = 0
                    image_response_data.seek(0, os.SEEK_SET)
                    data = image_response_data.read(
                        self._data_block_size_bytes)
                    bank_section.update_object("data_" + str(chunks_num), data)
                    image_response_data.truncate(0)
                    image_response_data.seek(0, os.SEEK_SET)
                    chunks_num += 1

            image_response_data.seek(0, os.SEEK_SET)
            data = image_response_data.read()
            if data != '':
                bank_section.update_object("data_" + str(chunks_num), data)
            else:
                chunks_num -= 1

            # Save the chunks_num to metadata
            resource_definition = bank_section.get_object("metadata")
            if resource_definition is not None:
                resource_definition["chunks_num"] = chunks_num
            bank_section.update_object("metadata", resource_definition)

            # Update resource_definition backup_status
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_AVAILABLE)
            LOG.info(
                'Protecting image (id: %s) to bank completed '
                'successfully', image_id)
        except Exception as err:
            # update resource_definition backup_status
            LOG.exception('Protecting image (id: %s) to bank failed.',
                          image_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=image_id,
                resource_type=constants.IMAGE_RESOURCE_TYPE)
Exemple #4
0
    def _create_backup(self, glance_client, bank_section, image_id):
        try:
            image_info = glance_client.images.get(image_id)

            retry_attempts = CONF.retry_attempts
            while image_info.status != "active" and retry_attempts != 0:
                sleep(60)
                image_info = glance_client.images.get(image_id)
                retry_attempts -= 1

            if retry_attempts == 0:
                raise Exception

            image_response = glance_client.images.data(image_id)
            image_response_data = BytesIO()
            for chunk in image_response:
                image_response_data.write(chunk)
            image_response_data.seek(0, os.SEEK_SET)

            chunks = 0
            while True:
                data = image_response_data.read(self.data_block_size_bytes)
                if data == '':
                    break
                bank_section.create_object("data_" + str(chunks), data)
                chunks += 1

            # update resource_definition backup_status
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_AVAILABLE)
            LOG.info(_LI("finish backup image, image_id: %s."), image_id)
        except Exception as err:
            # update resource_definition backup_status
            LOG.error(_LE("create image backup failed, image_id: %s."),
                      image_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=image_id,
                resource_type=constants.IMAGE_RESOURCE_TYPE)
    def on_main(self, checkpoint, resource, context, parameters, **kwargs):
        network_id = get_network_id(context)
        backup_name = kwargs.get("backup_name", "karbor network backup")
        bank_section = checkpoint.get_resource_bank_section(network_id)
        neutron_client = ClientFactory.create_client("neutron", context)

        resource_definition = {"resource_id": network_id}
        resource_definition["backup_name"] = backup_name
        resource_definition["network_metadata"] = (
            self._get_resources_by_network(context, neutron_client))
        resource_definition["subnet_metadata"] = (
            self._get_resources_by_subnet(context, neutron_client))
        resource_definition["port_metadata"] = (self._get_resources_by_port(
            context, neutron_client))
        resource_definition["router_metadata"] = (
            self._get_resources_by_router(context, neutron_client))
        resource_definition["security-group_metadata"] = (
            self._get_resources_by_security_group(context, neutron_client))

        try:
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)

            # write resource_definition in bank
            bank_section.update_object("metadata", resource_definition)

            # update resource_definition backup_status
            bank_section.update_object("status",
                                       constants.CHECKPOINT_STATUS_AVAILABLE)
            LOG.info("finish backup network, network_id: %s.", network_id)
        except Exception as err:
            # update resource_definition backup_status
            LOG.error("create backup failed, network_id: %s.", network_id)
            bank_section.update_object("status",
                                       constants.CHECKPOINT_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=network_id,
                resource_type=self._SUPPORT_RESOURCE_TYPES)
Exemple #6
0
    def create_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        backup_name = kwargs.get("backup_name")
        resource = resource_node.value
        volume_id = resource.id

        bank_section = checkpoint.get_resource_bank_section(volume_id)

        resource_definition = {"volume_id": volume_id}
        cinder_client = self._cinder_client(cntxt)

        LOG.info(_LI("creating volume backup, volume_id: %s."), volume_id)
        try:
            bank_section.create_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)

            backup = cinder_client.backups.create(volume_id=volume_id,
                                                  name=backup_name,
                                                  force=True)
            resource_definition["backup_id"] = backup.id
            bank_section.create_object("metadata", resource_definition)
            self.protection_resource_map[volume_id] = {
                "bank_section": bank_section,
                "backup_id": backup.id,
                "cinder_client": cinder_client,
                "operation": "create"
            }
        except Exception as e:
            LOG.error(_LE("create volume backup failed, volume_id: %s."),
                      volume_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=six.text_type(e),
                resource_id=volume_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE
            )
    def on_prepare_finish(self, checkpoint, resource, context, parameters,
                          **kwargs):
        volume_id = resource.id
        if not self._backup_from_snapshot:
            LOG.info(
                'Skipping taking snapshot of volume %s - backing up '
                'directly', volume_id)
            return

        LOG.info('Taking snapshot of volume %s', volume_id)
        bank_section = checkpoint.get_resource_bank_section(volume_id)
        bank_section.update_object('status',
                                   constants.RESOURCE_STATUS_PROTECTING)
        cinder_client = ClientFactory.create_client('cinder', context)
        try:
            self.snapshot_id = self._create_snapshot(cinder_client, volume_id)
        except Exception:
            bank_section.update_object('status',
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason='Error creating snapshot for volume',
                resource_id=volume_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE,
            )
Exemple #8
0
    def create_backup(self, cntxt, checkpoint, **kwargs):
        resource_node = kwargs.get("node")
        server_id = resource_node.value.id

        bank_section = checkpoint.get_resource_bank_section(server_id)

        nova_client = self._nova_client(cntxt)
        glance_client = self._glance_client(cntxt)
        cinder_client = self._cinder_client(cntxt)
        neutron_client = self._neutron_client(cntxt)

        resource_definition = {"resource_id": server_id}
        child_nodes = resource_node.child_nodes
        attach_metadata = {}

        LOG.info(_LI("creating server backup, server_id: %s."), server_id)

        try:
            bank_section.create_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)

            for child_node in child_nodes:
                child_resource = child_node.value
                if child_resource.type == constants.VOLUME_RESOURCE_TYPE:
                    volume = cinder_client.volumes.get(child_resource.id)
                    attachments = getattr(volume, "attachments")
                    for attachment in attachments:
                        if attachment["server_id"] == server_id:
                            attach_metadata[
                                child_resource.id] = attachment["device"]
            resource_definition["attach_metadata"] = attach_metadata

            server = nova_client.servers.get(server_id)
            availability_zone = getattr(server, "OS-EXT-AZ:availability_zone")

            addresses = getattr(server, "addresses")
            networks = []
            floating_ips = []
            for network_infos in addresses.values():
                for network_info in network_infos:
                    addr = network_info.get("addr")
                    mac = network_info.get("OS-EXT-IPS-MAC:mac_addr")
                    network_type = network_info.get("OS-EXT-IPS:type")
                    if network_type == 'fixed':
                        port = neutron_client.list_ports(
                            mac_address=mac)["ports"][0]
                        if port["network_id"] not in networks:
                            networks.append(port["network_id"])
                    elif network_type == "floating":
                        floating_ips.append(addr)

            flavor = getattr(server, "flavor")["id"]
            key_name = getattr(server, "key_name", None)
            security_groups = getattr(server, "security_groups", None)

            server_metadata = {
                "availability_zone": availability_zone,
                "networks": networks,
                "floating_ips": floating_ips,
                "flavor": flavor,
                "key_name": key_name,
                "security_groups": security_groups
            }
            resource_definition["server_metadata"] = server_metadata

            snapshot_id = nova_client.servers.create_image(
                server_id, "snapshot_%s" % server_id)

            bank_section.create_object("metadata", resource_definition)
        except Exception as err:
            # update resource_definition backup_status
            LOG.error(_LE("create backup failed, server_id: %s."), server_id)
            bank_section.create_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=server_id,
                resource_type=constants.SERVER_RESOURCE_TYPE)

        self._add_to_threadpool(self._create_backup, glance_client,
                                bank_section, server_id, snapshot_id,
                                resource_definition, checkpoint)
Exemple #9
0
    def _create_backup(self, glance_client, bank_section, server_id,
                       snapshot_id, resource_definition, checkpoint):
        try:
            image = glance_client.images.get(snapshot_id)
            # TODO(luobin): config retry_attempts
            retry_attempts = 10
            while image.status == "queued" and retry_attempts != 0:
                sleep(60)
                image = glance_client.images.get(snapshot_id)
                retry_attempts -= 1
            if retry_attempts == 0:
                raise Exception

            resource_definition["snapshot_id"] = snapshot_id
            snapshot_metadata = {
                "disk_format": image.disk_format,
                "container_format": image.container_format,
                "name": "snapshot_%s@%s" % (checkpoint.id, server_id)
            }

            if getattr(image, "kernel_id", None) is not None:
                kernel = glance_client.images.get(image.kernel_id)
                kernel_metadata = {
                    "disk_format": kernel.disk_format,
                    "container_format": kernel.container_format,
                    "name": "kernel_%s@%s" % (checkpoint.id, server_id)
                }
                snapshot_metadata["kernel_metadata"] = kernel_metadata

            if getattr(image, "ramdisk_id", None) is not None:
                ramdisk = glance_client.images.get(image.ramdisk_id)
                ramdisk_metadata = {
                    "disk_format": ramdisk.disk_format,
                    "container_format": ramdisk.container_format,
                    "name": "ramdisk_%s@%s" % (checkpoint.id, server_id)
                }
                snapshot_metadata["ramdisk_metadata"] = ramdisk_metadata

            resource_definition["snapshot_metadata"] = snapshot_metadata
            # write resource_definition in bank
            bank_section.create_object("metadata", resource_definition)

            image = glance_client.images.get(snapshot_id)
            # TODO(luobin): config retry_attempts
            retry_attempts = 10
            while image.status != "active" and retry_attempts != 0:
                sleep(60)
                image = glance_client.images.get(snapshot_id)
                retry_attempts -= 1
            if retry_attempts == 0:
                raise Exception

            # store kernel_data if need
            if getattr(image, "kernel_id", None) is not None:
                kernel_id = image.kernel_id
                kernel_response = glance_client.images.data(kernel_id)
                kernel_response_data = BytesIO()
                for chunk in kernel_response:
                    kernel_response_data.write(chunk)
                kernel_response_data.seek(0, os.SEEK_SET)

                chunks = 0
                while True:
                    data = kernel_response_data.read(self.image_object_size)
                    if data == '':
                        break
                    bank_section.create_object("kernel_" + str(chunks), data)
                    chunks += 1

            # store ramdisk_data if need
            if getattr(image, "ramdisk_id", None) is not None:
                ramdisk_id = image.ramdisk_id
                ramdisk_response = glance_client.images.data(ramdisk_id)
                ramdisk_response_data = BytesIO()
                for chunk in ramdisk_response:
                    ramdisk_response_data.write(chunk)
                ramdisk_response_data.seek(0, os.SEEK_SET)

                chunks = 0
                while True:
                    data = ramdisk_response_data.read(self.image_object_size)
                    if data == '':
                        break
                    bank_section.create_object("ramdisk_" + str(chunks), data)
                    chunks += 1

            # store snapshot_data
            image_response = glance_client.images.data(snapshot_id)
            image_response_data = BytesIO()
            for chunk in image_response:
                image_response_data.write(chunk)
            image_response_data.seek(0, os.SEEK_SET)

            chunks = 0
            while True:
                data = image_response_data.read(self.image_object_size)
                if data == '':
                    break
                bank_section.create_object("snapshot_" + str(chunks), data)
                chunks += 1

            glance_client.images.delete(snapshot_id)

            # update resource_definition backup_status
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_AVAILABLE)
            LOG.info(_LI("finish backup server, server_id: %s."), server_id)
        except Exception as err:
            LOG.error(_LE("create backup failed, server_id: %s."), server_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)

            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=server_id,
                resource_type=constants.SERVER_RESOURCE_TYPE)
    def on_main(self, checkpoint, resource, context, parameters, **kwargs):
        server_id = resource.id
        bank_section = checkpoint.get_resource_bank_section(server_id)

        nova_client = ClientFactory.create_client("nova", context)
        cinder_client = ClientFactory.create_client("cinder", context)
        neutron_client = ClientFactory.create_client("neutron", context)

        resource_definition = {"resource_id": server_id}

        # get dependent resources
        server_child_nodes = []
        resources = checkpoint.resource_graph
        for resource_node in resources:
            resource = resource_node.value
            if resource.id == server_id:
                server_child_nodes = resource_node.child_nodes

        LOG.info("Creating server backup, server_id: %s. ", server_id)
        try:
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_PROTECTING)

            # get attach_metadata about volume
            attach_metadata = {}
            for server_child_node in server_child_nodes:
                child_resource = server_child_node.value
                if child_resource.type == constants.VOLUME_RESOURCE_TYPE:
                    volume = cinder_client.volumes.get(child_resource.id)
                    attachments = getattr(volume, "attachments")
                    for attachment in attachments:
                        if attachment["server_id"] == server_id:
                            attachment["bootable"] = getattr(
                                volume, "bootable")
                            attach_metadata[child_resource.id] = attachment
            resource_definition["attach_metadata"] = attach_metadata

            # get metadata about AZ
            server = nova_client.servers.get(server_id)
            availability_zone = getattr(server, "OS-EXT-AZ:availability_zone")

            # get metadata about network, flavor, key_name, security_groups
            addresses = getattr(server, "addresses")
            networks = []
            floating_ips = []
            for network_infos in addresses.values():
                for network_info in network_infos:
                    addr = network_info.get("addr")
                    mac = network_info.get("OS-EXT-IPS-MAC:mac_addr")
                    network_type = network_info.get("OS-EXT-IPS:type")
                    if network_type == 'fixed':
                        port = neutron_client.list_ports(
                            mac_address=mac)["ports"][0]
                        if port["network_id"] not in networks:
                            networks.append(port["network_id"])
                    elif network_type == "floating":
                        floating_ips.append(addr)
            flavor = getattr(server, "flavor")["id"]
            key_name = getattr(server, "key_name", None)
            security_groups = getattr(server, "security_groups", None)

            # get metadata about boot device
            boot_metadata = {}
            image_info = getattr(server, "image", None)
            if image_info is not None and isinstance(image_info, dict):
                boot_metadata["boot_device_type"] = "image"
                boot_metadata["boot_image_id"] = image_info['id']
            else:
                boot_metadata["boot_device_type"] = "volume"
                volumes_attached = getattr(
                    server, "os-extended-volumes:volumes_attached", [])
                for volume_attached in volumes_attached:
                    volume_id = volume_attached["id"]
                    volume_attach_metadata = attach_metadata.get(
                        volume_id, None)
                    if volume_attach_metadata is not None and (
                            volume_attach_metadata["bootable"] == "true"):
                        boot_metadata["boot_volume_id"] = volume_id
                        boot_metadata["boot_attach_metadata"] = (
                            volume_attach_metadata)
            resource_definition["boot_metadata"] = boot_metadata

            # save all server's metadata
            server_metadata = {
                "availability_zone": availability_zone,
                "networks": networks,
                "floating_ips": floating_ips,
                "flavor": flavor,
                "key_name": key_name,
                "security_groups": security_groups,
            }
            resource_definition["server_metadata"] = server_metadata
            LOG.info("Creating server backup, resource_definition: %s.",
                     resource_definition)
            bank_section.update_object("metadata", resource_definition)

            # update resource_definition backup_status
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_AVAILABLE)
            LOG.info("Finish backup server, server_id: %s.", server_id)
        except Exception as err:
            # update resource_definition backup_status
            LOG.exception("Create backup failed, server_id: %s.", server_id)
            bank_section.update_object("status",
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=err,
                resource_id=server_id,
                resource_type=constants.SERVER_RESOURCE_TYPE)
    def on_main(self, checkpoint, resource, context, parameters, **kwargs):
        volume_id = resource.id
        bank_section = checkpoint.get_resource_bank_section(volume_id)
        cinder_client = ClientFactory.create_client('cinder', context)
        LOG.info('creating volume backup, volume_id: %s', volume_id)
        bank_section.update_object('status',
                                   constants.RESOURCE_STATUS_PROTECTING)
        resource_metadata = {
            'volume_id': volume_id,
        }
        is_success = utils.status_poll(
            partial(get_volume_status, cinder_client, volume_id),
            interval=self._interval,
            success_statuses={
                'available', 'in-use', 'error_extending', 'error_restoring'
            },
            failure_statuses={
                'error', 'error_deleting', 'deleting', 'not-found'
            },
            ignore_statuses={
                'attaching', 'creating', 'backing-up', 'restoring-backup'
            },
        )
        if not is_success:
            bank_section.update_object('status',
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason='Volume is in erroneous state',
                resource_id=volume_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE,
            )

        backup_name = parameters.get('backup_name', None)
        description = parameters.get('description', None)
        backup_mode = parameters.get('backup_mode', "full")
        container = parameters.get('container', None)
        force = parameters.get('force', False)
        incremental = False
        if backup_mode == "incremental":
            incremental = True
        elif backup_mode == "full":
            incremental = False

        try:
            backup_id = self._create_backup(cinder_client, volume_id,
                                            backup_name, description,
                                            self.snapshot_id, incremental,
                                            container, force)
        except Exception as e:
            LOG.error(
                'Error creating backup (volume_id: %(volume_id)s '
                'snapshot_id: %(snapshot_id)s): %(reason)s', {
                    'volume_id': volume_id,
                    'snapshot_id': self.snapshot_id,
                    'reason': e
                })
            bank_section.update_object('status',
                                       constants.RESOURCE_STATUS_ERROR)
            raise exception.CreateBackupFailed(
                reason=e,
                resource_id=volume_id,
                resource_type=constants.VOLUME_RESOURCE_TYPE,
            )

        resource_metadata['backup_id'] = backup_id
        bank_section.update_object('metadata', resource_metadata)
        bank_section.update_object('status',
                                   constants.RESOURCE_STATUS_AVAILABLE)
        LOG.info(
            'Backed up volume (volume_id: %(volume_id)s snapshot_id: '
            '%(snapshot_id)s backup_id: %(backup_id)s) successfully', {
                'backup_id': backup_id,
                'snapshot_id': self.snapshot_id,
                'volume_id': volume_id
            })

        if self.snapshot_id:
            try:
                self._delete_snapshot(cinder_client, self.snapshot_id)
            except Exception as e:
                LOG.warning(
                    'Failed deleting snapshot: %(snapshot_id)s. '
                    'Reason: %(reason)s', {
                        'snapshot_id': self.snapshot_id,
                        'reason': e
                    })