Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.cloud.hypervisor.xen.resource; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer; import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CopyCmd; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreateVolumeFromBaseImageCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol; import org.apache.cloudstack.storage.to.ImageOnPrimayDataStoreTO; import org.apache.cloudstack.storage.to.VolumeTO; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.log4j.Logger; import org.apache.xmlrpc.XmlRpcException; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.storage.DeleteVolumeCommand; import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.storage.encoding.DecodedDataObject; import com.cloud.utils.storage.encoding.DecodedDataStore; import com.cloud.utils.storage.encoding.Decoder; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Host; import com.xensource.xenapi.PBD; import com.xensource.xenapi.SR; import com.xensource.xenapi.Types; import com.xensource.xenapi.Types.BadServerResponse; import com.xensource.xenapi.Types.XenAPIException; import com.xensource.xenapi.VDI; import edu.emory.mathcs.backport.java.util.Arrays; public class XenServerStorageResource { private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class); protected CitrixResourceBase hypervisorResource; public XenServerStorageResource(CitrixResourceBase resource) { this.hypervisorResource = resource; } public Answer handleStorageCommands(StorageSubSystemCommand command) { if (command instanceof CopyCmd) { return this.execute((CopyCmd) command); } else if (command instanceof AttachPrimaryDataStoreCmd) { return this.execute((AttachPrimaryDataStoreCmd) command); } else if (command instanceof CreatePrimaryDataStoreCmd) { return execute((CreatePrimaryDataStoreCmd) command); } else if (command instanceof CreateVolumeFromBaseImageCommand) { return execute((CreateVolumeFromBaseImageCommand) command); } else if (command instanceof CreateObjectCommand) { return execute((CreateObjectCommand) command); } else if (command instanceof DeleteVolumeCommand) { return execute((DeleteVolumeCommand) command); } return new Answer((Command) command, false, "not implemented yet"); } protected SR getSRByNameLabel(Connection conn, String nameLabel) throws BadServerResponse, XenAPIException, XmlRpcException { Set<SR> srs = SR.getByNameLabel(conn, nameLabel); if (srs.size() != 1) { throw new CloudRuntimeException("storage uuid: " + nameLabel + " is not unique"); } SR poolsr = srs.iterator().next(); return poolsr; } protected VDI createVdi(Connection conn, String vdiName, SR sr, long size) throws BadServerResponse, XenAPIException, XmlRpcException { VDI.Record vdir = new VDI.Record(); vdir.nameLabel = vdiName; vdir.SR = sr; vdir.type = Types.VdiType.USER; vdir.virtualSize = size; VDI vdi = VDI.create(conn, vdir); return vdi; } protected void deleteVDI(Connection conn, VDI vdi) throws BadServerResponse, XenAPIException, XmlRpcException { vdi.destroy(conn); } private Map<String, String> getParameters(URI uri) { String parameters = uri.getQuery(); Map<String, String> params = new HashMap<String, String>(); List<String> paraLists = Arrays.asList(parameters.split("&")); for (String para : paraLists) { String[] pair = para.split("="); params.put(pair[0], pair[1]); } return params; } protected CreateObjectAnswer getTemplateSize(CreateObjectCommand cmd, String templateUrl) { Connection conn = hypervisorResource.getConnection(); long size = this.getTemplateSize(conn, templateUrl); return new CreateObjectAnswer(cmd, templateUrl, size); } protected CreateObjectAnswer execute(CreateObjectCommand cmd) { String uriString = cmd.getObjectUri(); DecodedDataObject obj = null; Connection conn = hypervisorResource.getConnection(); VDI vdi = null; boolean result = false; String errorMsg = null; try { obj = Decoder.decode(uriString); DecodedDataStore store = obj.getStore(); if (obj.getObjType().equalsIgnoreCase("template") && store.getRole().equalsIgnoreCase("image")) { return getTemplateSize(cmd, obj.getPath()); } long size = obj.getSize(); String name = obj.getName(); String storeUuid = store.getUuid(); SR primaryDataStoreSR = getSRByNameLabel(conn, storeUuid); vdi = createVdi(conn, name, primaryDataStoreSR, size); VDI.Record record = vdi.getRecord(conn); result = true; return new CreateObjectAnswer(cmd, record.uuid, record.virtualSize); } catch (BadServerResponse e) { s_logger.debug("Failed to create volume", e); errorMsg = e.toString(); } catch (XenAPIException e) { s_logger.debug("Failed to create volume", e); errorMsg = e.toString(); } catch (XmlRpcException e) { s_logger.debug("Failed to create volume", e); errorMsg = e.toString(); } catch (URISyntaxException e) { s_logger.debug("Failed to create volume", e); errorMsg = e.toString(); } finally { if (!result && vdi != null) { try { deleteVDI(conn, vdi); } catch (Exception e) { s_logger.debug("Faled to delete vdi: " + vdi.toString()); } } } return new CreateObjectAnswer(cmd, false, errorMsg); } protected Answer execute(DeleteVolumeCommand cmd) { VolumeTO volume = null; Connection conn = hypervisorResource.getConnection(); String errorMsg = null; try { VDI vdi = VDI.getByUuid(conn, volume.getUuid()); deleteVDI(conn, vdi); return new Answer(cmd); } catch (BadServerResponse e) { s_logger.debug("Failed to delete volume", e); errorMsg = e.toString(); } catch (XenAPIException e) { s_logger.debug("Failed to delete volume", e); errorMsg = e.toString(); } catch (XmlRpcException e) { s_logger.debug("Failed to delete volume", e); errorMsg = e.toString(); } return new Answer(cmd, false, errorMsg); } protected Answer execute(CreateVolumeFromBaseImageCommand cmd) { VolumeTO volume = cmd.getVolume(); ImageOnPrimayDataStoreTO baseImage = cmd.getImage(); Connection conn = hypervisorResource.getConnection(); try { VDI baseVdi = VDI.getByUuid(conn, baseImage.getPathOnPrimaryDataStore()); VDI newVol = baseVdi.createClone(conn, new HashMap<String, String>()); newVol.setNameLabel(conn, volume.getName()); return new CreateObjectAnswer(cmd, newVol.getUuid(conn), newVol.getVirtualSize(conn)); } catch (BadServerResponse e) { return new Answer(cmd, false, e.toString()); } catch (XenAPIException e) { return new Answer(cmd, false, e.toString()); } catch (XmlRpcException e) { return new Answer(cmd, false, e.toString()); } } protected SR getNfsSR(Connection conn, DecodedDataStore store) { Map<String, String> deviceConfig = new HashMap<String, String>(); String uuid = store.getUuid(); try { String server = store.getServer(); String serverpath = store.getPath(); serverpath = serverpath.replace("//", "/"); Set<SR> srs = SR.getAll(conn); for (SR sr : srs) { if (!SRType.NFS.equals(sr.getType(conn))) { continue; } Set<PBD> pbds = sr.getPBDs(conn); if (pbds.isEmpty()) { continue; } PBD pbd = pbds.iterator().next(); Map<String, String> dc = pbd.getDeviceConfig(conn); if (dc == null) { continue; } if (dc.get("server") == null) { continue; } if (dc.get("serverpath") == null) { continue; } if (server.equals(dc.get("server")) && serverpath.equals(dc.get("serverpath"))) { throw new CloudRuntimeException("There is a SR using the same configuration server:" + dc.get("server") + ", serverpath:" + dc.get("serverpath") + " for pool " + uuid + "on host:" + hypervisorResource.getHost().uuid); } } deviceConfig.put("server", server); deviceConfig.put("serverpath", serverpath); Host host = Host.getByUuid(conn, hypervisorResource.getHost().uuid); SR sr = SR.create(conn, host, deviceConfig, new Long(0), uuid, uuid, SRType.NFS.toString(), "user", true, new HashMap<String, String>()); sr.scan(conn); return sr; } catch (XenAPIException e) { throw new CloudRuntimeException("Unable to create NFS SR " + uuid, e); } catch (XmlRpcException e) { throw new CloudRuntimeException("Unable to create NFS SR " + uuid, e); } } /* protected SR getIscsiSR(Connection conn, PrimaryDataStoreTO pool) { synchronized (pool.getUuid().intern()) { Map<String, String> deviceConfig = new HashMap<String, String>(); try { String target = pool.getHost(); String path = pool.getPath(); if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } String tmp[] = path.split("/"); if (tmp.length != 3) { String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN"; s_logger.warn(msg); throw new CloudRuntimeException(msg); } String targetiqn = tmp[1].trim(); String lunid = tmp[2].trim(); String scsiid = ""; Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid()); for (SR sr : srs) { if (!SRType.LVMOISCSI.equals(sr.getType(conn))) { continue; } Set<PBD> pbds = sr.getPBDs(conn); if (pbds.isEmpty()) { continue; } PBD pbd = pbds.iterator().next(); Map<String, String> dc = pbd.getDeviceConfig(conn); if (dc == null) { continue; } if (dc.get("target") == null) { continue; } if (dc.get("targetIQN") == null) { continue; } if (dc.get("lunid") == null) { continue; } if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) { throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") + ", targetIQN:" + dc.get("targetIQN") + ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + _host.uuid); } } deviceConfig.put("target", target); deviceConfig.put("targetIQN", targetiqn); Host host = Host.getByUuid(conn, _host.uuid); Map<String, String> smConfig = new HashMap<String, String>(); String type = SRType.LVMOISCSI.toString(); String poolId = Long.toString(pool.getId()); SR sr = null; try { sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true, smConfig); } catch (XenAPIException e) { String errmsg = e.toString(); if (errmsg.contains("SR_BACKEND_FAILURE_107")) { String lun[] = errmsg.split("<LUN>"); boolean found = false; for (int i = 1; i < lun.length; i++) { int blunindex = lun[i].indexOf("<LUNid>") + 7; int elunindex = lun[i].indexOf("</LUNid>"); String ilun = lun[i].substring(blunindex, elunindex); ilun = ilun.trim(); if (ilun.equals(lunid)) { int bscsiindex = lun[i].indexOf("<SCSIid>") + 8; int escsiindex = lun[i].indexOf("</SCSIid>"); scsiid = lun[i].substring(bscsiindex, escsiindex); scsiid = scsiid.trim(); found = true; break; } } if (!found) { String msg = "can not find LUN " + lunid + " in " + errmsg; s_logger.warn(msg); throw new CloudRuntimeException(msg); } } else { String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString(); s_logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } } deviceConfig.put("SCSIid", scsiid); String result = SR.probe(conn, host, deviceConfig, type , smConfig); String pooluuid = null; if( result.indexOf("<UUID>") != -1) { pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).trim(); } if( pooluuid == null || pooluuid.length() != 36) { sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true, smConfig); } else { sr = SR.introduce(conn, pooluuid, pool.getUuid(), poolId, type, "user", true, smConfig); Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn); PBD.Record rec = new PBD.Record(); rec.deviceConfig = deviceConfig; rec.host = pRec.master; rec.SR = sr; PBD pbd = PBD.create(conn, rec); pbd.plug(conn); } sr.scan(conn); return sr; } catch (XenAPIException e) { String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString(); s_logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } catch (Exception e) { String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.getMessage(); s_logger.warn(msg, e); throw new CloudRuntimeException(msg, e); } } }*/ protected Answer execute(CreatePrimaryDataStoreCmd cmd) { Connection conn = hypervisorResource.getConnection(); String storeUrl = cmd.getDataStore(); try { DecodedDataObject obj = Decoder.decode(storeUrl); DecodedDataStore store = obj.getStore(); if (store.getScheme().equalsIgnoreCase("nfs")) { SR sr = getNfsSR(conn, store); } else if (store.getScheme().equalsIgnoreCase("iscsi")) { //getIscsiSR(conn, dataStore); } else if (store.getScheme().equalsIgnoreCase("presetup")) { } else { return new Answer(cmd, false, "The pool type: " + store.getScheme() + " is not supported."); } return new Answer(cmd, true, "success"); } catch (Exception e) { // String msg = "Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" + _host.uuid + " pool: " + pool.getHost() + pool.getPath(); //s_logger.warn(msg, e); return new Answer(cmd, false, null); } } private long getTemplateSize(Connection conn, String url) { String size = hypervisorResource.callHostPlugin(conn, "storagePlugin", "getTemplateSize", "srcUrl", url); if (size.equalsIgnoreCase("") || size == null) { throw new CloudRuntimeException("Can't get template size"); } try { return Long.parseLong(size); } catch (NumberFormatException e) { throw new CloudRuntimeException("Failed to get template lenght", e); } /* HttpHead method = new HttpHead(url); DefaultHttpClient client = new DefaultHttpClient(); try { HttpResponse response = client.execute(method); Header header = response.getFirstHeader("Content-Length"); if (header == null) { throw new CloudRuntimeException("Can't get content-lenght header from :" + url); } Long length = Long.parseLong(header.getValue()); return length; } catch (HttpException e) { throw new CloudRuntimeException("Failed to get template lenght", e); } catch (IOException e) { throw new CloudRuntimeException("Failed to get template lenght", e); } catch (NumberFormatException e) { throw new CloudRuntimeException("Failed to get template lenght", e); }*/ } private void downloadHttpToLocalFile(String destFilePath, String url) { File destFile = new File(destFilePath); if (!destFile.exists()) { throw new CloudRuntimeException("dest file doesn't exist: " + destFilePath); } DefaultHttpClient client = new DefaultHttpClient(); HttpGet getMethod = new HttpGet(url); HttpResponse response; BufferedOutputStream output = null; long length = 0; try { response = client.execute(getMethod); HttpEntity entity = response.getEntity(); length = entity.getContentLength(); output = new BufferedOutputStream(new FileOutputStream(destFile)); entity.writeTo(output); } catch (ClientProtocolException e) { throw new CloudRuntimeException("Failed to download template", e); } catch (IOException e) { throw new CloudRuntimeException("Failed to download template", e); } finally { if (output != null) { try { output.close(); } catch (IOException e) { throw new CloudRuntimeException("Failed to download template", e); } } } //double check the length destFile = new File(destFilePath); if (destFile.length() != length) { throw new CloudRuntimeException( "Download file length doesn't match: expected: " + length + ", actual: " + destFile.length()); } } protected Answer directDownloadHttpTemplate(CopyCmd cmd, DecodedDataObject srcObj, DecodedDataObject destObj) { Connection conn = hypervisorResource.getConnection(); SR poolsr = null; VDI vdi = null; boolean result = false; try { if (destObj.getPath() == null) { //need to create volume at first } vdi = VDI.getByUuid(conn, destObj.getPath()); if (vdi == null) { throw new CloudRuntimeException("can't find volume: " + destObj.getPath()); } String destStoreUuid = destObj.getStore().getUuid(); Set<SR> srs = SR.getByNameLabel(conn, destStoreUuid); if (srs.size() != 1) { throw new CloudRuntimeException("storage uuid: " + destStoreUuid + " is not unique"); } poolsr = srs.iterator().next(); VDI.Record vdir = vdi.getRecord(conn); String vdiLocation = vdir.location; String pbdLocation = null; if (destObj.getStore().getScheme().equalsIgnoreCase(DataStoreProtocol.NFS.toString())) { pbdLocation = "/run/sr-mount/" + poolsr.getUuid(conn); } else { Set<PBD> pbds = poolsr.getPBDs(conn); if (pbds.size() != 1) { throw new CloudRuntimeException("Don't how to handle multiple pbds:" + pbds.size() + " for sr: " + poolsr.getUuid(conn)); } PBD pbd = pbds.iterator().next(); Map<String, String> deviceCfg = pbd.getDeviceConfig(conn); pbdLocation = deviceCfg.get("location"); } if (pbdLocation == null) { throw new CloudRuntimeException("Can't get pbd location"); } String vdiPath = pbdLocation + "/" + vdiLocation + ".vhd"; //download a url into vdipath //downloadHttpToLocalFile(vdiPath, template.getPath()); hypervisorResource.callHostPlugin(conn, "storagePlugin", "downloadTemplateFromUrl", "destPath", vdiPath, "srcUrl", srcObj.getPath()); result = true; return new CopyCmdAnswer(cmd, vdi.getUuid(conn)); } catch (BadServerResponse e) { s_logger.debug("Failed to download template", e); } catch (XenAPIException e) { s_logger.debug("Failed to download template", e); } catch (XmlRpcException e) { s_logger.debug("Failed to download template", e); } catch (Exception e) { s_logger.debug("Failed to download template", e); } finally { if (!result && vdi != null) { try { vdi.destroy(conn); } catch (BadServerResponse e) { s_logger.debug("Failed to cleanup newly created vdi"); } catch (XenAPIException e) { s_logger.debug("Failed to cleanup newly created vdi"); } catch (XmlRpcException e) { s_logger.debug("Failed to cleanup newly created vdi"); } } } return new Answer(cmd, false, "Failed to download template"); } protected Answer execute(AttachPrimaryDataStoreCmd cmd) { String dataStoreUri = cmd.getDataStore(); Connection conn = hypervisorResource.getConnection(); try { DecodedDataObject obj = Decoder.decode(dataStoreUri); DecodedDataStore store = obj.getStore(); SR sr = hypervisorResource.getStorageRepository(conn, store.getUuid()); hypervisorResource.setupHeartbeatSr(conn, sr, false); long capacity = sr.getPhysicalSize(conn); long available = capacity - sr.getPhysicalUtilisation(conn); if (capacity == -1) { String msg = "Pool capacity is -1! pool: "; s_logger.warn(msg); return new Answer(cmd, false, msg); } AttachPrimaryDataStoreAnswer answer = new AttachPrimaryDataStoreAnswer(cmd); answer.setCapacity(capacity); answer.setUuid(sr.getUuid(conn)); answer.setAvailable(available); return answer; } catch (XenAPIException e) { String msg = "AttachPrimaryDataStoreCmd add XenAPIException:" + e.toString(); s_logger.warn(msg, e); return new Answer(cmd, false, msg); } catch (Exception e) { String msg = "AttachPrimaryDataStoreCmd failed:" + e.getMessage(); s_logger.warn(msg, e); return new Answer(cmd, false, msg); } } protected Answer execute(CopyCmd cmd) { DecodedDataObject srcObj = null; DecodedDataObject destObj = null; try { srcObj = Decoder.decode(cmd.getSrcUri()); destObj = Decoder.decode(cmd.getDestUri()); } catch (URISyntaxException e) { return new Answer(cmd, false, e.toString()); } if (srcObj.getPath().startsWith("http")) { return directDownloadHttpTemplate(cmd, srcObj, destObj); } else { return new Answer(cmd, false, "not implemented yet"); /* String tmplturl = cmd.getUrl(); String poolName = cmd.getPoolUuid(); int wait = cmd.getWait(); try { URI uri = new URI(tmplturl); String tmplpath = uri.getHost() + ":" + uri.getPath(); Connection conn = hypervisorResource.getConnection(); SR poolsr = null; Set<SR> srs = SR.getByNameLabel(conn, poolName); if (srs.size() != 1) { String msg = "There are " + srs.size() + " SRs with same name: " + poolName; s_logger.warn(msg); return new PrimaryStorageDownloadAnswer(msg); } else { poolsr = srs.iterator().next(); } String pUuid = poolsr.getUuid(conn); boolean isISCSI = IsISCSI(poolsr.getType(conn)); String uuid = copy_vhd_from_secondarystorage(conn, tmplpath, pUuid, wait); VDI tmpl = getVDIbyUuid(conn, uuid); VDI snapshotvdi = tmpl.snapshot(conn, new HashMap<String, String>()); String snapshotUuid = snapshotvdi.getUuid(conn); snapshotvdi.setNameLabel(conn, "Template " + cmd.getName()); String parentuuid = getVhdParent(conn, pUuid, snapshotUuid, isISCSI); VDI parent = getVDIbyUuid(conn, parentuuid); Long phySize = parent.getPhysicalUtilisation(conn); tmpl.destroy(conn); poolsr.scan(conn); try{ Thread.sleep(5000); } catch (Exception e) { } return new PrimaryStorageDownloadAnswer(snapshotvdi.getUuid(conn), phySize); } catch (Exception e) { String msg = "Catch Exception " + e.getClass().getName() + " on host:" + _host.uuid + " for template: " + tmplturl + " due to " + e.toString(); s_logger.warn(msg, e); return new PrimaryStorageDownloadAnswer(msg); }*/ } } }