package org.zstack.storage.ceph.backup; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusCallBack; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.SimpleQuery; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.image.*; import org.zstack.header.message.MessageReply; import org.zstack.header.rest.JsonAsyncRESTCallback; import org.zstack.header.rest.RESTFacade; import org.zstack.header.storage.backup.*; import org.zstack.storage.ceph.CephConstants; import org.zstack.storage.ceph.CephGlobalProperty; import org.zstack.storage.ceph.MonStatus; import org.zstack.utils.DebugUtils; import org.zstack.utils.Utils; import org.zstack.utils.gson.JSONObjectUtil; import org.zstack.utils.logging.CLogger; import javax.persistence.TypedQuery; import java.util.ArrayList; import java.util.List; /** * Created by Mei Lei <meilei007@gmail.com> on 11/3/16. */ public class CephBackupStorageMetaDataMaker implements AddImageExtensionPoint, AddBackupStorageExtensionPoint, ExpungeImageExtensionPoint { private static final CLogger logger = Utils.getLogger(CephBackupStorageMetaDataMaker.class); @Autowired protected RESTFacade restf; @Autowired private DatabaseFacade dbf; @Autowired private ErrorFacade errf; @Autowired private CloudBus bus; protected String buildUrl( String hostName, Integer monPort,String subPath) { return String.format("http://%s:%s%s", hostName, monPort, subPath); } @Transactional protected String getAllImageInventories(ImageInventory img, String bsUuid) { String allImageInventories = null; String sql = "select img from ImageVO img where uuid in (select imageUuid from ImageBackupStorageRefVO ref where ref.backupStorageUuid= :bsUuid)"; TypedQuery<ImageVO> q = dbf.getEntityManager().createQuery(sql, ImageVO.class); if (img != null ) { q.setParameter("bsUuid", getBackupStorageUuidFromImageInventory(img)); } else { q.setParameter("bsUuid", bsUuid); } List<ImageVO> allImageVO = q.getResultList(); for (ImageVO imageVO : allImageVO) { if (allImageInventories != null) { allImageInventories = JSONObjectUtil.toJsonString(ImageInventory.valueOf(imageVO)) + "\n" + allImageInventories; } else { allImageInventories = JSONObjectUtil.toJsonString(ImageInventory.valueOf(imageVO)); } } return allImageInventories; } protected String getBackupStorageUuidFromImageInventory(ImageInventory img) { SimpleQuery<ImageBackupStorageRefVO> q = dbf.createQuery(ImageBackupStorageRefVO.class); q.select(ImageBackupStorageRefVO_.backupStorageUuid); q.add(ImageBackupStorageRefVO_.imageUuid, SimpleQuery.Op.EQ, img.getUuid()); String backupStorageUuid = q.findValue(); DebugUtils.Assert(backupStorageUuid != null, String.format("cannot find backup storage for image [uuid:%s]", img.getUuid())); return backupStorageUuid; } protected void restoreImagesBackupStorageMetadataToDatabase(String imagesMetadata, String backupStorageUuid) { List<ImageVO> imageVOs = new ArrayList<ImageVO>(); List<ImageBackupStorageRefVO> backupStorageRefVOs = new ArrayList<ImageBackupStorageRefVO>(); String[] metadatas = imagesMetadata.split("\n"); for ( String metadata : metadatas) { if (metadata.contains("backupStorageRefs")) { ImageInventory imageInventory = JSONObjectUtil.toObject(metadata, ImageInventory.class); for ( ImageBackupStorageRefInventory ref : imageInventory.getBackupStorageRefs()) { ImageBackupStorageRefVO backupStorageRefVO = new ImageBackupStorageRefVO(); backupStorageRefVO.setStatus(ImageStatus.valueOf(ref.getStatus())); backupStorageRefVO.setInstallPath(ref.getInstallPath()); backupStorageRefVO.setImageUuid(ref.getImageUuid()); backupStorageRefVO.setBackupStorageUuid(backupStorageUuid); backupStorageRefVO.setCreateDate(ref.getCreateDate()); backupStorageRefVO.setLastOpDate(ref.getLastOpDate()); backupStorageRefVOs.add(backupStorageRefVO); } ImageVO imageVO = new ImageVO(); imageVO.setActualSize(imageInventory.getActualSize()); imageVO.setDescription(imageInventory.getDescription()); imageVO.setStatus(ImageStatus.valueOf(imageInventory.getStatus())); imageVO.setExportUrl(imageInventory.getExportUrl()); imageVO.setFormat(imageInventory.getFormat()); imageVO.setGuestOsType(imageInventory.getGuestOsType()); imageVO.setMd5Sum(imageInventory.getMd5Sum()); imageVO.setMediaType(ImageConstant.ImageMediaType.valueOf(imageInventory.getMediaType())); imageVO.setName(imageInventory.getName()); imageVO.setPlatform(ImagePlatform.valueOf(imageInventory.getPlatform())); imageVO.setSize(imageInventory.getSize()); imageVO.setState(ImageState.valueOf(imageInventory.getState())); imageVO.setSystem(imageInventory.isSystem()); imageVO.setType(imageInventory.getType()); imageVO.setUrl(imageInventory.getUrl()); imageVO.setUuid(imageInventory.getUuid()); imageVO.setCreateDate(imageInventory.getCreateDate()); imageVO.setLastOpDate(imageInventory.getLastOpDate()); imageVOs.add(imageVO); } } dbf.persistCollection(imageVOs); dbf.persistCollection(backupStorageRefVOs); } protected String getHostnameFromBackupStorage(CephBackupStorageInventory inv) { SimpleQuery<CephBackupStorageMonVO> q = dbf.createQuery(CephBackupStorageMonVO.class); q.select(CephBackupStorageMonVO_.hostname); q.add(CephBackupStorageMonVO_.backupStorageUuid, SimpleQuery.Op.EQ, inv.getUuid()); q.add(CephBackupStorageMonVO_.status, SimpleQuery.Op.EQ, MonStatus.Connected); q.setLimit(1); String hostName = q.findValue(); DebugUtils.Assert(hostName!= null, String.format("cannot find hostName for ceph backup storage [uuid:%s]", inv.getUuid())); return hostName; } @Transactional protected String getHostNameFromImageInventory(ImageInventory img) { String sql="select mon.hostname from CephBackupStorageMonVO mon, ImageBackupStorageRefVO ref where " + "ref.imageUuid= :uuid and ref.backupStorageUuid = mon.backupStorageUuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", img.getUuid()); return q.getSingleResult(); } @Transactional protected Integer getMonPortFromImageInventory(ImageInventory img) { String sql="select mon.monPort from CephBackupStorageMonVO mon, ImageBackupStorageRefVO ref where " + "ref.imageUuid= :uuid and ref.backupStorageUuid = mon.backupStorageUuid"; TypedQuery<Integer> q = dbf.getEntityManager().createQuery(sql, Integer.class); q.setParameter("uuid", img.getUuid()); return q.getSingleResult(); } @Transactional protected String getBackupStorageTypeFromImageInventory(ImageInventory img) { String sql = "select bs.type from BackupStorageVO bs, ImageBackupStorageRefVO refVo where " + "bs.uuid = refVo.backupStorageUuid and refVo.imageUuid = :uuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", img.getUuid()); return q.getSingleResult(); } protected void dumpImagesBackupStorageInfoToMetaDataFile(ImageInventory img, boolean allImagesInfo, String hostName, String bsUuid ) { logger.debug("dump images info to meta data file"); CephBackupStorageBase.DumpImageInfoToMetaDataFileCmd dumpCmd = new CephBackupStorageBase.DumpImageInfoToMetaDataFileCmd(); String metaData; if (allImagesInfo) { metaData = getAllImageInventories(null, bsUuid); } else { metaData = JSONObjectUtil.toJsonString(img); } dumpCmd.setImageMetaData(metaData); dumpCmd.setDumpAllMetaData(allImagesInfo); dumpCmd.setPoolName(bsUuid); if (hostName == null || hostName.isEmpty()) { hostName = getHostNameFromImageInventory(img); } Integer monPort = CephGlobalProperty.BACKUP_STORAGE_AGENT_PORT; restf.asyncJsonPost(buildUrl(hostName, monPort, CephBackupStorageBase.DUMP_IMAGE_METADATA_TO_FILE), dumpCmd, new JsonAsyncRESTCallback<CephBackupStorageBase.DumpImageInfoToMetaDataFileRsp >(null) { @Override public void fail(ErrorCode err) { logger.error("Dump image metadata failed" + err.toString()); } @Override public void success(CephBackupStorageBase.DumpImageInfoToMetaDataFileRsp rsp) { if (!rsp.isSuccess()) { logger.error("Dump image metadata failed"); } else { logger.info("Dump image metadata successfully"); } } @Override public Class<CephBackupStorageBase.DumpImageInfoToMetaDataFileRsp> getReturnClass() { return CephBackupStorageBase.DumpImageInfoToMetaDataFileRsp.class; } }); } @Override public void preAddImage(ImageInventory img) { } @Override public void beforeAddImage(ImageInventory img) { } @Override public void afterAddImage(ImageInventory img) { if (!getBackupStorageTypeFromImageInventory(img).equals(CephConstants.CEPH_BACKUP_STORAGE_TYPE)) { return; } SimpleQuery<CephBackupStorageVO> query = dbf.createQuery(CephBackupStorageVO.class); query.add(CephBackupStorageVO_.uuid, SimpleQuery.Op.EQ, getBackupStorageUuidFromImageInventory(img)); CephBackupStorageVO cephBackupStorageVO = query.find(); CephBackupStorageInventory inv = CephBackupStorageInventory.valueOf(cephBackupStorageVO); BakeImageMetadataMsg msg = new BakeImageMetadataMsg(); msg.setImg(img); msg.setOperation(CephConstants.AFTER_ADD_IMAGE); msg.setBackupStorageUuid(getBackupStorageUuidFromImageInventory(img)); msg.setPoolName(inv.getPoolName()); bus.makeLocalServiceId(msg, BackupStorageConstant.SERVICE_ID); bus.send(msg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { logger.debug("add image info to metadata file successfully"); } else { reply.setError(reply.getError()); } bus.reply(msg, reply); } }); } @Override public void failedToAddImage(ImageInventory img, ErrorCode err) { } @Override public void preAddBackupStorage(AddBackupStorageStruct backupStorage) { } @Override public void beforeAddBackupStorage(AddBackupStorageStruct backupStorage) { } @Override public void afterAddBackupStorage(AddBackupStorageStruct backupStorage) { logger.debug("starting to import ceph images metadata"); if (!(backupStorage.getType().equals(CephConstants.CEPH_BACKUP_STORAGE_TYPE) && backupStorage.isImportImages())) { logger.debug("will not to import ceph images metadata due to importImages didn't set or bs type is not ceph"); return; } String backupStorageUuid = backupStorage.getBackupStorageInventory().getUuid(); SimpleQuery<CephBackupStorageVO> query = dbf.createQuery(CephBackupStorageVO.class); query.add(CephBackupStorageVO_.uuid, SimpleQuery.Op.EQ, backupStorageUuid); CephBackupStorageVO cephBackupStorageVO = query.find(); CephBackupStorageInventory inv = CephBackupStorageInventory.valueOf(cephBackupStorageVO); BakeImageMetadataMsg msg = new BakeImageMetadataMsg(); msg.setBackupStorageUuid(backupStorageUuid); msg.setOperation(CephConstants.AFTER_ADD_BACKUPSTORAGE); msg.setPoolName(inv.getPoolName()); bus.makeLocalServiceId(msg, BackupStorageConstant.SERVICE_ID); bus.send(msg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { logger.debug("import ceph backup storage images info successfully"); } else { logger.debug("import ceph backup storage images info failed"); reply.setError(reply.getError()); } bus.reply(msg, reply); } }); } public void failedToAddBackupStorage(AddBackupStorageStruct backupStorage, ErrorCode err) { } public void preExpungeImage(ImageInventory img) { } public void beforeExpungeImage(ImageInventory img) { } public void afterExpungeImage(ImageInventory img, String backupStorageUuid) { logger.debug(String.format("starting to delete image %s from metadata file", img.getUuid())); if (!getBackupStorageTypeFromImageInventory(img).equals(CephConstants.CEPH_BACKUP_STORAGE_TYPE)) { return; } SimpleQuery<CephBackupStorageVO> query = dbf.createQuery(CephBackupStorageVO.class); query.add(CephBackupStorageVO_.uuid, SimpleQuery.Op.EQ, getBackupStorageUuidFromImageInventory(img)); CephBackupStorageVO cephBackupStorageVO = query.find(); CephBackupStorageInventory inv = CephBackupStorageInventory.valueOf(cephBackupStorageVO); BakeImageMetadataMsg msg = new BakeImageMetadataMsg(); msg.setImg(img); msg.setBackupStorageUuid(getBackupStorageUuidFromImageInventory(img)); msg.setOperation(CephConstants.AFTER_EXPUNGE_IMAGE); msg.setPoolName(inv.getPoolName()); bus.makeLocalServiceId(msg, BackupStorageConstant.SERVICE_ID); bus.send(msg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { if (reply.isSuccess()) { logger.debug("delete image info from metadata file successfully"); } else { reply.setError(reply.getError()); } bus.reply(msg, reply); } }); } public void failedToExpungeImage(ImageInventory img, ErrorCode err) { } }