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)
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)
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, )
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)
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 })