package org.zstack.simulator.storage.backup.sftp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.zstack.core.thread.AsyncThread;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.rest.RESTConstant;
import org.zstack.header.rest.RESTFacade;
import org.zstack.simulator.AsyncRESTReplyer;
import org.zstack.storage.backup.sftp.SftpBackupStorageCommands.*;
import org.zstack.storage.backup.sftp.SftpBackupStorageConstant;
import org.zstack.utils.Utils;
import org.zstack.utils.gson.JSONObjectUtil;
import org.zstack.utils.logging.CLogger;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
@Controller
public class SftpBackupStorageSimulator {
CLogger logger = Utils.getLogger(SftpBackupStorageSimulator.class);
@Autowired
private SftpBackupStorageSimulatorConfig config;
@Autowired
private RESTFacade restf;
private AsyncRESTReplyer replyer;
@RequestMapping(value = SftpBackupStorageConstant.CONNECT_PATH, method = RequestMethod.POST)
public
@ResponseBody
String connect(@RequestBody String body) {
ConnectCmd cmd = JSONObjectUtil.toObject(body, ConnectCmd.class);
ConnectResponse rsp = new ConnectResponse();
if (!config.connectSuccess) {
rsp.setSuccess(false);
rsp.setError("Fail connect on purpose");
} else {
config.bsUuid = cmd.getUuid();
rsp.setTotalCapacity(config.totalCapacity);
rsp.setAvailableCapacity(config.availableCapacity);
logger.debug(String.format("Connect to path[%s], %s", cmd.getStoragePath(), JSONObjectUtil.toJsonString(rsp)));
}
return JSONObjectUtil.toJsonString(rsp);
}
@RequestMapping(value = SftpBackupStorageConstant.ECHO_PATH, method = RequestMethod.POST)
public
@ResponseBody
String echo(@RequestBody String body) {
return "";
}
private void reply(HttpEntity<String> entity, AgentResponse rsp) {
if (replyer == null) {
replyer = new AsyncRESTReplyer();
}
replyer.reply(entity, rsp);
}
@AsyncThread
private void doDownload(HttpEntity<String> entity) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
DownloadCmd cmd = JSONObjectUtil.toObject(entity.getBody(), DownloadCmd.class);
DownloadResponse rsp = new DownloadResponse();
if (!config.downloadSuccess2) {
rsp.setSuccess(false);
rsp.setError("Fail download on purpose");
} else {
Long size = config.imageSizes.get(cmd.getImageUuid());
Long asize = config.imageActualSizes.get(cmd.getImageUuid());
rsp.setSize(size == null ? 0 : size);
rsp.setActualSize(asize == null ? 0 : asize);
rsp.setMd5Sum(config.imageMd5sum);
rsp.setTotalCapacity(config.totalCapacity);
long usedSize = 0;
for (Long s : config.imageSizes.values()) {
usedSize += s;
}
rsp.setAvailableCapacity(config.totalCapacity - usedSize);
logger.debug(String.format("Download %s", cmd.getUrl()));
}
reply(entity, rsp);
}
@RequestMapping(value = SftpBackupStorageConstant.DOWNLOAD_IMAGE_PATH, method = RequestMethod.POST)
public
@ResponseBody
String download(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
if (!config.downloadSuccess1) {
throw new CloudRuntimeException("Fail download on purpose");
} else {
doDownload(entity);
}
return null;
}
@RequestMapping(value = SftpBackupStorageConstant.GET_IMAGE_SIZE, method = RequestMethod.POST)
public
@ResponseBody
String getImageActualSize(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
GetImageSizeCmd cmd = JSONObjectUtil.toObject(entity.getBody(), GetImageSizeCmd.class);
GetImageSizeRsp rsp = new GetImageSizeRsp();
Long asize = config.getImageSizeCmdActualSize.get(cmd.imageUuid);
rsp.actualSize = asize == null ? 0 : asize;
Long size = config.getImageSizeCmdSize.get(cmd.imageUuid);
rsp.size = size == null ? 0 : size;
reply(entity, rsp);
return null;
}
@AsyncThread
private void doDelete(HttpEntity<String> entity) {
AgentResponse rsp = null;
DeleteCmd cmd = JSONObjectUtil.toObject(entity.getBody(), DeleteCmd.class);
if (!config.deleteSuccess) {
rsp = new AgentResponse();
rsp.setError("Fail delete on purpose");
rsp.setSuccess(false);
} else {
config.deleteCmds.add(cmd);
logger.debug(String.format("Deleted %s", cmd.getInstallUrl()));
rsp = (AgentResponse) (new DeleteResponse());
}
String taskUuid = entity.getHeaders().getFirst(RESTConstant.TASK_UUID);
String callbackUrl = entity.getHeaders().getFirst(RESTConstant.CALLBACK_URL);
String rspBody = JSONObjectUtil.toJsonString(rsp);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setContentLength(rspBody.length());
headers.set(RESTConstant.TASK_UUID, taskUuid);
HttpEntity<String> rreq = new HttpEntity<String>(rspBody, headers);
restf.getRESTTemplate().exchange(callbackUrl, HttpMethod.POST, rreq, String.class);
}
@RequestMapping(value = SftpBackupStorageConstant.DELETE_PATH, method = RequestMethod.POST)
public
@ResponseBody
String delete(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
doDelete(entity);
return null;
}
@RequestMapping(value = SftpBackupStorageConstant.PING_PATH, method = RequestMethod.POST)
public
@ResponseBody
String ping(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
if (config.pingException) {
throw new CloudRuntimeException("on purpose");
}
doPing(entity);
return null;
}
@AsyncThread
private void doPing(HttpEntity<String> entity) {
PingResponse rsp = new PingResponse();
if (!config.pingSuccess) {
rsp.setError("on purpose");
rsp.setSuccess(false);
} else {
rsp.setUuid(config.bsUuid);
}
reply(entity, rsp);
}
@RequestMapping(value = SftpBackupStorageConstant.CHECK_IMAGE_METADATA_FILE_EXIST, method = RequestMethod.POST)
public
@ResponseBody
String checkMetadataFileExist(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
CheckImageMetaDataFileExistCmd cmd = JSONObjectUtil.toObject(entity.getBody(), CheckImageMetaDataFileExistCmd.class);
CheckImageMetaDataFileExistRsp rsp = new CheckImageMetaDataFileExistRsp();
rsp.setBackupStorageMetaFileName("bs_file_info.json");
rsp.setExist(true);
rsp.setSuccess(true);
reply(entity, rsp);
return null;
}
@RequestMapping(value = SftpBackupStorageConstant.GENERATE_IMAGE_METADATA_FILE, method = RequestMethod.POST)
public
@ResponseBody
String generateMetadataFile(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
GenerateImageMetaDataFileCmd cmd = JSONObjectUtil.toObject(entity.getBody(), GenerateImageMetaDataFileCmd.class);
GenerateImageMetaDataFileRsp rsp = new GenerateImageMetaDataFileRsp();
rsp.setBackupStorageMetaFileName("bs_file_info.json");
rsp.setSuccess(true);
reply(entity, rsp);
return null;
}
@RequestMapping(value = SftpBackupStorageConstant.DUMP_IMAGE_METADATA_TO_FILE, method = RequestMethod.POST)
public
@ResponseBody
String dumpImagesInfoToMetadataFile(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
DumpImageInfoToMetaDataFileCmd cmd = JSONObjectUtil.toObject(entity.getBody(), DumpImageInfoToMetaDataFileCmd.class);
DumpImageInfoToMetaDataFileRsp rsp = new DumpImageInfoToMetaDataFileRsp();
rsp.setSuccess(true);
reply(entity, rsp);
return null;
}
@RequestMapping(value = SftpBackupStorageConstant.DELETE_IMAGES_METADATA, method = RequestMethod.POST)
public
@ResponseBody
String deleteImagesInfoFromMetadataFile(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
DeleteImageInfoFromMetaDataFileCmd cmd = JSONObjectUtil.toObject(entity.getBody(), DeleteImageInfoFromMetaDataFileCmd.class);
DeleteImageInfoFromMetaDataFileRsp rsp = new DeleteImageInfoFromMetaDataFileRsp();
rsp.setSuccess(true);
rsp.setOut("delete success");
rsp.setRet(0);
reply(entity, rsp);
return null;
}
@RequestMapping(value = SftpBackupStorageConstant.GET_IMAGES_METADATA, method = RequestMethod.POST)
public
@ResponseBody
String getImagesInfoFromMetadataFile(HttpServletRequest req) throws InterruptedException {
HttpEntity<String> entity = restf.httpServletRequestToHttpEntity(req);
GetImagesMetaDataCmd cmd = JSONObjectUtil.toObject(entity.getBody(), GetImagesMetaDataCmd.class);
GetImagesMetaDataRsp rsp = new GetImagesMetaDataRsp();
rsp.setSuccess(true);
rsp.setImagesMetaData("{\"uuid\":\"a603e80ea18f424f8a5f00371d484537\",\"name\":\"test\",\"description\":\"\",\"state\":\"Enabled\",\"status\":\"Ready\",\"size\":19862528,\"actualSize\":15794176,\"md5Sum\":\"not calculated\",\"url\":\"http://192.168.200.1/mirror/diskimages/zstack-image-1.2.qcow2\",\"mediaType\":\"RootVolumeTemplate\",\"type\":\"zstack\",\"platform\":\"Linux\",\"format\":\"qcow2\",\"system\":false,\"createDate\":\"Dec 22, 2016 5:10:06 PM\",\"lastOpDate\":\"Dec 22, 2016 5:10:08 PM\",\"backupStorageRefs\":[{\"id\":45,\"imageUuid\":\"a603e80ea18f424f8a5f00371d484537\",\"backupStorageUuid\":\"63879ceb90764f839d3de772aa646c83\",\"installPath\":\"/bs-sftp/rootVolumeTemplates/acct-36c27e8ff05c4780bf6d2fa65700f22e/a603e80ea18f424f8a5f00371d484537/zstack-image-1.2.template\",\"status\":\"Ready\",\"createDate\":\"Dec 22, 2016 5:10:08 PM\",\"lastOpDate\":\"Dec 22, 2016 5:10:08 PM\"}]}");
reply(entity, rsp);
return null;
}
}