From 66c019fa58a7c79e1fcebc9c79b2f0aaa7140c1d Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Fri, 22 May 2020 11:01:46 +0530 Subject: [PATCH 001/148] Initial commit adding few required managed object classes and added pbm sdk --- deps/install-non-oss.sh | 2 + plugins/hypervisors/vmware/pom.xml | 6 ++ vmware-base/pom.xml | 6 ++ .../vmware/mo/PbmProfileManagerMO.java | 53 +++++++++++++++++ .../vmware/mo/VirtualMachineMO.java | 10 +++- .../mo/VirtualStorageObjectManager.java | 58 +++++++++++++++++++ .../hypervisor/vmware/util/VmwareClient.java | 26 +++++++++ .../hypervisor/vmware/util/VmwareContext.java | 10 ++++ 8 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java create mode 100644 vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualStorageObjectManager.java diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh index a387050d5390..f8a526305a81 100755 --- a/deps/install-non-oss.sh +++ b/deps/install-non-oss.sh @@ -39,3 +39,5 @@ mvn install:install-file -Dfile=vim25_65.jar -DgroupId=com.cloud.com.vmwa # From https://my.vmware.com/group/vmware/details?downloadGroup=WEBCLIENTSDK67U2&productId=742 mvn install:install-file -Dfile=vim25_67.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=6.7 -Dpackaging=jar + +mvn install:install-file -Dfile=pbm_65.jar -DgroupId=com.cloud.com.vmware -DartifactId=pbm -Dversion=6.5 -Dpackaging=jar diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index f5489488f355..b0c1ca8cb799 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -72,5 +72,11 @@ wsdl4j wsdl4j + + com.cloud.com.vmware + pbm + ${cs.vmware.api.version} + compile + diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml index c84580f90b4b..925a00314007 100644 --- a/vmware-base/pom.xml +++ b/vmware-base/pom.xml @@ -75,5 +75,11 @@ ${cs.jaxws.version} pom + + com.cloud.com.vmware + pbm + ${cs.vmware.api.version} + compile + diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java new file mode 100644 index 000000000000..352cbf300279 --- /dev/null +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java @@ -0,0 +1,53 @@ +package com.cloud.hypervisor.vmware.mo; + + +import com.cloud.hypervisor.vmware.util.VmwareContext; + +import com.vmware.pbm.PbmProfile; +import com.vmware.pbm.PbmProfileId; +import com.vmware.pbm.PbmProfileResourceType; +import com.vmware.pbm.PbmProfileResourceTypeEnum; +import com.vmware.vim25.ManagedObjectReference; + +import org.apache.log4j.Logger; + +import java.util.List; + +public class PbmProfileManagerMO extends BaseMO { + + private static final Logger s_logger = Logger.getLogger(PbmProfileManagerMO.class); + + public PbmProfileManagerMO (VmwareContext context) { + super(context, context.getPbmServiceContent().getProfileManager()); + } + + public PbmProfileManagerMO (VmwareContext context, ManagedObjectReference morProfileMgr) { + super(context, morProfileMgr); + } + + public PbmProfileManagerMO (VmwareContext context, String morType, String morValue) { + super(context, morType, morValue); + } + + public List getProfileIds() throws Exception { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Querying vCenter " + _context.getServerAddress() + " for profiles"); + } + List profileIds = _context.getPbmService().pbmQueryProfile(_mor, getStorageResourceType(), null); + return profileIds; + } + + public List getProfiles(PbmProfileResourceType pbmResourceType) throws Exception { + List profileIds = getProfileIds(); + List profiles = _context.getPbmService().pbmRetrieveContent(_mor, profileIds); + return profiles; + } + + private PbmProfileResourceType getStorageResourceType() { + PbmProfileResourceType resourceType = new PbmProfileResourceType(); + resourceType.setResourceType(PbmProfileResourceTypeEnum.STORAGE.value()); + return resourceType; + } +} + + diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index d5df4b934713..da965cec5eef 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -34,6 +34,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; +import com.vmware.vim25.VStorageObject; +import com.vmware.vim25.VStorageObjectConfigInfo; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -2455,7 +2457,13 @@ public Pair getDiskDevice(String vmdkDatastorePath) throws String deviceNumbering = getDeviceBusName(devices, device); s_logger.info("Disk backing : " + diskBackingInfo.getFileName() + " matches ==> " + deviceNumbering); - + if (((VirtualDisk) device).getVDiskId() == null) { + s_logger.debug("vDiskid does not exist for volume " + vmdkDatastorePath + " registering the disk now"); + VirtualStorageObjectManager vStorageObjectManagerMO = new VirtualStorageObjectManager(getOwnerDatacenter().first().getContext()); + VStorageObject vStorageObject = vStorageObjectManagerMO.registerVirtualDisk(dsBackingFile, null, getOwnerDatacenter().first().getName()); + VStorageObjectConfigInfo diskConfigInfo = vStorageObject.getConfig(); + ((VirtualDisk) device).setVDiskId(diskConfigInfo.getId()); + } return new Pair<>((VirtualDisk)device, deviceNumbering); } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualStorageObjectManager.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualStorageObjectManager.java new file mode 100644 index 000000000000..0b6f44ae0b0d --- /dev/null +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualStorageObjectManager.java @@ -0,0 +1,58 @@ +// 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.vmware.mo; + +import com.vmware.vim25.ID; +import com.vmware.vim25.VStorageObject; +import org.apache.log4j.Logger; + +import com.vmware.vim25.ManagedObjectReference; + +import com.cloud.hypervisor.vmware.util.VmwareContext; + +public class VirtualStorageObjectManager extends BaseMO { + @SuppressWarnings("unused") + private static final Logger s_logger = Logger.getLogger(VirtualStorageObjectManager.class); + + public VirtualStorageObjectManager(VmwareContext context) { + super(context, context.getServiceContent().getVStorageObjectManager()); + } + + public VirtualStorageObjectManager(VmwareContext context, ManagedObjectReference morDiskMgr) { + super(context, morDiskMgr); + } + + public VirtualStorageObjectManager(VmwareContext context, String morType, String morValue) { + super(context, morType, morValue); + } + + public VStorageObject registerVirtualDisk(DatastoreFile datastoreFile, String name, String dcName) throws Exception { + StringBuilder sb = new StringBuilder(); + //https://10.2.2.254/folder/i-2-4-VM/89e3756d9b7444dc92388eb36ddd026b.vmdk?dcPath=datacenter-21&dsName=c84e4af9b6ac33e887a25d9242650091 + sb.append("https://").append(_context.getServerAddress()).append("/folder/"); + sb.append(datastoreFile.getRelativePath()); + sb.append("?dcPath="); + sb.append(dcName); + sb.append("&dsName="); + sb.append(datastoreFile.getDatastoreName()); + return _context.getService().registerDisk(_mor, sb.toString(), name); + } + + public VStorageObject retrieveVirtualDisk (ID id, ManagedObjectReference morDS) throws Exception { + return _context.getService().retrieveVStorageObject(_mor, id, morDS); + } +} diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java index 3d80ffdfae74..376afb1dbe71 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java @@ -32,6 +32,8 @@ import org.apache.cloudstack.utils.security.SSLUtils; import org.apache.cloudstack.utils.security.SecureSSLSocketFactory; +import com.vmware.pbm.PbmPortType; +import com.vmware.pbm.PbmServiceInstanceContent; import org.apache.log4j.Logger; import org.w3c.dom.Element; @@ -120,8 +122,14 @@ private static void trustAllHttpsCertificates() throws Exception { } private final ManagedObjectReference svcInstRef = new ManagedObjectReference(); + private final ManagedObjectReference pbmSvcInstRef = new ManagedObjectReference(); + private static VimService vimService; private VimPortType vimPort; + private PbmPortType pbmPort; + private static final String PBM_SERVICE_INSTANCE_TYPE = "PbmServiceInstance"; + private static final String PBM_SERVICE_INSTANCE_VALUE = "ServiceInstance"; + private String serviceCookie; private final static String SVC_INST_NAME = "ServiceInstance"; private int vCenterSessionTimeout = 1200000; // Timeout in milliseconds @@ -211,6 +219,24 @@ public ServiceContent getServiceContent() { return null; } + /** + * @return PBM service instance + */ + public PbmPortType getPbmService() { + return pbmPort; + } + + /** + * @return Service instance content + */ + public PbmServiceInstanceContent getPbmServiceContent() { + try { + return pbmPort.pbmRetrieveServiceContent(pbmSvcInstRef); + } catch (com.vmware.pbm.RuntimeFaultFaultMsg e) { + } + return null; + } + /** * @return cookie used in service connection */ diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java index 9b477aef42bc..33b9644a3077 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java @@ -20,6 +20,8 @@ import com.cloud.hypervisor.vmware.mo.DatastoreFile; import com.cloud.utils.ActionDelegate; import com.cloud.utils.StringUtils; +import com.vmware.pbm.PbmPortType; +import com.vmware.pbm.PbmServiceInstanceContent; import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.ObjectContent; import com.vmware.vim25.ObjectSpec; @@ -148,6 +150,14 @@ public ServiceContent getServiceContent() { return _vimClient.getServiceContent(); } + public PbmPortType getPbmService() { + return _vimClient.getPbmService(); + } + + public PbmServiceInstanceContent getPbmServiceContent() { + return _vimClient.getPbmServiceContent(); + } + public ManagedObjectReference getPropertyCollector() { return _vimClient.getPropCol(); } From 76c183b9abb81482bf7744cd1a58f18acec945f7 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 26 May 2020 19:09:40 +0530 Subject: [PATCH 002/148] Added PBM service connect --- .../vmware/mo/HypervisorHostHelper.java | 2 +- .../vmware/mo/PbmProfileManagerMO.java | 17 +++- .../vmware/util/VcenterSessionHandler.java | 88 +++++++++++++++++++ .../hypervisor/vmware/util/VmwareClient.java | 41 ++++++++- 4 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VcenterSessionHandler.java diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index d9604ac01e21..78a348a3a6db 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -1738,7 +1738,7 @@ public static String removeOVFNetwork(final String ovfString) { return ovfString; } - public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, ManagedObjectReference morRp, + public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, ManagedObjectReference morRp, ManagedObjectReference morHost) throws Exception { assert (morRp != null); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java index 352cbf300279..31a7a44deea0 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java @@ -1,6 +1,21 @@ +// 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.vmware.mo; - import com.cloud.hypervisor.vmware.util.VmwareContext; import com.vmware.pbm.PbmProfile; diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VcenterSessionHandler.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VcenterSessionHandler.java new file mode 100644 index 000000000000..9efab7b8eceb --- /dev/null +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VcenterSessionHandler.java @@ -0,0 +1,88 @@ +// 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.vmware.util; + +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPHeader; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.soap.SOAPHandler; +import javax.xml.ws.handler.soap.SOAPMessageContext; + +import org.apache.log4j.Logger; +import org.w3c.dom.DOMException; + +import com.cloud.utils.exception.CloudRuntimeException; + +public class VcenterSessionHandler implements SOAPHandler { + public static final Logger s_logger = Logger.getLogger(VcenterSessionHandler.class); + private final String vcSessionCookie; + + public VcenterSessionHandler(String vcSessionCookie) { + this.vcSessionCookie = vcSessionCookie; + } + + @Override + public boolean handleMessage(SOAPMessageContext smc) { + if (isOutgoingMessage(smc)) { + try { + SOAPHeader header = getSOAPHeader(smc); + + SOAPElement vcsessionHeader = header.addChildElement(new javax.xml.namespace.QName("#", + "vcSessionCookie")); + vcsessionHeader.setValue(vcSessionCookie); + + } catch (DOMException e) { + s_logger.debug(e); + throw new CloudRuntimeException(e); + } catch (SOAPException e) { + s_logger.debug(e); + throw new CloudRuntimeException(e); + } + } + return true; + } + + @Override + public void close(MessageContext arg0) { + } + + @Override + public boolean handleFault(SOAPMessageContext arg0) { + return false; + } + + @Override + public Set getHeaders() { + return null; + } + + SOAPHeader getSOAPHeader(SOAPMessageContext smc) throws SOAPException { + return smc.getMessage().getSOAPPart().getEnvelope().getHeader() == null ? smc + .getMessage().getSOAPPart().getEnvelope().addHeader() + : smc.getMessage().getSOAPPart().getEnvelope().getHeader(); + } + + boolean isOutgoingMessage(SOAPMessageContext smc) { + Boolean outboundProperty = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); + return outboundProperty; + } + +} diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java index 376afb1dbe71..2395ccf53262 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareClient.java @@ -17,8 +17,11 @@ package com.cloud.hypervisor.vmware.util; import java.lang.reflect.Method; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -29,10 +32,15 @@ import javax.xml.ws.BindingProvider; import javax.xml.ws.WebServiceException; import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.Handler; +import javax.xml.ws.handler.HandlerResolver; +import javax.xml.ws.handler.PortInfo; + import org.apache.cloudstack.utils.security.SSLUtils; import org.apache.cloudstack.utils.security.SecureSSLSocketFactory; import com.vmware.pbm.PbmPortType; +import com.vmware.pbm.PbmService; import com.vmware.pbm.PbmServiceInstanceContent; import org.apache.log4j.Logger; import org.w3c.dom.Element; @@ -103,6 +111,7 @@ public boolean verify(String urlHostName, SSLSession session) { HttpsURLConnection.setDefaultHostnameVerifier(hv); vimService = new VimService(); + pbmService = new PbmService(); } catch (Exception e) { s_logger.info("[ignored]" + "failed to trust all certificates blindly: ", e); @@ -125,6 +134,8 @@ private static void trustAllHttpsCertificates() throws Exception { private final ManagedObjectReference pbmSvcInstRef = new ManagedObjectReference(); private static VimService vimService; + private static PbmService pbmService; + private PbmServiceInstanceContent pbmServiceContent; private VimPortType vimPort; private PbmPortType pbmPort; private static final String PBM_SERVICE_INSTANCE_TYPE = "PbmServiceInstance"; @@ -184,10 +195,38 @@ public void connect(String url, String userName, String password) throws Excepti cookieValue = tokenizer.nextToken(); String pathData = "$" + tokenizer.nextToken(); serviceCookie = "$Version=\"1\"; " + cookieValue + "; " + pathData; - + Map> map = new HashMap>(); + map.put("Cookie", Collections.singletonList(serviceCookie)); + ((BindingProvider)vimPort).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, map); + pbmConnect(url, cookieValue); isConnected = true; } + private void pbmConnect(String url, String cookieValue) throws Exception { + URI uri = new URI(url); + String pbmurl = "https://" + uri.getHost() + "/pbm"; + String[] tokens = cookieValue.split("="); + String extractedCookie = tokens[1]; + + HandlerResolver soapHandlerResolver = new HandlerResolver() { + @Override + public List getHandlerChain(PortInfo portInfo) { + VcenterSessionHandler VcSessionHandler = new VcenterSessionHandler(extractedCookie); + List handlerChain = new ArrayList(); + handlerChain.add((Handler)VcSessionHandler); + return handlerChain; + } + }; + pbmService.setHandlerResolver(soapHandlerResolver); + + pbmSvcInstRef.setType(PBM_SERVICE_INSTANCE_TYPE); + pbmSvcInstRef.setValue(PBM_SERVICE_INSTANCE_VALUE); + pbmPort = pbmService.getPbmPort(); + Map pbmCtxt = ((BindingProvider)pbmPort).getRequestContext(); + pbmCtxt.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true); + pbmCtxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, pbmurl); + } + /** * Disconnects the user session. * From 1db6d78e7ee67ef834c8c16c0b0ab1a897837481 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 28 May 2020 15:16:17 +0200 Subject: [PATCH 003/148] pokemon anihilation and class-javadoc --- .../java/com/cloud/storage/template/OVAProcessor.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java index d771c67acec6..c3b9262affc5 100644 --- a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java +++ b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java @@ -20,11 +20,13 @@ package com.cloud.storage.template; import java.io.File; +import java.io.IOException; import java.util.List; import java.util.Map; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import com.cloud.agent.api.storage.OVFPropertyTO; import org.apache.commons.collections.CollectionUtils; @@ -32,6 +34,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import com.cloud.agent.api.storage.OVFHelper; import com.cloud.agent.api.to.DatadiskTO; @@ -42,6 +45,9 @@ import com.cloud.utils.component.AdapterBase; import com.cloud.utils.script.Script; +/** + * processes the content of an OVA for registration of a template + */ public class OVAProcessor extends AdapterBase implements Processor { private static final Logger s_logger = Logger.getLogger(OVAProcessor.class); StorageLayer _storage; @@ -113,7 +119,7 @@ public FormatInfo process(String templatePath, ImageFormat format, String templa s_logger.info("Found " + ovfProperties.size() + " configurable OVF properties"); info.ovfProperties = ovfProperties; } - } catch (Exception e) { + } catch (ParserConfigurationException | IOException | SAXException e) { s_logger.info("The ovf file " + ovfFile + " is invalid ", e); throw new InternalErrorException("OVA package has bad ovf file " + e.getMessage(), e); } From 32aa5801c78fba9fb2f16c3ce9e2f7374d7a9750 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Thu, 28 May 2020 16:02:35 +0530 Subject: [PATCH 004/148] Fix root folder issue on datastore --- deps/install-non-oss.sh | 1 + .../hypervisor/vmware/resource/VmwareResource.java | 4 +++- .../storage/resource/VmwareStorageLayoutHelper.java | 6 ++++++ .../com/cloud/hypervisor/vmware/mo/DatastoreMO.java | 8 +++++++- .../java/com/cloud/hypervisor/vmware/mo/HostMO.java | 6 +++++- .../hypervisor/vmware/mo/HypervisorHostHelper.java | 11 +++++++++++ 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh index f8a526305a81..f1c63c4a95f6 100755 --- a/deps/install-non-oss.sh +++ b/deps/install-non-oss.sh @@ -40,4 +40,5 @@ mvn install:install-file -Dfile=vim25_65.jar -DgroupId=com.cloud.com.vmwa # From https://my.vmware.com/group/vmware/details?downloadGroup=WEBCLIENTSDK67U2&productId=742 mvn install:install-file -Dfile=vim25_67.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=6.7 -Dpackaging=jar +# From https://my.vmware.com/group/vmware/get-download?downloadGroup=VS-MGMT-SDK65 mvn install:install-file -Dfile=pbm_65.jar -DgroupId=com.cloud.com.vmware -DartifactId=pbm -Dversion=6.5 -Dpackaging=jar diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index aebda554a938..641fc60f416e 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -4902,8 +4902,10 @@ protected Answer execute(ModifyStoragePoolCommand cmd) { assert (morDatastore != null); - DatastoreSummary summary = new DatastoreMO(getServiceContext(), morDatastore).getSummary(); + DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDatastore); + HypervisorHostHelper.createBaseFolderInDatastore(dsMo, hyperHost); + DatastoreSummary summary = dsMo.getSummary(); long capacity = summary.getCapacity(); long available = summary.getFreeSpace(); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageLayoutHelper.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageLayoutHelper.java index 9b2acbc5179e..a422fedb25f7 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageLayoutHelper.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageLayoutHelper.java @@ -23,6 +23,8 @@ import com.cloud.hypervisor.vmware.mo.DatacenterMO; import com.cloud.hypervisor.vmware.mo.DatastoreFile; import com.cloud.hypervisor.vmware.mo.DatastoreMO; +import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; + import com.cloud.utils.Pair; /** @@ -309,6 +311,10 @@ public static void deleteVolumeVmdkFiles(DatastoreMO dsMo, String volumeName, Da } public static String getLegacyDatastorePathFromVmdkFileName(DatastoreMO dsMo, String vmdkFileName) throws Exception { + return String.format("[%s] %s/%s", dsMo.getName(), HypervisorHostHelper.VSPHERE_DATASTORE_BASE_FOLDER, vmdkFileName); + } + + public static String getDeprecatedLegacyDatastorePathFromVmdkFileName(DatastoreMO dsMo, String vmdkFileName) throws Exception { return String.format("[%s] %s", dsMo.getName(), vmdkFileName); } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java index fa0c380eb062..d0d3a5bb28d1 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java @@ -258,6 +258,12 @@ public boolean moveDatastoreFile(String srcFilePath, ManagedObjectReference morS if (!DatastoreFile.isFullDatastorePath(destFullPath)) destFullPath = String.format("[%s] %s", destDsName, destFilePath); + DatastoreMO srcDsMo = new DatastoreMO(_context, morDestDs); + if (!srcDsMo.fileExists(srcFullPath)) { + s_logger.error(String.format("Cannot move file to destination datastore due to file %s does not exists", srcFullPath)); + return false; + } + ManagedObjectReference morTask = _context.getService().moveDatastoreFileTask(morFileManager, srcFullPath, morSrcDc, destFullPath, morDestDc, forceOverwrite); boolean result = _context.getVimClient().waitForTask(morTask); @@ -265,7 +271,7 @@ public boolean moveDatastoreFile(String srcFilePath, ManagedObjectReference morS _context.waitForTaskProgressDone(morTask); return true; } else { - s_logger.error("VMware moveDatgastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + s_logger.error("VMware moveDatastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask)); } return false; } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java index 7877db980f46..65b1572598fd 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -839,6 +839,7 @@ public ManagedObjectReference mountDatastore(boolean vmfsDatastore, String poolH s_logger.trace("vCenter API trace - mountDatastore(). target MOR: " + _mor.getValue() + ", vmfs: " + vmfsDatastore + ", poolHost: " + poolHostAddress + ", poolHostPort: " + poolHostPort + ", poolPath: " + poolPath + ", poolUuid: " + poolUuid); + DatastoreMO dsMo = null; HostDatastoreSystemMO hostDatastoreSystemMo = getHostDatastoreSystemMO(); ManagedObjectReference morDatastore = hostDatastoreSystemMo.findDatastore(poolUuid); if (morDatastore == null) { @@ -865,6 +866,7 @@ public ManagedObjectReference mountDatastore(boolean vmfsDatastore, String poolH s_logger.trace("vCenter API trace - mountDatastore() done(failed)"); throw new Exception(msg); } + dsMo = new DatastoreMO(_context, morDatastore); } else { morDatastore = _context.getDatastoreMorByPath(poolPath); if (morDatastore == null) { @@ -876,11 +878,13 @@ public ManagedObjectReference mountDatastore(boolean vmfsDatastore, String poolH throw new Exception(msg); } - DatastoreMO dsMo = new DatastoreMO(_context, morDatastore); + dsMo = new DatastoreMO(_context, morDatastore); dsMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, poolUuid); } } + HypervisorHostHelper.createBaseFolderInDatastore(dsMo, this); + if (s_logger.isTraceEnabled()) s_logger.trace("vCenter API trace - mountDatastore() done(successfully)"); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index 78a348a3a6db..b109efde6adb 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -138,6 +138,7 @@ public class HypervisorHostHelper { private static final String UNTAGGED_VLAN_NAME = "untagged"; private static final String VMDK_PACK_DIR = "ova"; private static final String OVA_OPTION_KEY_BOOTDISK = "cloud.ova.bootdisk"; + public static final String VSPHERE_DATASTORE_BASE_FOLDER = ".cloudstack.base.folder"; public static VirtualMachineMO findVmFromObjectContent(VmwareContext context, ObjectContent[] ocs, String name, String instanceNameCustomField) { @@ -171,6 +172,7 @@ public static ManagedObjectReference findDatastoreWithBackwardsCompatibility(Vmw if (morDs == null) morDs = hyperHost.findDatastore(uuidName); + DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs); return morDs; } @@ -2077,4 +2079,13 @@ public static boolean isIdeController(String controller) { return DiskControllerType.getType(controller) == DiskControllerType.ide; } + public static void createBaseFolderInDatastore(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception { + String dsPath = String.format("[%s]", dsMo.getName()); + String folderPath = String.format("[%s] %s", dsMo.getName(), VSPHERE_DATASTORE_BASE_FOLDER); + + if (!dsMo.folderExists(dsPath, VSPHERE_DATASTORE_BASE_FOLDER)) { + s_logger.info(String.format("vSphere datastore base folder: %s does not exist, now creating on datastore: %s", VSPHERE_DATASTORE_BASE_FOLDER, dsMo.getName())); + dsMo.makeDirectory(folderPath, hyperHost.getHyperHostDatacenter()); + } + } } From f2ea28cd1a53a25be346d12a4e638f5c48e98a0b Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 29 May 2020 12:38:40 +0000 Subject: [PATCH 005/148] add ovf properties to template details --- .../image/BaseImageStoreDriverImpl.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index dec9b76dbc84..8013a0dbe942 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -29,9 +29,11 @@ import com.cloud.agent.api.storage.OVFPropertyTO; import com.cloud.storage.Upload; +import com.cloud.storage.VMTemplateDetailVO; import com.cloud.storage.dao.TemplateOVFPropertiesDao; import com.cloud.storage.TemplateOVFPropertyVO; import com.cloud.utils.crypt.DBEncryptionUtil; +import com.google.gson.Gson; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -97,7 +99,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { @Inject AlertManager _alertMgr; @Inject - VMTemplateDetailsDao _templateDetailsDao; + VMTemplateDetailsDao templateDetailsDao; @Inject DefaultEndPointSelector _defaultEpSelector; @Inject @@ -109,6 +111,8 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { protected String _proxy = null; + private static Gson gson; + protected Proxy getHttpProxy() { if (_proxy == null) { return null; @@ -173,8 +177,17 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal * Persist OVF properties as template details for template with id = templateId */ private void persistOVFProperties(List ovfProperties, long templateId) { + List templateDetailsList = new ArrayList<>(); + for (OVFPropertyTO property : ovfProperties) { + persistOvfPropertyAsTemplateDetail(templateId, property); + } + persistOvfPropertiesInDedicatedTable(ovfProperties, templateId); + } + + private void persistOvfPropertiesInDedicatedTable(List ovfProperties, long templateId) { List listToPersist = new ArrayList<>(); for (OVFPropertyTO property : ovfProperties) { + persistOvfPropertyAsTemplateDetail(templateId, property); if (!templateOvfPropertiesDao.existsOption(templateId, property.getKey())) { TemplateOVFPropertyVO option = new TemplateOVFPropertyVO(templateId, property.getKey(), property.getType(), property.getValue(), property.getQualifiers(), property.isUserConfigurable(), @@ -192,6 +205,15 @@ private void persistOVFProperties(List ovfProperties, long templa } } + private void persistOvfPropertyAsTemplateDetail(long templateId, OVFPropertyTO property) { + String key = "ovfProperty-" + property.getKey(); + templateDetailsDao.removeDetail(templateId,key); + String json = gson.toJson(property); + VMTemplateDetailVO detailVO = new VMTemplateDetailVO(templateId, key, json, property.isUserConfigurable()); + s_logger.debug("Persisting template details " + detailVO.getName() + " from OVF properties for template " + templateId); + templateDetailsDao.persist(detailVO); + } + protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher callback, CreateContext context) { if (s_logger.isDebugEnabled()) { From 8311a54e8ffb1b3d867a8b55a37597bd67819982 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 29 May 2020 12:56:06 +0000 Subject: [PATCH 006/148] disected ova processing --- .../cloud/storage/template/OVAProcessor.java | 106 ++++++++++++------ 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java index c3b9262affc5..fc31424454e9 100644 --- a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java +++ b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java @@ -29,6 +29,7 @@ import javax.xml.parsers.ParserConfigurationException; import com.cloud.agent.api.storage.OVFPropertyTO; +import com.cloud.storage.Storage; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.w3c.dom.Document; @@ -59,10 +60,7 @@ public FormatInfo process(String templatePath, ImageFormat format, String templa @Override public FormatInfo process(String templatePath, ImageFormat format, String templateName, long processTimeout) throws InternalErrorException { - if (format != null) { - if (s_logger.isInfoEnabled()) { - s_logger.info("We currently don't handle conversion from " + format + " to OVA."); - } + if (! conversionChecks(format)){ return null; } @@ -75,44 +73,41 @@ public FormatInfo process(String templatePath, ImageFormat format, String templa return null; } - s_logger.info("Template processing - untar OVA package. templatePath: " + templatePath + ", templateName: " + templateName); - String templateFileFullPath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension(); - File templateFile = new File(templateFileFullPath); - Script command = new Script("tar", processTimeout, s_logger); - command.add("--no-same-owner"); - command.add("--no-same-permissions"); - command.add("-xf", templateFileFullPath); - command.setWorkDir(templateFile.getParent()); - String result = command.execute(); - if (result != null) { - s_logger.info("failed to untar OVA package due to " + result + ". templatePath: " + templatePath + ", templateName: " + templateName); - throw new InternalErrorException("failed to untar OVA package"); - } + String templateFileFullPath = unpackOva(templatePath, templateName, processTimeout); - command = new Script("chmod", 0, s_logger); - command.add("-R"); - command.add("666", templatePath); - result = command.execute(); - if (result != null) { - s_logger.warn("Unable to set permissions for files in " + templatePath + " due to " + result); - } - command = new Script("chmod", 0, s_logger); - command.add("777", templatePath); - result = command.execute(); - if (result != null) { - s_logger.warn("Unable to set permissions for " + templatePath + " due to " + result); - } + setFileSystemAccessRights(templatePath); + FormatInfo info = createFormatInfo(templatePath, templateName, templateFilePath, templateFileFullPath); + // The intention is to use the ova file as is for deployment and use done processing only for + // - property assessment and + // - reconsiliation of + // - - disks, + // - - networks and + // - - compute dimensions. + return info; + } + + private FormatInfo createFormatInfo(String templatePath, String templateName, String templateFilePath, String templateFileFullPath) throws InternalErrorException { FormatInfo info = new FormatInfo(); info.format = ImageFormat.OVA; info.filename = templateName + "." + ImageFormat.OVA.getFileExtension(); info.size = _storage.getSize(templateFilePath); info.virtualSize = getTemplateVirtualSize(templatePath, info.filename); + validateOva(templateFileFullPath, info); - //vaidate ova + return info; + } + + /** + * side effect; properties are added to the info + * + * @throws InternalErrorException on an invalid ova contents + */ + private void validateOva(String templateFileFullPath, FormatInfo info) throws InternalErrorException { String ovfFile = getOVFFilePath(templateFileFullPath); try { OVFHelper ovfHelper = new OVFHelper(); + // TDOD assess side effects of this call, remove capture of return value and optionally remove or simplify called method List disks = ovfHelper.getOVFVolumeInfo(ovfFile); List ovfProperties = ovfHelper.getOVFPropertiesFromFile(ovfFile); if (CollectionUtils.isNotEmpty(ovfProperties)) { @@ -123,9 +118,52 @@ public FormatInfo process(String templatePath, ImageFormat format, String templa s_logger.info("The ovf file " + ovfFile + " is invalid ", e); throw new InternalErrorException("OVA package has bad ovf file " + e.getMessage(), e); } - // delete original OVA file - // templateFile.delete(); - return info; + } + + private void setFileSystemAccessRights(String templatePath) { + Script command; + String result; + + command = new Script("chmod", 0, s_logger); + command.add("-R"); + command.add("666", templatePath); + result = command.execute(); + if (result != null) { + s_logger.warn("Unable to set permissions for files in " + templatePath + " due to " + result); + } + command = new Script("chmod", 0, s_logger); + command.add("777", templatePath); + result = command.execute(); + if (result != null) { + s_logger.warn("Unable to set permissions for " + templatePath + " due to " + result); + } + } + + private String unpackOva(String templatePath, String templateName, long processTimeout) throws InternalErrorException { + s_logger.info("Template processing - untar OVA package. templatePath: " + templatePath + ", templateName: " + templateName); + String templateFileFullPath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension(); + File templateFile = new File(templateFileFullPath); + Script command = new Script("tar", processTimeout, s_logger); + command.add("--no-same-owner"); + command.add("--no-same-permissions"); + command.add("-xf", templateFileFullPath); + command.setWorkDir(templateFile.getParent()); + String result = command.execute(); + if (result != null) { + s_logger.info("failed to untar OVA package due to " + result + ". templatePath: " + templatePath + ", templateName: " + templateName); + throw new InternalErrorException("failed to untar OVA package"); + } + return templateFileFullPath; + } + + private boolean conversionChecks(ImageFormat format) { + if (format != null) { + if (s_logger.isInfoEnabled()) { + s_logger.info("We currently don't handle conversion from " + format + " to OVA."); + } + return false; + } + return true; } @Override From 4772813b472bc2e6939d514f0015d319e30cf9ee Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Wed, 3 Jun 2020 07:43:48 +0000 Subject: [PATCH 007/148] import --- core/src/main/java/com/cloud/storage/template/OVAProcessor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java index fc31424454e9..bf4fb3f020ae 100644 --- a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java +++ b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java @@ -29,7 +29,6 @@ import javax.xml.parsers.ParserConfigurationException; import com.cloud.agent.api.storage.OVFPropertyTO; -import com.cloud.storage.Storage; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import org.w3c.dom.Document; From 50678dba3851448fb83780e44e1dd672657540c2 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Mon, 1 Jun 2020 11:17:33 +0530 Subject: [PATCH 008/148] Added importVsphereStoragePolicies API and scheme changes --- .../com/cloud/dc/VsphereStoragePolicy.java | 31 +++++ .../main/java/com/cloud/event/EventTypes.java | 5 + .../META-INF/db/schema-41400to41500.sql | 17 ++- .../vmware/VmwareDatacenterService.java | 3 + .../vmware/VsphereStoragePolicy.java | 31 +++++ .../vmware/VsphereStoragePolicyVO.java | 108 ++++++++++++++++++ .../vmware/dao/VsphereStoragePolicyDao.java | 23 ++++ .../dao/VsphereStoragePolicyDaoImpl.java | 23 ++++ .../vmware/manager/VmwareManagerImpl.java | 53 +++++++++ .../zone/ImportVsphereStoragePoliciesCmd.java | 106 +++++++++++++++++ .../ImportVsphereStoragePoliciesResponse.java | 89 +++++++++++++++ .../vmware/mo/PbmProfileManagerMO.java | 6 +- 12 files changed, 491 insertions(+), 4 deletions(-) create mode 100644 api/src/main/java/com/cloud/dc/VsphereStoragePolicy.java create mode 100644 plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java create mode 100644 plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java create mode 100644 plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java create mode 100644 plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java create mode 100644 plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java create mode 100644 plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java diff --git a/api/src/main/java/com/cloud/dc/VsphereStoragePolicy.java b/api/src/main/java/com/cloud/dc/VsphereStoragePolicy.java new file mode 100644 index 000000000000..ca0ed5447003 --- /dev/null +++ b/api/src/main/java/com/cloud/dc/VsphereStoragePolicy.java @@ -0,0 +1,31 @@ +// 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.dc; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface VsphereStoragePolicy extends Identity, InternalIdentity { + + long getZoneId(); + + String getPolicyId(); + + String getName(); + + String getDescription(); +} diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 5ea31a781786..19de913d9d9a 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -605,6 +605,9 @@ public class EventTypes { public static final String EVENT_POD_ROLLING_MAINTENANCE = "POD.ROLLING.MAINTENANCE"; public static final String EVENT_ZONE_ROLLING_MAINTENANCE = "ZONE.ROLLING.MAINTENANCE"; + // Storage Policies + public static final String EVENT_IMPORT_VCENTER_STORAGE_POLICIES = "IMPORT.VCENTER.STORAGE.POLICIES"; + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking @@ -1011,6 +1014,8 @@ public class EventTypes { entityEventDetails.put(EVENT_POD_ROLLING_MAINTENANCE, PodResponse.class); entityEventDetails.put(EVENT_CLUSTER_ROLLING_MAINTENANCE, ClusterResponse.class); entityEventDetails.put(EVENT_HOST_ROLLING_MAINTENANCE, HostResponse.class); + + entityEventDetails.put(EVENT_IMPORT_VCENTER_STORAGE_POLICIES, "StoragePolicies"); } public static String getEntityForEvent(String eventName) { diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index 6ec5dcd5b818..80cf7e43eb9f 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -31,4 +31,19 @@ UPDATE `cloud`.`roles` SET `is_default` = 1 WHERE id IN (1, 2, 3, 4); INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Read-Only Admin - Default', 'Admin', 'Default read-only admin role', 1); INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Read-Only User - Default', 'User', 'Default read-only user role', 1); INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Support Admin - Default', 'Admin', 'Default support admin role', 1); -INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Support User - Default', 'User', 'Default support user role', 1); \ No newline at end of file +INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Support User - Default', 'User', 'Default support user role', 1); + +CREATE TABLE IF NOT EXISTS `cloud`.`vsphere_storage_policy` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `zone_id` bigint(20) unsigned NOT NULL COMMENT 'id of the zone', + `policy_id` varchar(255) NOT NULL COMMENT 'the identifier of the Storage Policy in vSphere DataCenter', + `name` varchar(255) NOT NULL COMMENT 'name of the storage policy', + `description` text COMMENT 'description of the storage policy', + `update_time` datetime COMMENT 'last updated when policy imported', + `removed` datetime COMMENT 'date removed', + PRIMARY KEY (`id`), + KEY `fk_vsphere_storage_policy__zone_id` (`zone_id`), + UNIQUE KEY (`zone_id`, `policy_id`), + CONSTRAINT `fk_vsphere_storage_policy__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java index 53792539ee8e..7810cb38632c 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java @@ -20,6 +20,7 @@ import java.util.List; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; +import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.UpdateVmwareDcCmd; @@ -38,4 +39,6 @@ public interface VmwareDatacenterService extends PluggableService { boolean removeVmwareDatacenter(RemoveVmwareDcCmd cmd) throws IllegalArgumentException, ResourceInUseException; List listVmwareDatacenters(ListVmwareDcsCmd cmd) throws IllegalArgumentException, CloudRuntimeException; + + List importVsphereStoragePolicies(ImportVsphereStoragePoliciesCmd cmd); } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java new file mode 100644 index 000000000000..102bdaa3c04c --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java @@ -0,0 +1,31 @@ +// 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.vmware; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface VsphereStoragePolicy extends Identity, InternalIdentity { + + long getZoneId(); + + String getPolicyId(); + + String getName(); + + String getDescription(); +} diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java new file mode 100644 index 000000000000..bc07b886719c --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java @@ -0,0 +1,108 @@ +// 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.vmware; + +import com.cloud.utils.db.GenericDao; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; +import java.util.UUID; + +@Entity +@Table(name = "vsphere_storage_policy") +public class VsphereStoragePolicyVO implements VsphereStoragePolicy { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "zone_id") + private long zoneId; + + @Column(name = "policy_id") + private String policyId; + + @Column(name = "name") + private String name; + + @Column(name = "description") + private String description; + + @Column(name = "update_time", updatable = true) + @Temporal(value = TemporalType.TIMESTAMP) + private Date updateTime; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + public VsphereStoragePolicyVO(long zoneId, String policyId, String name, String description) { + this.uuid = UUID.randomUUID().toString(); + this.zoneId = zoneId; + this.policyId = policyId; + this.name = name; + this.description = description; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getZoneId() { + return zoneId; + } + + @Override + public String getPolicyId() { + return policyId; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return description; + } + + public Date getUpdateTime() { + return updateTime; + } + + public Date getRemoved() { + return removed; + } +} diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java new file mode 100644 index 000000000000..14f77af9bd8c --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java @@ -0,0 +1,23 @@ +// 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.vmware.dao; + +import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; +import com.cloud.utils.db.GenericDao; + +public interface VsphereStoragePolicyDao extends GenericDao { +} diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java new file mode 100644 index 000000000000..2d13eff0c5b9 --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java @@ -0,0 +1,23 @@ +// 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.vmware.dao; + +import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; +import com.cloud.utils.db.GenericDaoBase; + +public class VsphereStoragePolicyDaoImpl extends GenericDaoBase implements VsphereStoragePolicyDao { +} diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index c4b939a11493..cc5e9a3ab284 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -38,7 +38,13 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.hypervisor.vmware.VsphereStoragePolicy; +import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; +import com.cloud.hypervisor.vmware.dao.VsphereStoragePolicyDao; +import com.cloud.hypervisor.vmware.mo.PbmProfileManagerMO; +import com.vmware.pbm.PbmProfile; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; +import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.UpdateVmwareDcCmd; @@ -208,6 +214,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private UserVmCloneSettingDao cloneSettingDao; @Inject private TemplateManager templateManager; + @Inject + private VsphereStoragePolicyDao vsphereStoragePolicyDao; private String _mountParent; private StorageLayer _storage; @@ -1383,6 +1391,51 @@ private void doesZoneExist(Long zoneId) throws InvalidParameterValueException { } } + @Override + public List importVsphereStoragePolicies(ImportVsphereStoragePoliciesCmd cmd) { + Long zoneId = cmd.getZoneId(); + // Validate Id of zone + doesZoneExist(zoneId); + + // Get DC associated with this zone + VmwareDatacenterVO vmwareDatacenter; + String vmwareDcName; + String vCenterHost; + String userName; + String password; + DatacenterMO dcMo = null; + final VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId); + // Check if zone is associated with VMware DC + if (vmwareDcZoneMap == null) { + throw new CloudRuntimeException("Zone " + zoneId + " is not associated with any VMware datacenter."); + } + + final long vmwareDcId = vmwareDcZoneMap.getVmwareDcId(); + vmwareDatacenter = vmwareDcDao.findById(vmwareDcId); + vmwareDcName = vmwareDatacenter.getVmwareDatacenterName(); + vCenterHost = vmwareDatacenter.getVcenterHost(); + userName = vmwareDatacenter.getUser(); + password = vmwareDatacenter.getPassword(); + List storageProfiles = null; + try { + VmwareContext context = VmwareContextFactory.getContext(vCenterHost, userName, password); + PbmProfileManagerMO profileManagerMO = new PbmProfileManagerMO(context); + storageProfiles = profileManagerMO.getStorageProfiles(); + } catch (Exception e) { + String msg = String.format("Unable to list storage profiles from DC %s due to : %s", vmwareDcName, VmwareHelper.getExceptionMessage(e); + s_logger.error(msg); + throw new CloudRuntimeException(msg); + } + + for (PbmProfile storageProfile : storageProfiles) { + VsphereStoragePolicyVO StoragePolicyVO = new VsphereStoragePolicyVO(zoneId, storageProfile.getProfileId().toString(), storageProfile.getName(), storageProfile.getDescription()); + vsphereStoragePolicyDao.persist(StoragePolicyVO); + } + + List storagePolicies = vsphereStoragePolicyDao.listAll(); + return storagePolicies; + } + @Override public boolean hasNexusVSM(Long clusterId) { ClusterVSMMapVO vsmMapVo = null; diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java new file mode 100644 index 000000000000..cff37f50d3f6 --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java @@ -0,0 +1,106 @@ +// 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 org.apache.cloudstack.api.command.admin.zone; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.vmware.VmwareDatacenterService; +import com.cloud.hypervisor.vmware.VsphereStoragePolicy; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ImportVsphereStoragePoliciesResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; + +@APICommand(name = ImportVsphereStoragePoliciesCmd.APINAME, description = "Import vSphere storage policies", + responseObject = ImportVsphereStoragePoliciesResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin}) +public class ImportVsphereStoragePoliciesCmd extends BaseAsyncCmd { + + public static final Logger s_logger = Logger.getLogger(ImportVsphereStoragePoliciesCmd.class.getName()); + + public static final String APINAME = "importVsphereStoragePolicies"; + + @Inject + public VmwareDatacenterService _vmwareDatacenterService; + + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, + description = "ID of the zone") + private Long zoneId; + + @Override + public String getEventType() { + return EventTypes.EVENT_IMPORT_VCENTER_STORAGE_POLICIES; + } + + @Override + public String getEventDescription() { + return "Importing vSphere Storage Policies"; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + List storagePolicies = _vmwareDatacenterService.importVsphereStoragePolicies(this); + final ListResponse responseList = new ListResponse<>(); + final List storagePoliciesResponseList = new ArrayList<>(); + for (VsphereStoragePolicy storagePolicy : storagePolicies) { + final ImportVsphereStoragePoliciesResponse storagePoliciesResponse = new ImportVsphereStoragePoliciesResponse(); + storagePoliciesResponse.setId(storagePolicy.getUuid()); + storagePoliciesResponse.setName(storagePolicy.getName()); + storagePoliciesResponse.setPolicyId(storagePolicy.getPolicyId()); + storagePoliciesResponse.setDescription(storagePolicy.getDescription()); + storagePoliciesResponseList.add(storagePoliciesResponse); + } + responseList.setResponses(storagePoliciesResponseList); + responseList.setResponseName(getCommandName()); + setResponseObject(responseList); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getZoneId() { + return zoneId; + } + +} diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java new file mode 100644 index 000000000000..82baf080348e --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java @@ -0,0 +1,89 @@ +// 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 org.apache.cloudstack.api.response; + +import com.cloud.hypervisor.vmware.VsphereStoragePolicy; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + + +@EntityReference(value = VsphereStoragePolicy.class) +public class ImportVsphereStoragePoliciesResponse extends BaseResponse { + + @SerializedName(ApiConstants.ID) + @Param(description = "the ID of the Storage Policy") + private String id; + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "the ID of the Zone") + private String zoneId; + + @SerializedName(ApiConstants.POLICY_ID) + @Param(description = "the identifier of the Storage Policy in vSphere DataCenter") + private String policyId; + + @SerializedName(ApiConstants.NAME) + @Param(description = "the name of the Storage Policy") + private String name; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the Storage Policy") + private String description; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getPolicyId() { + return policyId; + } + + public void setPolicyId(String policyId) { + this.policyId = policyId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java index 31a7a44deea0..9109b18f7b3a 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java @@ -44,7 +44,7 @@ public PbmProfileManagerMO (VmwareContext context, String morType, String morVal super(context, morType, morValue); } - public List getProfileIds() throws Exception { + public List getStorageProfileIds() throws Exception { if (s_logger.isDebugEnabled()) { s_logger.debug("Querying vCenter " + _context.getServerAddress() + " for profiles"); } @@ -52,8 +52,8 @@ public List getProfileIds() throws Exception { return profileIds; } - public List getProfiles(PbmProfileResourceType pbmResourceType) throws Exception { - List profileIds = getProfileIds(); + public List getStorageProfiles() throws Exception { + List profileIds = getStorageProfileIds(); List profiles = _context.getPbmService().pbmRetrieveContent(_mor, profileIds); return profiles; } From b27735d04ec1d5e9c247ff88bca7f062038c77c4 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 2 Jun 2020 21:14:27 +0530 Subject: [PATCH 009/148] Fixed bean creation errors on VsphereStoragePolicyDaoImpl --- .../dao/VsphereStoragePolicyDaoImpl.java | 22 +++++++++++++++++++ .../vmware/manager/VmwareManagerImpl.java | 3 ++- .../zone/ImportVsphereStoragePoliciesCmd.java | 1 - .../core/spring-vmware-core-context.xml | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java index 2d13eff0c5b9..291daae11f8a 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java @@ -18,6 +18,28 @@ import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; +@Component public class VsphereStoragePolicyDaoImpl extends GenericDaoBase implements VsphereStoragePolicyDao { + + protected static final Logger LOGGER = Logger.getLogger(VsphereStoragePolicyDaoImpl.class); + + private final SearchBuilder zoneSearch; + private final SearchBuilder policySearch; + + public VsphereStoragePolicyDaoImpl() { + super(); + + zoneSearch = createSearchBuilder(); + zoneSearch.and("zoneId", zoneSearch.entity().getZoneId(), SearchCriteria.Op.EQ); + zoneSearch.done(); + + policySearch = createSearchBuilder(); + policySearch.and("policyId", policySearch.entity().getPolicyId(), SearchCriteria.Op.EQ); + policySearch.done(); + } } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index cc5e9a3ab284..5a89e07639ca 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -1054,6 +1054,7 @@ public List> getCommands() { cmdList.add(UpdateVmwareDcCmd.class); cmdList.add(RemoveVmwareDcCmd.class); cmdList.add(ListVmwareDcsCmd.class); + cmdList.add(ImportVsphereStoragePoliciesCmd.class); return cmdList; } @@ -1422,7 +1423,7 @@ public List importVsphereStoragePolicies(ImportV PbmProfileManagerMO profileManagerMO = new PbmProfileManagerMO(context); storageProfiles = profileManagerMO.getStorageProfiles(); } catch (Exception e) { - String msg = String.format("Unable to list storage profiles from DC %s due to : %s", vmwareDcName, VmwareHelper.getExceptionMessage(e); + String msg = String.format("Unable to list storage profiles from DC %s due to : %s", vmwareDcName, VmwareHelper.getExceptionMessage(e)); s_logger.error(msg); throw new CloudRuntimeException(msg); } diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java index cff37f50d3f6..6938588a9943 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java @@ -35,7 +35,6 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.ImportVsphereStoragePoliciesResponse; import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml index 3af2d1ac31fe..406a6976b9a3 100644 --- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml +++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml @@ -36,7 +36,7 @@ - + From 78ec2116ba3f99ff19af1e908c957b1f7d32d23c Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Wed, 3 Jun 2020 12:56:19 +0530 Subject: [PATCH 010/148] Added Storage policy id to VO --- .../hypervisor/vmware/VsphereStoragePolicyVO.java | 10 ++++++++++ .../hypervisor/vmware/manager/VmwareManagerImpl.java | 2 +- .../admin/zone/ImportVsphereStoragePoliciesCmd.java | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java index bc07b886719c..13c46784f190 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.hypervisor.vmware; +import com.cloud.utils.DateUtil; import com.cloud.utils.db.GenericDao; import javax.persistence.Column; @@ -66,6 +67,15 @@ public VsphereStoragePolicyVO(long zoneId, String policyId, String name, String this.policyId = policyId; this.name = name; this.description = description; + this.updateTime = DateUtil.currentGMTTime(); + } + + public VsphereStoragePolicyVO() { + uuid = UUID.randomUUID().toString(); + } + public VsphereStoragePolicyVO(long id) { + this.id = id; + uuid = UUID.randomUUID().toString(); } @Override diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 5a89e07639ca..c42a90e62d7f 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -1429,7 +1429,7 @@ public List importVsphereStoragePolicies(ImportV } for (PbmProfile storageProfile : storageProfiles) { - VsphereStoragePolicyVO StoragePolicyVO = new VsphereStoragePolicyVO(zoneId, storageProfile.getProfileId().toString(), storageProfile.getName(), storageProfile.getDescription()); + VsphereStoragePolicyVO StoragePolicyVO = new VsphereStoragePolicyVO(zoneId, storageProfile.getProfileId().getUniqueId(), storageProfile.getName(), storageProfile.getDescription()); vsphereStoragePolicyDao.persist(StoragePolicyVO); } diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java index 6938588a9943..b0e1d82a02ea 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.api.command.admin.zone; +import com.cloud.dc.DataCenter; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -29,6 +30,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; @@ -72,15 +74,23 @@ public String getEventDescription() { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final DataCenter dataCenter = _resourceService.getZone(getZoneId()); + if (dataCenter == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId()); + } + List storagePolicies = _vmwareDatacenterService.importVsphereStoragePolicies(this); final ListResponse responseList = new ListResponse<>(); final List storagePoliciesResponseList = new ArrayList<>(); for (VsphereStoragePolicy storagePolicy : storagePolicies) { final ImportVsphereStoragePoliciesResponse storagePoliciesResponse = new ImportVsphereStoragePoliciesResponse(); + storagePoliciesResponse.setZoneId(dataCenter.getUuid()); storagePoliciesResponse.setId(storagePolicy.getUuid()); storagePoliciesResponse.setName(storagePolicy.getName()); storagePoliciesResponse.setPolicyId(storagePolicy.getPolicyId()); storagePoliciesResponse.setDescription(storagePolicy.getDescription()); + storagePoliciesResponse.setObjectName("StoragePolicy"); + storagePoliciesResponseList.add(storagePoliciesResponse); } responseList.setResponses(storagePoliciesResponseList); From 8f10d32caf62ca00bcd6f5d2f2bde1ef2576b815 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Thu, 4 Jun 2020 12:00:07 +0530 Subject: [PATCH 011/148] Moved Dao and VO files to different packages --- .../com/cloud/dc}/VsphereStoragePolicyVO.java | 2 +- .../dc}/dao/VsphereStoragePolicyDao.java | 4 +-- .../dc}/dao/VsphereStoragePolicyDaoImpl.java | 4 +-- ...spring-engine-schema-core-daos-context.xml | 1 + .../vmware/VmwareDatacenterService.java | 1 + .../vmware/VsphereStoragePolicy.java | 31 ------------------- .../vmware/manager/VmwareManagerImpl.java | 6 ++-- .../zone/ImportVsphereStoragePoliciesCmd.java | 2 +- .../ImportVsphereStoragePoliciesResponse.java | 2 +- .../core/spring-vmware-core-context.xml | 1 - 10 files changed, 12 insertions(+), 42 deletions(-) rename {plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware => engine/schema/src/main/java/com/cloud/dc}/VsphereStoragePolicyVO.java (98%) rename {plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware => engine/schema/src/main/java/com/cloud/dc}/dao/VsphereStoragePolicyDao.java (90%) rename {plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware => engine/schema/src/main/java/com/cloud/dc}/dao/VsphereStoragePolicyDaoImpl.java (94%) delete mode 100644 plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java b/engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java similarity index 98% rename from plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java rename to engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java index 13c46784f190..591455ed8a62 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicyVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.hypervisor.vmware; +package com.cloud.dc;; import com.cloud.utils.DateUtil; import com.cloud.utils.db.GenericDao; diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java similarity index 90% rename from plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java rename to engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java index 14f77af9bd8c..907ab2018188 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java @@ -14,9 +14,9 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.hypervisor.vmware.dao; +package com.cloud.dc.dao; -import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; +import com.cloud.dc.VsphereStoragePolicyVO; import com.cloud.utils.db.GenericDao; public interface VsphereStoragePolicyDao extends GenericDao { diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java similarity index 94% rename from plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java rename to engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java index 291daae11f8a..4b2fd2341327 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/dao/VsphereStoragePolicyDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java @@ -14,9 +14,9 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.hypervisor.vmware.dao; +package com.cloud.dc.dao; -import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; +import com.cloud.dc.VsphereStoragePolicyVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 7faf85cef4b5..98e6c4584959 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -293,4 +293,5 @@ + diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java index 7810cb38632c..6e69009b62f0 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java @@ -19,6 +19,7 @@ import java.util.List; +import com.cloud.dc.VsphereStoragePolicy; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java deleted file mode 100644 index 102bdaa3c04c..000000000000 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VsphereStoragePolicy.java +++ /dev/null @@ -1,31 +0,0 @@ -// 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.vmware; - -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.api.InternalIdentity; - -public interface VsphereStoragePolicy extends Identity, InternalIdentity { - - long getZoneId(); - - String getPolicyId(); - - String getName(); - - String getDescription(); -} diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index c42a90e62d7f..add830c588d2 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -38,9 +38,9 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.hypervisor.vmware.VsphereStoragePolicy; -import com.cloud.hypervisor.vmware.VsphereStoragePolicyVO; -import com.cloud.hypervisor.vmware.dao.VsphereStoragePolicyDao; +import com.cloud.dc.VsphereStoragePolicy; +import com.cloud.dc.VsphereStoragePolicyVO; +import com.cloud.dc.dao.VsphereStoragePolicyDao; import com.cloud.hypervisor.vmware.mo.PbmProfileManagerMO; import com.vmware.pbm.PbmProfile; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java index b0e1d82a02ea..cf950003d5b6 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.api.command.admin.zone; import com.cloud.dc.DataCenter; +import com.cloud.dc.VsphereStoragePolicy; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -25,7 +26,6 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.vmware.VmwareDatacenterService; -import com.cloud.hypervisor.vmware.VsphereStoragePolicy; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java index 82baf080348e..a2227fb8e7fc 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.api.response; -import com.cloud.hypervisor.vmware.VsphereStoragePolicy; +import com.cloud.dc.VsphereStoragePolicy; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.ApiConstants; diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml index 406a6976b9a3..a2d8314bfb88 100644 --- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml +++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml @@ -36,7 +36,6 @@ - From dfe20e49e67259328cc9287922b24d6623eb7b04 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Thu, 4 Jun 2020 15:31:34 +0530 Subject: [PATCH 012/148] Added gen_toc.py changes for API importvpsherestoragepolicies --- tools/apidoc/gen_toc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index ef98b1358987..1ec1ac25036d 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -195,7 +195,8 @@ 'KubernetesSupportedVersion': 'Kubernetes Service', 'KubernetesCluster': 'Kubernetes Service', 'UnmanagedInstance': 'Virtual Machine', - 'Rolling': 'Rolling Maintenance' + 'Rolling': 'Rolling Maintenance', + 'importVsphereStoragePolicies' : 'vSphere storage policies' } From 0e3f72c5e33858c8dc7d92e24075b4a73bf46b68 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Thu, 4 Jun 2020 15:37:16 +0530 Subject: [PATCH 013/148] Fixed unit test failure --- .../hypervisor/vmware/VmwareDatacenterApiUnitTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index eb041396459b..1249f6ce0047 100644 --- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -31,6 +31,7 @@ import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.VsphereStoragePolicyDao; import com.cloud.event.dao.EventDao; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; @@ -486,6 +487,11 @@ public TemplateManager templateManager() { return Mockito.mock(TemplateManager.class); } + @Bean + public VsphereStoragePolicyDao vsphereStoragePolicyDao() { + return Mockito.mock(VsphereStoragePolicyDao.class); + } + public static class Library implements TypeFilter { @Override From c7c4dc84d1db05f8a1c94fbe23f3ee8298351048 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Fri, 5 Jun 2020 11:58:57 +0530 Subject: [PATCH 014/148] Updated code to handle sync of storage policies when importVsphereStoragePolicies API is called multiple times --- .../java/com/cloud/dc/VsphereStoragePolicyVO.java | 8 ++++++++ .../com/cloud/dc/dao/VsphereStoragePolicyDao.java | 3 +++ .../com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java | 9 +++++++++ .../hypervisor/vmware/manager/VmwareManagerImpl.java | 11 +++++++++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java b/engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java index 591455ed8a62..1415d15ec776 100644 --- a/engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java +++ b/engine/schema/src/main/java/com/cloud/dc/VsphereStoragePolicyVO.java @@ -103,11 +103,19 @@ public String getName() { return name; } + public void setName(String name) { + this.name = name; + } + @Override public String getDescription() { return description; } + public void setDescription(String description) { + this.description = description; + } + public Date getUpdateTime() { return updateTime; } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java index 907ab2018188..e06fd36b6d4d 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDao.java @@ -20,4 +20,7 @@ import com.cloud.utils.db.GenericDao; public interface VsphereStoragePolicyDao extends GenericDao { + + public VsphereStoragePolicyVO findByPolicyId(Long zoneId, String policyId); + } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java index 4b2fd2341327..fadea5cef250 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VsphereStoragePolicyDaoImpl.java @@ -39,7 +39,16 @@ public VsphereStoragePolicyDaoImpl() { zoneSearch.done(); policySearch = createSearchBuilder(); + policySearch.and("zoneId", policySearch.entity().getZoneId(), SearchCriteria.Op.EQ); policySearch.and("policyId", policySearch.entity().getPolicyId(), SearchCriteria.Op.EQ); policySearch.done(); } + + @Override + public VsphereStoragePolicyVO findByPolicyId(Long zoneId, String policyId) { + SearchCriteria sc = policySearch.create(); + sc.setParameters("zoneId", zoneId); + sc.setParameters("policyId", policyId); + return findOneBy(sc); + } } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index add830c588d2..ce1730c3e833 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -1429,8 +1429,15 @@ public List importVsphereStoragePolicies(ImportV } for (PbmProfile storageProfile : storageProfiles) { - VsphereStoragePolicyVO StoragePolicyVO = new VsphereStoragePolicyVO(zoneId, storageProfile.getProfileId().getUniqueId(), storageProfile.getName(), storageProfile.getDescription()); - vsphereStoragePolicyDao.persist(StoragePolicyVO); + VsphereStoragePolicyVO storagePolicyVO = vsphereStoragePolicyDao.findByPolicyId(zoneId, storageProfile.getProfileId().getUniqueId()); + if (storagePolicyVO == null) { + storagePolicyVO = new VsphereStoragePolicyVO(zoneId, storageProfile.getProfileId().getUniqueId(), storageProfile.getName(), storageProfile.getDescription()); + vsphereStoragePolicyDao.persist(storagePolicyVO); + } else { + storagePolicyVO.setDescription(storageProfile.getDescription()); + storagePolicyVO.setName(storageProfile.getName()); + vsphereStoragePolicyDao.update(storagePolicyVO.getId(), storagePolicyVO); + } } List storagePolicies = vsphereStoragePolicyDao.listAll(); From 957924d23af14ac9e59f0f4482289707d4503900 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 9 Jun 2020 12:56:13 +0530 Subject: [PATCH 015/148] Check if datastore is complaince with the storagepolicy provided in the disk offering. Added corresponding manager objects from PBM sdk to do the job. Made dao layer changes to read the storage policy in diskoffering --- .../storage/resource/StorageProcessor.java | 3 + .../StorageSubsystemCommandHandlerBase.java | 3 + ...taStoreStoragePolicyComplainceCommand.java | 61 +++++++++++++++++ .../com/cloud/storage/StorageManager.java | 2 + .../dao/DiskOfferingDetailsDao.java | 1 + .../dao/DiskOfferingDetailsDaoImpl.java | 10 +++ .../AbstractStoragePoolAllocator.java | 12 ++++ .../kvm/storage/KVMStorageProcessor.java | 7 ++ .../ovm3/resources/Ovm3StorageProcessor.java | 7 ++ .../resource/VmwareStorageProcessor.java | 33 +++++++++ .../resource/XenServerStorageProcessor.java | 7 ++ .../Xenserver625StorageProcessor.java | 7 ++ .../deploy/DeploymentPlanningManagerImpl.java | 13 ++++ .../com/cloud/storage/StorageManagerImpl.java | 54 ++++++++++++++- .../hypervisor/vmware/mo/DatacenterMO.java | 14 ++++ .../hypervisor/vmware/mo/DatastoreMO.java | 11 +++ .../vmware/mo/PbmPlacementSolverMO.java | 68 +++++++++++++++++++ .../vmware/mo/PbmProfileManagerMO.java | 15 ++++ 18 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/apache/cloudstack/storage/command/CheckDataStoreStoragePolicyComplainceCommand.java create mode 100644 vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmPlacementSolverMO.java diff --git a/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java b/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java index f940e22f45a1..4b2438ea1025 100644 --- a/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand; import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.DeleteCommand; @@ -76,4 +77,6 @@ public interface StorageProcessor { public Answer handleDownloadTemplateToPrimaryStorage(DirectDownloadCommand cmd); Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd); + + public Answer CheckDataStoreStoragePolicyComplaince(CheckDataStoreStoragePolicyComplainceCommand cmd); } diff --git a/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index 17b9b700d6c0..910eb3d87905 100644 --- a/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -21,6 +21,7 @@ import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.log4j.Logger; import org.apache.cloudstack.storage.command.AttachCommand; @@ -71,6 +72,8 @@ public Answer handleStorageCommands(StorageSubSystemCommand command) { return processor.resignature((ResignatureCommand) command); } else if (command instanceof DirectDownloadCommand) { return processor.handleDownloadTemplateToPrimaryStorage((DirectDownloadCommand) command); + } else if (command instanceof CheckDataStoreStoragePolicyComplainceCommand) { + return processor.CheckDataStoreStoragePolicyComplaince((CheckDataStoreStoragePolicyComplainceCommand) command); } return new Answer((Command)command, false, "not implemented yet"); diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/CheckDataStoreStoragePolicyComplainceCommand.java b/core/src/main/java/org/apache/cloudstack/storage/command/CheckDataStoreStoragePolicyComplainceCommand.java new file mode 100644 index 000000000000..f9544b873ef2 --- /dev/null +++ b/core/src/main/java/org/apache/cloudstack/storage/command/CheckDataStoreStoragePolicyComplainceCommand.java @@ -0,0 +1,61 @@ +// +// 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 org.apache.cloudstack.storage.command; + +import com.cloud.agent.api.to.StorageFilerTO; + +public class CheckDataStoreStoragePolicyComplainceCommand extends StorageSubSystemCommand { + + String storagePolicyId; + private StorageFilerTO storagePool; + + public CheckDataStoreStoragePolicyComplainceCommand(String storagePolicyId, StorageFilerTO storagePool) { + super(); + + this.storagePolicyId = storagePolicyId; + this.storagePool = storagePool; + } + + @Override + public void setExecuteInSequence(boolean inSeq) { + } + + @Override + public boolean executeInSequence() { + return false; + } + + + public String getStoragePolicyId() { + return storagePolicyId; + } + + public void setStoragePolicyId(String storagePolicyId) { + this.storagePolicyId = storagePolicyId; + } + + public StorageFilerTO getStoragePool() { + return storagePool; + } + + public void setStoragePool(StorageFilerTO storagePool) { + this.storagePool = storagePool; + } +} diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java index 62a241be4345..e8519ee303ea 100644 --- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java +++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java @@ -206,6 +206,8 @@ public interface StorageManager extends StorageService { boolean storagePoolHasEnoughSpaceForResize(StoragePool pool, long currentSize, long newSiz); + boolean isStoragePoolComplaintWithStoragePolicy(List volumes, StoragePool pool) throws StorageUnavailableException; + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException; diff --git a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java index e201ae27fdc8..815f1693ee54 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDao.java @@ -26,4 +26,5 @@ public interface DiskOfferingDetailsDao extends GenericDao, ResourceDetailsDao { List findDomainIds(final long resourceId); List findZoneIds(final long resourceId); + String getDetail(Long diskOfferingId, String key); } \ No newline at end of file diff --git a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java index da0ec5bc580d..5408f2d7f036 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/resourcedetail/dao/DiskOfferingDetailsDaoImpl.java @@ -56,4 +56,14 @@ public List findZoneIds(long resourceId) { } return zoneIds; } + + @Override + public String getDetail(Long diskOfferingId, String key) { + String detailValue = null; + DiskOfferingDetailVO diskOfferingDetail = findDetail(diskOfferingId, key); + if (diskOfferingDetail != null) { + detailValue = diskOfferingDetail.getValue(); + } + return detailValue; + } } \ No newline at end of file diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index 727d10af1300..23fb21428680 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -26,6 +26,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.exception.StorageUnavailableException; import org.apache.log4j.Logger; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -215,6 +216,17 @@ protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh, Volume volume = volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList<>(); requestVolumes.add(volume); + if (dskCh.getHypervisorType() == HypervisorType.VMware) { + try { + boolean isStoragePoolStoragepolicyComplaince = storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, pool); + if (!isStoragePoolStoragepolicyComplaince) { + return false; + } + } catch (StorageUnavailableException e) { + s_logger.warn(String.format("Could not verify storage policy complaince against storage pool %s due to exception %s", pool.getUuid(), e.getMessage())); + return false; + } + } return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) && storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool, plan.getClusterId()); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 1df72de517c3..c761af139aca 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -45,6 +45,7 @@ import org.apache.cloudstack.agent.directdownload.NfsDirectDownloadCommand; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CreateObjectAnswer; @@ -1832,4 +1833,10 @@ protected boolean isEnoughSpaceForDownloadTemplateOnTemporaryLocation(Long templ } return availableBytes >= templateSize; } + + @Override + public Answer CheckDataStoreStoragePolicyComplaince(CheckDataStoreStoragePolicyComplainceCommand cmd) { + s_logger.info("'CheckDataStoreStoragePolicyComplainceCommand' not currently applicable for KVMStorageProcessor"); + return new Answer(cmd,false,"Not currently applicable for KVMStorageProcessor"); + } } diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java index 7915586fca3f..dd58bb573d94 100644 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CreateObjectAnswer; @@ -826,6 +827,12 @@ public Answer handleDownloadTemplateToPrimaryStorage(DirectDownloadCommand cmd) return null; } + @Override + public Answer CheckDataStoreStoragePolicyComplaince(CheckDataStoreStoragePolicyComplainceCommand cmd) { + LOGGER.info("'CheckDataStoreStoragePolicyComplainceCommand' not applicable used for Ovm3StorageProcessor"); + return new Answer(cmd,false,"Not applicable used for Ovm3StorageProcessor"); + } + @Override public Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd) { return null; diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index 796db94f0ed5..0da059116f0e 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -37,6 +37,7 @@ import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CreateObjectAnswer; @@ -3555,6 +3556,38 @@ public Answer handleDownloadTemplateToPrimaryStorage(DirectDownloadCommand cmd) return null; } + @Override + public Answer CheckDataStoreStoragePolicyComplaince(CheckDataStoreStoragePolicyComplainceCommand cmd) { + String primaryStorageNameLabel = cmd.getStoragePool().getUuid(); + String storagePolicyId = cmd.getStoragePolicyId(); + VmwareContext context = hostService.getServiceContext(cmd); + try { + VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); + ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel); + if (morPrimaryDs == null) { + String msg = "Unable to find datastore: " + primaryStorageNameLabel; + s_logger.error(msg); + throw new Exception(msg); + } + + DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); + boolean isDatastoreStoragePolicyComplaint = primaryDsMo.isDatastoreStoragePolicyComplaint(storagePolicyId); + + String failedMessage = String.format("DataStore %s is not complaince with storage policy id %s", primaryStorageNameLabel, storagePolicyId); + if (!isDatastoreStoragePolicyComplaint) + return new Answer(cmd, isDatastoreStoragePolicyComplaint, failedMessage); + else + return new Answer(cmd, isDatastoreStoragePolicyComplaint, null); + } catch (Throwable e) { + if (e instanceof RemoteException) { + hostService.invalidateServiceContext(context); + } + String details = String.format("Exception while checking if datastore %s is storage policy %s complaince : %s", primaryStorageNameLabel, storagePolicyId, VmwareHelper.getExceptionMessage(e)); + s_logger.error(details, e); + return new Answer(cmd, false, details); + } + } + @Override public Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd) { return null; diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java index e4c07d4ba79e..a7da201167c9 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java @@ -34,6 +34,7 @@ import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CreateObjectAnswer; @@ -214,6 +215,12 @@ public Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd) { return null; } + @Override + public Answer CheckDataStoreStoragePolicyComplaince(CheckDataStoreStoragePolicyComplainceCommand cmd) { + s_logger.info("'CheckDataStoreStoragePolicyComplainceCommand' not applicable used for XenServerStorageProcessor"); + return new Answer(cmd,false,"Not applicable used for XenServerStorageProcessor"); + } + @Override public AttachAnswer attachIso(final AttachCommand cmd) { final DiskTO disk = cmd.getDisk(); diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java index a2c8b708bf3a..12b70e85d054 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java @@ -27,6 +27,7 @@ import java.util.Set; import java.util.UUID; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; @@ -910,6 +911,12 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) { return new CopyCmdAnswer(details); } + @Override + public Answer CheckDataStoreStoragePolicyComplaince(CheckDataStoreStoragePolicyComplainceCommand cmd) { + s_logger.info("'CheckDataStoreStoragePolicyComplainceCommand' not applicable used for XenServerStorageProcessor"); + return new Answer(cmd,false,"Not applicable used for XenServerStorageProcessor"); + } + @Override public Answer copyVolumeFromPrimaryToSecondary(final CopyCommand cmd) { final Connection conn = hypervisorResource.getConnection(); diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 26b36157dcdd..b628b3a9c3c8 100644 --- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -31,6 +31,7 @@ import javax.naming.ConfigurationException; import com.cloud.utils.StringUtils; +import com.cloud.exception.StorageUnavailableException; import com.cloud.utils.db.Filter; import com.cloud.utils.fsm.StateMachine2; @@ -1268,6 +1269,18 @@ public int compare(Volume v1, Volume v2) { requestVolumes = new ArrayList(); requestVolumes.add(vol); + if (potentialHost.getHypervisorType() == HypervisorType.VMware) { + try { + boolean isStoragePoolStoragepolicyComplaince = _storageMgr.isStoragePoolComplaintWithStoragePolicy(requestVolumes, potentialSPool); + if (!isStoragePoolStoragepolicyComplaince) { + continue; + } + } catch (StorageUnavailableException e) { + s_logger.warn(String.format("Could not verify storage policy complaince against storage pool %s due to exception %s", potentialSPool.getUuid(), e.getMessage())); + continue; + } + } + if (!_storageMgr.storagePoolHasEnoughIops(requestVolumes, potentialSPool) || !_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool, potentialHost.getClusterId())) continue; diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index 79343ab4725f..3ee20b10d21e 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -39,6 +39,11 @@ import javax.inject.Inject; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.dc.VsphereStoragePolicyVO; +import com.cloud.dc.dao.VsphereStoragePolicyDao; +import com.cloud.utils.StringUtils; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd; import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd; import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; @@ -81,6 +86,8 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.management.ManagementServerHost; +import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; +import org.apache.cloudstack.storage.command.CheckDataStoreStoragePolicyComplainceCommand; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; @@ -175,7 +182,6 @@ import com.cloud.utils.DateUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.StringUtils; import com.cloud.utils.UriUtils; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; @@ -296,6 +302,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C SnapshotService _snapshotService; @Inject StoragePoolTagsDao _storagePoolTagsDao; + @Inject + DiskOfferingDetailsDao _diskOfferingDetailsDao; + @Inject + VsphereStoragePolicyDao _vsphereStoragePolicyDao; protected List _discoverers; @@ -1859,6 +1869,48 @@ public boolean storagePoolHasEnoughSpaceForResize(StoragePool pool, long current } } + @Override + public boolean isStoragePoolComplaintWithStoragePolicy(List volumes, StoragePool pool) throws StorageUnavailableException { + if (volumes == null || volumes.isEmpty()) { + return false; + } + List> answers = new ArrayList>(); + + for (Volume volume : volumes) { + String storagePolicyId = _diskOfferingDetailsDao.getDetail(volume.getDiskOfferingId(), ApiConstants.STORAGE_POLICY); + if (org.apache.commons.lang.StringUtils.isNotEmpty(storagePolicyId)) { + VsphereStoragePolicyVO storagePolicyVO = _vsphereStoragePolicyDao.findById(Long.parseLong(storagePolicyId)); + List hostIds = getUpHostsInPool(pool.getId()); + Collections.shuffle(hostIds); + + if (hostIds == null || hostIds.isEmpty()) { + throw new StorageUnavailableException("Unable to send command to the pool " + pool.getName() + " due to there is no enabled hosts up in this cluster", pool.getId()); + } + try { + StorageFilerTO storageFilerTO = new StorageFilerTO(pool); + CheckDataStoreStoragePolicyComplainceCommand cmd = new CheckDataStoreStoragePolicyComplainceCommand(storagePolicyVO.getPolicyId(), storageFilerTO); + long targetHostId = _hvGuruMgr.getGuruProcessedCommandTargetHost(hostIds.get(0), cmd); + Answer answer = _agentMgr.send(targetHostId, cmd); + answers.add(new Pair<>(volume, answer)); + } catch (AgentUnavailableException e) { + s_logger.debug("Unable to send storage pool command to " + pool + " via " + hostIds.get(0), e); + throw new StorageUnavailableException("Unable to send command to the pool ", pool.getId()); + } catch (OperationTimedoutException e) { + s_logger.debug("Failed to process storage pool command to " + pool + " via " + hostIds.get(0), e); + throw new StorageUnavailableException("Failed to process storage command to the pool ", pool.getId()); + } + } + } + // check cummilative result for all volumes + for (Pair answer : answers) { + if (!answer.second().getResult()) { + s_logger.debug(String.format("Storage pool %s is not complaince with storage policy for volume %s", pool.getName(), answer.first().getName())); + return false; + } + } + return true; + } + private boolean checkPoolforSpace(StoragePool pool, long allocatedSizeWithTemplate, long totalAskingSize) { // allocated space includes templates StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatacenterMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatacenterMO.java index b0b91fb7d5b2..af89757d521f 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatacenterMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatacenterMO.java @@ -186,6 +186,20 @@ public ManagedObjectReference findDatastore(String name) throws Exception { return null; } + public ManagedObjectReference listDatastore(String name) throws Exception { + assert (name != null); + + List ocs = getDatastorePropertiesOnDatacenter(new String[] {"name"}); + if (ocs != null) { + for (ObjectContent oc : ocs) { + if (oc.getPropSet().get(0).getVal().toString().equals(name)) { + return oc.getObj(); + } + } + } + return null; + } + public ManagedObjectReference findHost(String name) throws Exception { List ocs = getHostPropertiesOnDatacenterHostFolder(new String[] {"name"}); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java index d0d3a5bb28d1..fc8bb8c8c8b8 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; +import com.vmware.pbm.PbmProfile; import org.apache.log4j.Logger; import com.vmware.vim25.DatastoreHostMount; @@ -468,4 +469,14 @@ public boolean isAccessibleToHost(String hostValue) throws Exception { } return isAccessible; } + + public boolean isDatastoreStoragePolicyComplaint(String storagePolicyId) throws Exception { + PbmProfileManagerMO profMgrMo = new PbmProfileManagerMO(_context); + PbmProfile profile = profMgrMo.getStorageProfile(storagePolicyId); + + PbmPlacementSolverMO placementSolverMo = new PbmPlacementSolverMO(_context); + boolean isDatastoreCompatible = placementSolverMo.isDatastoreCompatibleWithStorageProfile(_mor, profile); + + return isDatastoreCompatible; + } } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmPlacementSolverMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmPlacementSolverMO.java new file mode 100644 index 000000000000..9735f424d889 --- /dev/null +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmPlacementSolverMO.java @@ -0,0 +1,68 @@ +// 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.vmware.mo; + +import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.vmware.pbm.PbmPlacementCompatibilityResult; +import com.vmware.pbm.PbmPlacementHub; +import com.vmware.pbm.PbmProfile; +import com.vmware.pbm.PbmProfileId; +import com.vmware.vim25.ManagedObjectReference; +import org.apache.commons.collections.CollectionUtils; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; + +public class PbmPlacementSolverMO extends BaseMO { + + private static final Logger s_logger = Logger.getLogger(PbmPlacementSolverMO.class); + + public PbmPlacementSolverMO (VmwareContext context) { + super(context, context.getPbmServiceContent().getPlacementSolver()); + } + + public PbmPlacementSolverMO(VmwareContext context, ManagedObjectReference morPlacementSolver) { + super(context, morPlacementSolver); + } + + public PbmPlacementSolverMO(VmwareContext context, String morType, String morValue) { + super(context, morType, morValue); + } + + public boolean isDatastoreCompatibleWithStorageProfile(ManagedObjectReference dsMor, PbmProfile profile) throws Exception { + boolean isDatastoreCompatibleWithStorageProfile = false; + + PbmPlacementHub placementHub = new PbmPlacementHub(); + placementHub.setHubId(dsMor.getValue()); + placementHub.setHubType(dsMor.getType()); + + List placementHubList = new ArrayList(); + placementHubList.add(placementHub); + PbmProfileId profileId = profile.getProfileId(); + List placementCompatibilityResultList = _context.getPbmService().pbmCheckCompatibility(_mor, placementHubList, profileId); + if (CollectionUtils.isNotEmpty(placementCompatibilityResultList)) { + for (PbmPlacementCompatibilityResult placementResult : placementCompatibilityResultList) { + // Check for error and warning + if (CollectionUtils.isEmpty(placementResult.getError()) && CollectionUtils.isEmpty(placementResult.getWarning())) { + isDatastoreCompatibleWithStorageProfile = true; + } + } + } + return isDatastoreCompatibleWithStorageProfile; + } +} diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java index 9109b18f7b3a..557f350cf8ed 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/PbmProfileManagerMO.java @@ -18,6 +18,7 @@ import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.utils.exception.CloudRuntimeException; import com.vmware.pbm.PbmProfile; import com.vmware.pbm.PbmProfileId; import com.vmware.pbm.PbmProfileResourceType; @@ -26,6 +27,7 @@ import org.apache.log4j.Logger; +import java.util.Collections; import java.util.List; public class PbmProfileManagerMO extends BaseMO { @@ -58,6 +60,19 @@ public List getStorageProfiles() throws Exception { return profiles; } + public PbmProfile getStorageProfile(String storageProfileId) throws Exception { + List profileIds = getStorageProfileIds(); + for (PbmProfileId profileId : profileIds) { + if (storageProfileId.equals(profileId.getUniqueId())) { + List profile = _context.getPbmService().pbmRetrieveContent(_mor, Collections.singletonList(profileId)); + return profile.get(0); + } + } + String errMsg = String.format("Storage profile with id %s not found", storageProfileId); + s_logger.debug(errMsg); + throw new CloudRuntimeException(errMsg); + } + private PbmProfileResourceType getStorageResourceType() { PbmProfileResourceType resourceType = new PbmProfileResourceType(); resourceType.setResourceType(PbmProfileResourceTypeEnum.STORAGE.value()); From 0b98d264d3d3c77e275f18015d06a86d262c0904 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 4 Jun 2020 08:22:17 +0000 Subject: [PATCH 016/148] ovf string props hack --- ui/scripts/ui-custom/instanceWizard.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index 4aefa97b335b..4926ae434f9e 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -172,10 +172,20 @@ .html(qualifier) propertyField.append(option); }); - } else if (qualifiers.startsWith("MaxLen")) { - var length = qualifiers.replace("MaxLen(","").slice(0,-1); + } else if (qualifiers.includes("MinLen") || qualifiers.includes("MaxLen") ) { + var split = qualifiers.split(","); + var minLen = 0; + var maxLen = 524288; /* 524288 being the default according to w3schools */ + for ( var i = 0; i < split.length; i++ ) { + if (split[i].startsWith("MaxLen")) { + maxLen = split[i].replace("MaxLen(","").replace(")",""); + } else if (split[i].startsWith("MinLen")) { + minLen = split[i].replace("MinLen(","").replace(")",""); + } + } propertyField = $('') - .attr({maxlength : length, type: fieldType}) + .attr({pattern : '.{' + minLen + ',' + maxLen + '}'}) + .attr(type: fieldType}) .addClass('name').val(_s(this[fields.value])) } } else { From 3481393f60c1dddf7bee637cefbaa281c8621991 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 5 Jun 2020 08:25:55 +0000 Subject: [PATCH 017/148] refactor plan in comments --- .../main/java/com/cloud/storage/TemplateOVFPropertyVO.java | 1 + .../java/com/cloud/hypervisor/guru/VmwareVmImplementer.java | 5 +++++ .../main/java/com/cloud/template/TemplateManagerImpl.java | 3 +++ server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 5 +++++ 4 files changed, 14 insertions(+) diff --git a/engine/schema/src/main/java/com/cloud/storage/TemplateOVFPropertyVO.java b/engine/schema/src/main/java/com/cloud/storage/TemplateOVFPropertyVO.java index 425b1f22e453..cd7f04b71d6e 100644 --- a/engine/schema/src/main/java/com/cloud/storage/TemplateOVFPropertyVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/TemplateOVFPropertyVO.java @@ -28,6 +28,7 @@ @Entity @Table(name = "template_ovf_properties") +@Deprecated(since = "now" , forRemoval = true) public class TemplateOVFPropertyVO implements OVFProperty { @Id diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java index c9f8b0c337a2..228227e57a40 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java @@ -317,10 +317,15 @@ private void handleOvfProperties(VirtualMachineProfile vm, VirtualMachineTO to, } } + // TODO FR37 phase out ovf properties in favor of template details private List getOvfPropertyList(VirtualMachineProfile vm, Map details) { List ovfProperties = new ArrayList(); for (String detailKey : details.keySet()) { if (detailKey.startsWith(ApiConstants.OVF_PROPERTIES)) { + // get value from template details using key including ApiConstants.OVF_PROPERTIES prefix + // put the resulting json in a OVFPropertyTO named propertyTO + // setValue(details.get(detailKey)) on the resulting propTO + // skipp all upto ovfProperties.add(propertyTO); String ovfPropKey = detailKey.replace(ApiConstants.OVF_PROPERTIES + "-", ""); TemplateOVFPropertyVO templateOVFPropertyVO = templateOVFPropertiesDao.findByTemplateAndKey(vm.getTemplateId(), ovfPropKey); if (templateOVFPropertyVO == null) { diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 749f272bf361..48c186eabdc9 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -339,6 +339,9 @@ public VirtualMachineTemplate registerTemplate(RegisterTemplateCmd cmd) throws U } TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor())); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Template adapter: " + adapter); + } TemplateProfile profile = adapter.prepare(cmd); VMTemplateVO template = adapter.create(profile); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index ce9a41a8470c..d0504738244a 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -2487,8 +2487,11 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx } for (String detailName : details.keySet()) { if (detailName.startsWith(ApiConstants.OVF_PROPERTIES)) { + // TODO FR37 do not replace the name String ovfPropKey = detailName.replace(ApiConstants.OVF_PROPERTIES + "-", ""); + // TODO FR37 get the vm_template_detail TemplateOVFPropertyVO ovfPropertyVO = templateOVFPropertiesDao.findByTemplateAndKey(vmInstance.getTemplateId(), ovfPropKey); + // TODO FR37 create the OvfProperertyTO from the value of the vm_template_detail and get isPassword from that if (ovfPropertyVO != null && ovfPropertyVO.isPassword()) { details.put(detailName, DBEncryptionUtil.encrypt(details.get(detailName))); } @@ -3956,6 +3959,8 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap } else if (value.equalsIgnoreCase("False")) { value = "False"; } else { + // TODO FR37 get the vm_template_detail + // TODO FR37 create the OvfProperertyTO from the value of the vm_template_detail and get isPassword from that TemplateOVFPropertyVO ovfPropertyVO = templateOVFPropertiesDao.findByTemplateAndKey(vm.getTemplateId(), key); if (ovfPropertyVO.isPassword()) { value = DBEncryptionUtil.encrypt(value); From b0eec074ef6c0303bac99c14842d16ecbcf5860e Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 8 Jun 2020 09:00:58 +0000 Subject: [PATCH 018/148] trace --- .../com/cloud/storage/template/OVAProcessor.java | 3 +++ .../storage/image/BaseImageStoreDriverImpl.java | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java index bf4fb3f020ae..82c1f0e1b0ec 100644 --- a/core/src/main/java/com/cloud/storage/template/OVAProcessor.java +++ b/core/src/main/java/com/cloud/storage/template/OVAProcessor.java @@ -162,6 +162,9 @@ private boolean conversionChecks(ImageFormat format) { } return false; } + if (s_logger.isTraceEnabled()) { + s_logger.trace("We are handling format " + format + "."); + } return true; } diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 8013a0dbe942..09fc707dc442 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -177,14 +177,22 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal * Persist OVF properties as template details for template with id = templateId */ private void persistOVFProperties(List ovfProperties, long templateId) { - List templateDetailsList = new ArrayList<>(); + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("saving properts for template %d as details", templateId)); + } for (OVFPropertyTO property : ovfProperties) { + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("saving property %s for template %d as detail", property.getKey(), templateId)); + } persistOvfPropertyAsTemplateDetail(templateId, property); } persistOvfPropertiesInDedicatedTable(ovfProperties, templateId); } private void persistOvfPropertiesInDedicatedTable(List ovfProperties, long templateId) { + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("saving properties for template %d in dedicated table", templateId)); + } List listToPersist = new ArrayList<>(); for (OVFPropertyTO property : ovfProperties) { persistOvfPropertyAsTemplateDetail(templateId, property); @@ -207,7 +215,10 @@ private void persistOvfPropertiesInDedicatedTable(List ovfPropert private void persistOvfPropertyAsTemplateDetail(long templateId, OVFPropertyTO property) { String key = "ovfProperty-" + property.getKey(); - templateDetailsDao.removeDetail(templateId,key); + if ( templateDetailsDao.findDetail(templateId,key) != null) { + s_logger.debug(String.format("detail '%s' existed for template %d, deleting.", key, templateId)); + templateDetailsDao.removeDetail(templateId,key); + } String json = gson.toJson(property); VMTemplateDetailVO detailVO = new VMTemplateDetailVO(templateId, key, json, property.isUserConfigurable()); s_logger.debug("Persisting template details " + detailVO.getName() + " from OVF properties for template " + templateId); From cf9952663b75ba6354fdf2f7131a3c1281e8ff49 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Wed, 10 Jun 2020 10:22:57 +0000 Subject: [PATCH 019/148] hack to deal with: ovf property attributes in details --- .../image/BaseImageStoreDriverImpl.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 09fc707dc442..2e7eb4c335be 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -28,6 +28,7 @@ import javax.inject.Inject; import com.cloud.agent.api.storage.OVFPropertyTO; +import com.cloud.serializer.GsonHelper; import com.cloud.storage.Upload; import com.cloud.storage.VMTemplateDetailVO; import com.cloud.storage.dao.TemplateOVFPropertiesDao; @@ -111,7 +112,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { protected String _proxy = null; - private static Gson gson; + private static Gson gson = GsonHelper.getGson(); protected Proxy getHttpProxy() { if (_proxy == null) { @@ -178,7 +179,7 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal */ private void persistOVFProperties(List ovfProperties, long templateId) { if (s_logger.isTraceEnabled()) { - s_logger.trace(String.format("saving properts for template %d as details", templateId)); + s_logger.trace(String.format("saving properties for template %d as details", templateId)); } for (OVFPropertyTO property : ovfProperties) { if (s_logger.isTraceEnabled()) { @@ -195,7 +196,6 @@ private void persistOvfPropertiesInDedicatedTable(List ovfPropert } List listToPersist = new ArrayList<>(); for (OVFPropertyTO property : ovfProperties) { - persistOvfPropertyAsTemplateDetail(templateId, property); if (!templateOvfPropertiesDao.existsOption(templateId, property.getKey())) { TemplateOVFPropertyVO option = new TemplateOVFPropertyVO(templateId, property.getKey(), property.getType(), property.getValue(), property.getQualifiers(), property.isUserConfigurable(), @@ -215,12 +215,24 @@ private void persistOvfPropertiesInDedicatedTable(List ovfPropert private void persistOvfPropertyAsTemplateDetail(long templateId, OVFPropertyTO property) { String key = "ovfProperty-" + property.getKey(); + // TODO save separate details for each of the properties of a property + // + savePropertyAttribute(templateId, key + "-default", property.getValue()); + savePropertyAttribute(templateId, key + "-description", property.getDescription()); + savePropertyAttribute(templateId, key + "-qualifiers", property.getQualifiers()); + savePropertyAttribute(templateId, key + "-label", property.getLabel()); + savePropertyAttribute(templateId, key + "-type", property.getType()); + savePropertyAttribute(templateId, key + "-password", property.isPassword().toString()); + } + void savePropertyAttribute(long templateId, String key, String value) { if ( templateDetailsDao.findDetail(templateId,key) != null) { s_logger.debug(String.format("detail '%s' existed for template %d, deleting.", key, templateId)); templateDetailsDao.removeDetail(templateId,key); } - String json = gson.toJson(property); - VMTemplateDetailVO detailVO = new VMTemplateDetailVO(templateId, key, json, property.isUserConfigurable()); + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("template property for template %d to save is '%s': '%s'", templateId, key, value)); + } + VMTemplateDetailVO detailVO = new VMTemplateDetailVO(templateId, key, value, false); s_logger.debug("Persisting template details " + detailVO.getName() + " from OVF properties for template " + templateId); templateDetailsDao.persist(detailVO); } From f0bbe9c3457be5f11e71698454e640a3a49fe306 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 11 Jun 2020 12:59:37 +0000 Subject: [PATCH 020/148] PoC code for properties iso --- .../vmware/resource/VmwareResource.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 641fc60f416e..e8c69d622173 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1713,6 +1713,13 @@ protected StartAnswer execute(StartCommand cmd) { s_logger.info("Executing resource StartCommand: " + _gson.toJson(cmd)); } + // FR37 if startcommand contains a secendary storage URL or some flag or other type of indicator, deploy OVA as is + String secStorUrl = cmd.getSecondaryStorage(); + if (StringUtils.isNotEmpty(secStorUrl)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace(String.format("deploying OVA as is from %s", secStorUrl)); + } + } VirtualMachineTO vmSpec = cmd.getVirtualMachine(); boolean vmAlreadyExistsInVcenter = false; @@ -1902,6 +1909,14 @@ protected StartAnswer execute(StartCommand cmd) { } int totalChangeDevices = disks.length + nics.length; + // vApp cdrom device + // HACK ALERT: ovf properties might not be the only or defining feature of vApps; needs checking + if (s_logger.isTraceEnabled()) { + s_logger.trace("adding divice tie device count for vApp config ISO"); + } + if (vmSpec.getOvfProperties() != null) { + totalChangeDevices++; + } DiskTO volIso = null; if (vmSpec.getType() != VirtualMachine.Type.User) { @@ -1956,6 +1971,30 @@ protected StartAnswer execute(StartCommand cmd) { // Setup ISO device // + // vAPP ISO + // FR37 the native deploy mechs should create this for us + if (vmSpec.getOvfProperties() != null) { + if (s_logger.isTraceEnabled()) { + // FR37 TODO add more usefull info (if we keep this bit + s_logger.trace("adding iso for properties for 'xxx'"); + } + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + Pair isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1); + deviceConfigSpecArray[i].setDevice(isoInfo.first()); + if (isoInfo.second()) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Prepare vApp ISO volume at existing device " + _gson.toJson(isoInfo.first())); + + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + if (s_logger.isDebugEnabled()) + s_logger.debug("Prepare vApp ISO volume at existing device " + _gson.toJson(isoInfo.first())); + + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + i++; + } + // prepare systemvm patch ISO if (vmSpec.getType() != VirtualMachine.Type.User) { // attach ISO (for patching of system VM) From fec5e73a72d0f7ca78f1ba9e8e4bb63ae51268d6 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 11 Jun 2020 13:00:37 +0000 Subject: [PATCH 021/148] flag for deploy as is --- .../java/com/cloud/hypervisor/guru/VMwareGuru.java | 7 +++++-- .../com/cloud/hypervisor/guru/VmwareVmImplementer.java | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java index a2a086b0b6c7..d45320ee055e 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java @@ -197,6 +197,9 @@ protected VMwareGuru() { public static final ConfigKey VmwareEnableNestedVirtualizationPerVM = new ConfigKey(Boolean.class, "vmware.nested.virtualization.perVM", "Advanced", "false", "When set to true this will enable nested virtualization per vm", true, ConfigKey.Scope.Global, null); + public static final ConfigKey VmwareImplementAsIsAndReconsiliate = new ConfigKey(Boolean.class, "vmware.dont.orchestrate.but.reconsiliate", "Advanced", "false", + "When set to true OVAs will be deployed as is to then discover disk.]/net/etc", true, ConfigKey.Scope.Global, null); + @Override public HypervisorType getHypervisorType() { return HypervisorType.VMware; } @@ -204,7 +207,7 @@ protected VMwareGuru() { @Override public VirtualMachineTO implement(VirtualMachineProfile vm) { vmwareVmImplementer.setGlobalNestedVirtualisationEnabled(VmwareEnableNestedVirtualization.value()); vmwareVmImplementer.setGlobalNestedVPerVMEnabled(VmwareEnableNestedVirtualizationPerVM.value()); - return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), getClusterId(vm.getId())); + return vmwareVmImplementer.implement(vm, toVirtualMachineTO(vm), getClusterId(vm.getId()), VmwareImplementAsIsAndReconsiliate.value()); } long getClusterId(long vmId) { @@ -373,7 +376,7 @@ private static String resolveNameInGuid(String guid) { } @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {VmwareReserveCpu, VmwareReserveMemory, VmwareEnableNestedVirtualization, VmwareEnableNestedVirtualizationPerVM}; + return new ConfigKey[] {VmwareReserveCpu, VmwareReserveMemory, VmwareEnableNestedVirtualization, VmwareEnableNestedVirtualizationPerVM, VmwareImplementAsIsAndReconsiliate}; } @Override public List finalizeExpungeVolumes(VirtualMachine vm) { diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java index 228227e57a40..9e98c4b33791 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java @@ -114,9 +114,17 @@ void setGlobalNestedVPerVMEnabled(Boolean globalNestedVPerVMEnabled) { this.globalNestedVPerVMEnabled = globalNestedVPerVMEnabled; } - VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long clusterId) { + VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long clusterId, Boolean deployOvaAsIs) { to.setBootloader(VirtualMachineTemplate.BootloaderType.HVM); + // FR37 if VmwareImplementAsIsAndReconsiliate add secondary storage or some other encoding of the OVA file to the start command, + // FR37 so the url for the original OVA can be used for deployment + if (deployOvaAsIs) { + if (LOG.isTraceEnabled()) { + // FR37 TODO add usefull stuff in message + LOG.trace("deploying OVA as is."); + } + } Map details = to.getDetails(); if (details == null) details = new HashMap(); From fa93d5366cc9ee9029ab9a4451caf437371bf9cf Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 12 Jun 2020 10:35:22 +0000 Subject: [PATCH 022/148] factor out 700 line start command and callees --- .../vmware/resource/StartCommandExecutor.java | 1728 ++++++++++++++++ .../vmware/resource/VmwareResource.java | 1828 ++--------------- .../resource/StartCommandExecutorTest.java | 37 + .../vmware/resource/VmwareResourceTest.java | 19 - 4 files changed, 1884 insertions(+), 1728 deletions(-) create mode 100644 plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java create mode 100644 plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java new file mode 100644 index 000000000000..142f97f8c274 --- /dev/null +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java @@ -0,0 +1,1728 @@ +// 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.vmware.resource; + +import com.cloud.agent.api.Command; +import com.cloud.agent.api.StartAnswer; +import com.cloud.agent.api.StartCommand; +import com.cloud.agent.api.storage.OVFPropertyTO; +import com.cloud.agent.api.to.DataStoreTO; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.api.to.NfsTO; +import com.cloud.agent.api.to.NicTO; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.configuration.Resource; +import com.cloud.hypervisor.vmware.manager.VmwareManager; +import com.cloud.hypervisor.vmware.mo.CustomFieldConstants; +import com.cloud.hypervisor.vmware.mo.DatacenterMO; +import com.cloud.hypervisor.vmware.mo.DatastoreFile; +import com.cloud.hypervisor.vmware.mo.DatastoreMO; +import com.cloud.hypervisor.vmware.mo.DiskControllerType; +import com.cloud.hypervisor.vmware.mo.HostMO; +import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; +import com.cloud.hypervisor.vmware.mo.TaskMO; +import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; +import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; +import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; +import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; +import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.hypervisor.vmware.util.VmwareHelper; +import com.cloud.network.Networks; +import com.cloud.storage.Storage; +import com.cloud.storage.Volume; +import com.cloud.storage.resource.VmwareStorageLayoutHelper; +import com.cloud.storage.resource.VmwareStorageProcessor; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.nicira.nvp.plugin.NiciraNvpApiVersion; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VmDetailConstants; +import com.vmware.vim25.BoolPolicy; +import com.vmware.vim25.DVPortConfigInfo; +import com.vmware.vim25.DVPortConfigSpec; +import com.vmware.vim25.DasVmPriority; +import com.vmware.vim25.DistributedVirtualPort; +import com.vmware.vim25.DistributedVirtualSwitchPortConnection; +import com.vmware.vim25.DistributedVirtualSwitchPortCriteria; +import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.OptionValue; +import com.vmware.vim25.VMwareDVSPortSetting; +import com.vmware.vim25.VirtualDevice; +import com.vmware.vim25.VirtualDeviceBackingInfo; +import com.vmware.vim25.VirtualDeviceConfigSpec; +import com.vmware.vim25.VirtualDeviceConfigSpecOperation; +import com.vmware.vim25.VirtualDisk; +import com.vmware.vim25.VirtualEthernetCard; +import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; +import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; +import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo; +import com.vmware.vim25.VirtualMachineBootOptions; +import com.vmware.vim25.VirtualMachineConfigSpec; +import com.vmware.vim25.VirtualMachineFileInfo; +import com.vmware.vim25.VirtualMachineFileLayoutEx; +import com.vmware.vim25.VirtualMachineGuestOsIdentifier; +import com.vmware.vim25.VirtualUSBController; +import com.vmware.vim25.VmConfigInfo; +import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.storage.configdrive.ConfigDrive; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import java.io.File; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class StartCommandExecutor { + private static final Logger LOGGER = Logger.getLogger(StartCommandExecutor.class); + + private final VmwareResource vmwareResource; + + public StartCommandExecutor(VmwareResource vmwareResource) { + this.vmwareResource = vmwareResource; + } + + // FR37 the monster blob god method: + protected StartAnswer execute(StartCommand cmd) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Executing resource StartCommand: " + vmwareResource.getGson().toJson(cmd)); + } + + // FR37 if startcommand contains a secendary storage URL or some flag or other type of indicator, deploy OVA as is + String secStorUrl = cmd.getSecondaryStorage(); + if (StringUtils.isNotEmpty(secStorUrl)) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(String.format("deploying OVA as is from %s", secStorUrl)); + } + } + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); + boolean vmAlreadyExistsInVcenter = false; + + String existingVmName = null; + VirtualMachineFileInfo existingVmFileInfo = null; + VirtualMachineFileLayoutEx existingVmFileLayout = null; + List existingDatastores = new ArrayList<>(); + + Pair names = composeVmNames(vmSpec); + String vmInternalCSName = names.first(); + String vmNameOnVcenter = names.second(); + String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER); + String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); + DiskTO rootDiskTO = null; + String bootMode = null; + if (vmSpec.getDetails().containsKey(VmDetailConstants.BOOT_MODE)) { + bootMode = vmSpec.getDetails().get(VmDetailConstants.BOOT_MODE); + } + if (null == bootMode) { + bootMode = ApiConstants.BootType.BIOS.toString(); + } + + // If root disk controller is scsi, then data disk controller would also be scsi instead of using 'osdefault' + // This helps avoid mix of different scsi subtype controllers in instance. + if (DiskControllerType.osdefault == DiskControllerType.getType(dataDiskController) && DiskControllerType.lsilogic == DiskControllerType.getType(rootDiskController)) { + dataDiskController = DiskControllerType.scsi.toString(); + } + + // Validate the controller types + dataDiskController = DiskControllerType.getType(dataDiskController).toString(); + rootDiskController = DiskControllerType.getType(rootDiskController).toString(); + + if (DiskControllerType.getType(rootDiskController) == DiskControllerType.none) { + throw new CloudRuntimeException("Invalid root disk controller detected : " + rootDiskController); + } + if (DiskControllerType.getType(dataDiskController) == DiskControllerType.none) { + throw new CloudRuntimeException("Invalid data disk controller detected : " + dataDiskController); + } + + Pair controllerInfo = new Pair<>(rootDiskController, dataDiskController); + + Boolean systemVm = vmSpec.getType().isUsedBySystem(); + // Thus, vmInternalCSName always holds i-x-y, the cloudstack generated internal VM name. + VmwareContext context = vmwareResource.getServiceContext(); + DatacenterMO dcMo = null; + try { + VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); + + VmwareHypervisorHost hyperHost = vmwareResource.getHyperHost(context); + dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter()); + + // Validate VM name is unique in Datacenter + VirtualMachineMO vmInVcenter = dcMo.checkIfVmAlreadyExistsInVcenter(vmNameOnVcenter, vmInternalCSName); + if (vmInVcenter != null) { + vmAlreadyExistsInVcenter = true; + String msg = "VM with name: " + vmNameOnVcenter + " already exists in vCenter."; + LOGGER.error(msg); + throw new Exception(msg); + } + // FR37 disks should not yet be our concern + String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value(); + DiskTO[] disks = validateDisks(vmSpec.getDisks()); + // FR37 this assert is not usefull if disks may be reconsiled later + assert (disks.length > 0); + + NicTO[] nics = vmSpec.getNics(); + + HashMap> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks, cmd); + if ((dataStoresDetails == null) || (dataStoresDetails.isEmpty())) { + String msg = "Unable to locate datastore details of the volumes to be attached"; + LOGGER.error(msg); + // throw a more specific Exception + throw new Exception(msg); + } + + DatastoreMO dsRootVolumeIsOn = getDatastoreThatRootDiskIsOn(dataStoresDetails, disks); + if (dsRootVolumeIsOn == null) { + String msg = "Unable to locate datastore details of root volume"; + LOGGER.error(msg); + // throw a more specific Exception + throw new Exception(msg); + } + + VirtualMachineDiskInfoBuilder diskInfoBuilder = null; + VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); + DiskControllerType systemVmScsiControllerType = DiskControllerType.lsilogic; + int firstScsiControllerBusNum = 0; + int numScsiControllerForSystemVm = 1; + boolean hasSnapshot = false; + if (vmMo != null) { + LOGGER.info("VM " + vmInternalCSName + " already exists, tear down devices for reconfiguration"); + if (VmwareResource.getVmPowerState(vmMo) != VirtualMachine.PowerState.PowerOff) + vmMo.safePowerOff(vmwareResource.getShutdownWaitMs()); + + // retrieve disk information before we tear down + diskInfoBuilder = vmMo.getDiskInfoBuilder(); + hasSnapshot = vmMo.hasSnapshot(); + if (!hasSnapshot) + vmMo.tearDownDevices(new Class[] {VirtualDisk.class, VirtualEthernetCard.class}); + else + vmMo.tearDownDevices(new Class[] {VirtualEthernetCard.class}); + if (systemVm) { + ensureScsiDiskControllers(vmMo, systemVmScsiControllerType.toString(), numScsiControllerForSystemVm, firstScsiControllerBusNum); + } else { + ensureDiskControllers(vmMo, controllerInfo); + } + } else { + ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter(); + assert (morDc != null); + + vmMo = hyperHost.findVmOnPeerHyperHost(vmInternalCSName); + if (vmMo != null) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Found vm " + vmInternalCSName + " at other host, relocate to " + hyperHost.getHyperHostName()); + } + + takeVmFromOtherHyperHost(hyperHost, vmInternalCSName); + + if (VmwareResource.getVmPowerState(vmMo) != VirtualMachine.PowerState.PowerOff) + vmMo.safePowerOff(vmwareResource.getShutdownWaitMs()); + + diskInfoBuilder = vmMo.getDiskInfoBuilder(); + hasSnapshot = vmMo.hasSnapshot(); + if (!hasSnapshot) + vmMo.tearDownDevices(new Class[] {VirtualDisk.class, VirtualEthernetCard.class}); + else + vmMo.tearDownDevices(new Class[] {VirtualEthernetCard.class}); + + if (systemVm) { + // System volumes doesn't require more than 1 SCSI controller as there is no requirement for data volumes. + ensureScsiDiskControllers(vmMo, systemVmScsiControllerType.toString(), numScsiControllerForSystemVm, firstScsiControllerBusNum); + } else { + ensureDiskControllers(vmMo, controllerInfo); + } + } else { + // If a VM with the same name is found in a different cluster in the DC, unregister the old VM and configure a new VM (cold-migration). + VirtualMachineMO existingVmInDc = dcMo.findVm(vmInternalCSName); + if (existingVmInDc != null) { + LOGGER.debug("Found VM: " + vmInternalCSName + " on a host in a different cluster. Unregistering the exisitng VM."); + existingVmName = existingVmInDc.getName(); + existingVmFileInfo = existingVmInDc.getFileInfo(); + existingVmFileLayout = existingVmInDc.getFileLayout(); + existingDatastores = existingVmInDc.getAllDatastores(); + existingVmInDc.unregisterVm(); + } + Pair rootDiskDataStoreDetails = null; + for (DiskTO vol : disks) { + if (vol.getType() == Volume.Type.ROOT) { + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + if (managed) { + String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); + + rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); + } else { + DataStoreTO primaryStore = vol.getData().getDataStore(); + + rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + } + } + } + + assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); + + boolean vmFolderExists = rootDiskDataStoreDetails.second().folderExists(String.format("[%s]", rootDiskDataStoreDetails.second().getName()), vmNameOnVcenter); + String vmxFileFullPath = dsRootVolumeIsOn.searchFileInSubFolders(vmNameOnVcenter + ".vmx", false, VmwareManager.s_vmwareSearchExcludeFolder.value()); + if (vmFolderExists && vmxFileFullPath != null) { // VM can be registered only if .vmx is present. + registerVm(vmNameOnVcenter, dsRootVolumeIsOn, vmwareResource); + vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); + if (vmMo != null) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Found registered vm " + vmInternalCSName + " at host " + hyperHost.getHyperHostName()); + } + } + tearDownVm(vmMo); + } else { + // FR37 create blank or install as is ???? + if (!hyperHost + .createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmwareResource.getReservedCpuMHZ(vmSpec), vmSpec.getLimitCpuUse(), (int)(vmSpec.getMaxRam() / Resource.ResourceType.bytesToMiB), vmwareResource.getReservedMemoryMb(vmSpec), guestOsId, + rootDiskDataStoreDetails.first(), false, controllerInfo, systemVm)) { + throw new Exception("Failed to create VM. vmName: " + vmInternalCSName); + } + } + } + + vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); + if (vmMo == null) { + throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmInternalCSName); + } + } + + int totalChangeDevices = disks.length + nics.length; + // vApp cdrom device + // HACK ALERT: ovf properties might not be the only or defining feature of vApps; needs checking + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("adding divice tie device count for vApp config ISO"); + } + if (vmSpec.getOvfProperties() != null) { + totalChangeDevices++; + } + + DiskTO volIso = null; + if (vmSpec.getType() != VirtualMachine.Type.User) { + // system VM needs a patch ISO + totalChangeDevices++; + } else { + volIso = getIsoDiskTO(disks); + if (volIso == null) + totalChangeDevices++; + } + + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + + VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmwareResource.getReservedCpuMHZ(vmSpec), (int)(vmSpec.getMaxRam() / (1024 * 1024)), + vmwareResource.getReservedMemoryMb(vmSpec), guestOsId, vmSpec.getLimitCpuUse()); + + // Check for multi-cores per socket settings + int numCoresPerSocket = 1; + String coresPerSocket = vmSpec.getDetails().get(VmDetailConstants.CPU_CORE_PER_SOCKET); + if (coresPerSocket != null) { + String apiVersion = HypervisorHostHelper.getVcenterApiVersion(vmMo.getContext()); + // Property 'numCoresPerSocket' is supported since vSphere API 5.0 + if (apiVersion.compareTo("5.0") >= 0) { + numCoresPerSocket = NumbersUtil.parseInt(coresPerSocket, 1); + vmConfigSpec.setNumCoresPerSocket(numCoresPerSocket); + } + } + + // Check for hotadd settings + vmConfigSpec.setMemoryHotAddEnabled(vmMo.isMemoryHotAddSupported(guestOsId)); + + String hostApiVersion = ((HostMO)hyperHost).getHostAboutInfo().getApiVersion(); + if (numCoresPerSocket > 1 && hostApiVersion.compareTo("5.0") < 0) { + LOGGER.warn("Dynamic scaling of CPU is not supported for Virtual Machines with multi-core vCPUs in case of ESXi hosts 4.1 and prior. Hence CpuHotAdd will not be" + + " enabled for Virtual Machine: " + vmInternalCSName); + vmConfigSpec.setCpuHotAddEnabled(false); + } else { + vmConfigSpec.setCpuHotAddEnabled(vmMo.isCpuHotAddSupported(guestOsId)); + } + + vmwareResource.configNestedHVSupport(vmMo, vmSpec, vmConfigSpec); + + VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[totalChangeDevices]; + int i = 0; + int ideUnitNumber = 0; + int scsiUnitNumber = 0; + int ideControllerKey = vmMo.getIDEDeviceControllerKey(); + int scsiControllerKey = vmMo.getGenericScsiDeviceControllerKeyNoException(); + int controllerKey; + + // + // Setup ISO device + // + + // vAPP ISO + // FR37 the native deploy mechs should create this for us + if (vmSpec.getOvfProperties() != null) { + if (LOGGER.isTraceEnabled()) { + // FR37 TODO add more usefull info (if we keep this bit + LOGGER.trace("adding iso for properties for 'xxx'"); + } + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + Pair isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1); + deviceConfigSpecArray[i].setDevice(isoInfo.first()); + if (isoInfo.second()) { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare vApp ISO volume at existing device " + vmwareResource.getGson().toJson(isoInfo.first())); + + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare vApp ISO volume at existing device " + vmwareResource.getGson().toJson(isoInfo.first())); + + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + i++; + } + + // prepare systemvm patch ISO + if (vmSpec.getType() != VirtualMachine.Type.User) { + // attach ISO (for patching of system VM) + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(vmwareResource.getDcId())); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); + if (secStoreUrl == null) { + String msg = "secondary storage for dc " + vmwareResource.getDcId() + " is not ready yet?"; + throw new Exception(msg); + } + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); + + ManagedObjectReference morSecDs = vmwareResource.prepareSecondaryDatastoreOnHost(secStoreUrl); + if (morSecDs == null) { + String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl; + throw new Exception(msg); + } + DatastoreMO secDsMo = new DatastoreMO(hyperHost.getContext(), morSecDs); + + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + Pair isoInfo = VmwareHelper + .prepareIsoDevice(vmMo, String.format("[%s] systemvm/%s", secDsMo.getName(), mgr.getSystemVMIsoFileNameOnDatastore()), secDsMo.getMor(), true, true, + ideUnitNumber++, i + 1); + deviceConfigSpecArray[i].setDevice(isoInfo.first()); + if (isoInfo.second()) { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare ISO volume at new device " + vmwareResource.getGson().toJson(isoInfo.first())); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare ISO volume at existing device " + vmwareResource.getGson().toJson(isoInfo.first())); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + i++; + } else { + // Note: we will always plug a CDROM device + if (volIso != null) { + for (DiskTO vol : disks) { + if (vol.getType() == Volume.Type.ISO) { + + TemplateObjectTO iso = (TemplateObjectTO)vol.getData(); + + if (iso.getPath() != null && !iso.getPath().isEmpty()) { + DataStoreTO imageStore = iso.getDataStore(); + if (!(imageStore instanceof NfsTO)) { + LOGGER.debug("unsupported protocol"); + throw new Exception("unsupported protocol"); + } + NfsTO nfsImageStore = (NfsTO)imageStore; + String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath(); + Pair isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath); + assert (isoDatastoreInfo != null); + assert (isoDatastoreInfo.second() != null); + + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + Pair isoInfo = VmwareHelper + .prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber++, i + 1); + deviceConfigSpecArray[i].setDevice(isoInfo.first()); + if (isoInfo.second()) { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare ISO volume at new device " + vmwareResource.getGson().toJson(isoInfo.first())); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare ISO volume at existing device " + vmwareResource.getGson().toJson(isoInfo.first())); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + } + i++; + } + } + } else { + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + Pair isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1); + deviceConfigSpecArray[i].setDevice(isoInfo.first()); + if (isoInfo.second()) { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare ISO volume at existing device " + vmwareResource.getGson().toJson(isoInfo.first())); + + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare ISO volume at existing device " + vmwareResource.getGson().toJson(isoInfo.first())); + + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + i++; + } + } + + // + // Setup ROOT/DATA disk devices + // + DiskTO[] sortedDisks = sortVolumesByDeviceId(disks); + for (DiskTO vol : sortedDisks) { + if (vol.getType() == Volume.Type.ISO) + continue; + + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context); + controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey); + String diskController = getDiskController(vmMo, matchingExistingDisk, vol, new Pair<>(rootDiskController, dataDiskController)); + + if (DiskControllerType.getType(diskController) == DiskControllerType.osdefault) { + diskController = vmMo.getRecommendedDiskController(null); + } + if (DiskControllerType.getType(diskController) == DiskControllerType.ide) { + controllerKey = vmMo.getIDEControllerKey(ideUnitNumber); + if (vol.getType() == Volume.Type.DATADISK) { + // Could be result of flip due to user configured setting or "osdefault" for data disks + // Ensure maximum of 2 data volumes over IDE controller, 3 includeing root volume + if (vmMo.getNumberOfVirtualDisks() > 3) { + throw new CloudRuntimeException( + "Found more than 3 virtual disks attached to this VM [" + vmMo.getVmName() + "]. Unable to implement the disks over " + diskController + " controller, as maximum number of devices supported over IDE controller is 4 includeing CDROM device."); + } + } + } else { + controllerKey = vmMo.getScsiDiskControllerKeyNoException(diskController); + if (controllerKey == -1) { + // This may happen for ROOT legacy VMs which doesn't have recommended disk controller when global configuration parameter 'vmware.root.disk.controller' is set to "osdefault" + // Retrieve existing controller and use. + Ternary vmScsiControllerInfo = vmMo.getScsiControllerInfo(); + DiskControllerType existingControllerType = vmScsiControllerInfo.third(); + controllerKey = vmMo.getScsiDiskControllerKeyNoException(existingControllerType.toString()); + } + } + if (!hasSnapshot) { + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + + VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + DataStoreTO primaryStore = volumeTO.getDataStore(); + Map details = vol.getDetails(); + boolean managed = false; + String iScsiName = null; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + iScsiName = details.get(DiskTO.IQN); + } + + // if the storage is managed, iScsiName should not be null + String datastoreName = managed ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); + Pair volumeDsDetails = dataStoresDetails.get(datastoreName); + + assert (volumeDsDetails != null); + + String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, vol, matchingExistingDisk, dataStoresDetails); + if (controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) + scsiUnitNumber++; + VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, diskChain, volumeDsDetails.first(), + (controllerKey == vmMo.getIDEControllerKey(ideUnitNumber)) ? ((ideUnitNumber++) % VmwareHelper.MAX_IDE_CONTROLLER_COUNT) : scsiUnitNumber++, i + 1); + + if (vol.getType() == Volume.Type.ROOT) + rootDiskTO = vol; + deviceConfigSpecArray[i].setDevice(device); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare volume at new device " + vmwareResource.getGson().toJson(device)); + + i++; + } else { + if (controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) + scsiUnitNumber++; + if (controllerKey == vmMo.getIDEControllerKey(ideUnitNumber)) + ideUnitNumber++; + else + scsiUnitNumber++; + } + } + + // + // Setup USB devices + // + if (guestOsId.startsWith("darwin")) { //Mac OS + VirtualDevice[] devices = vmMo.getMatchedDevices(new Class[] {VirtualUSBController.class}); + if (devices.length == 0) { + LOGGER.debug("No USB Controller device on VM Start. Add USB Controller device for Mac OS VM " + vmInternalCSName); + + //For Mac OS X systems, the EHCI+UHCI controller is enabled by default and is required for USB mouse and keyboard access. + VirtualDevice usbControllerDevice = VmwareHelper.prepareUSBControllerDevice(); + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + deviceConfigSpecArray[i].setDevice(usbControllerDevice); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare USB controller at new device " + vmwareResource.getGson().toJson(deviceConfigSpecArray[i])); + + i++; + } else { + LOGGER.debug("USB Controller device exists on VM Start for Mac OS VM " + vmInternalCSName); + } + } + + // + // Setup NIC devices + // + VirtualDevice nic; + int nicMask = 0; + int nicCount = 0; + + if (vmSpec.getType() == VirtualMachine.Type.DomainRouter) { + int extraPublicNics = mgr.getRouterExtraPublicNics(); + if (extraPublicNics > 0 && vmSpec.getDetails().containsKey("PeerRouterInstanceName")) { + //Set identical MAC address for RvR on extra public interfaces + String peerRouterInstanceName = vmSpec.getDetails().get("PeerRouterInstanceName"); + + VirtualMachineMO peerVmMo = hyperHost.findVmOnHyperHost(peerRouterInstanceName); + if (peerVmMo == null) { + peerVmMo = hyperHost.findVmOnPeerHyperHost(peerRouterInstanceName); + } + + if (peerVmMo != null) { + String oldMacSequence = generateMacSequence(nics); + + for (int nicIndex = nics.length - extraPublicNics; nicIndex < nics.length; nicIndex++) { + VirtualDevice nicDevice = peerVmMo.getNicDeviceByIndex(nics[nicIndex].getDeviceId()); + if (nicDevice != null) { + String mac = ((VirtualEthernetCard)nicDevice).getMacAddress(); + if (mac != null) { + LOGGER.info("Use same MAC as previous RvR, the MAC is " + mac + " for extra NIC with device id: " + nics[nicIndex].getDeviceId()); + nics[nicIndex].setMac(mac); + } + } + } + + if (!StringUtils.isBlank(vmSpec.getBootArgs())) { + String newMacSequence = generateMacSequence(nics); + vmSpec.setBootArgs(vmwareResource.replaceNicsMacSequenceInBootArgs(oldMacSequence, newMacSequence, vmSpec)); + } + } + } + } + + VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.valueOf(vmSpec.getDetails().get(VmDetailConstants.NIC_ADAPTER)); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("VM " + vmInternalCSName + " will be started with NIC device type: " + nicDeviceType); + + NiciraNvpApiVersion.logNiciraApiVersion(); + + Map nicUuidToDvSwitchUuid = new HashMap<>(); + for (NicTO nicTo : sortNicsByDeviceId(nics)) { + LOGGER.info("Prepare NIC device based on NicTO: " + vmwareResource.getGson().toJson(nicTo)); + + boolean configureVServiceInNexus = (nicTo.getType() == Networks.TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus")); + VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); + Pair networkInfo = vmwareResource.prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, vmType); + if ((nicTo.getBroadcastType() != Networks.BroadcastDomainType.Lswitch) || (nicTo.getBroadcastType() == Networks.BroadcastDomainType.Lswitch && NiciraNvpApiVersion.isApiVersionLowerThan("4.2"))) { + if (VmwareHelper.isDvPortGroup(networkInfo.first())) { + String dvSwitchUuid; + ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); + DatacenterMO dataCenterMo = new DatacenterMO(context, dcMor); + ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first()); + dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor); + LOGGER.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid); + nic = VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid, nicTo.getMac(), i + 1, true, true); + if (nicTo.getUuid() != null) { + nicUuidToDvSwitchUuid.put(nicTo.getUuid(), dvSwitchUuid); + } + } else { + LOGGER.info("Preparing NIC device on network " + networkInfo.second()); + nic = VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), nicTo.getMac(), i + 1, true, true); + } + } else { + //if NSX API VERSION >= 4.2, connect to br-int (nsx.network), do not create portgroup else previous behaviour + nic = VmwareHelper.prepareNicOpaque(vmMo, nicDeviceType, networkInfo.second(), nicTo.getMac(), i + 1, true, true); + } + + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + deviceConfigSpecArray[i].setDevice(nic); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Prepare NIC at new device " + vmwareResource.getGson().toJson(deviceConfigSpecArray[i])); + + // this is really a hacking for DomR, upon DomR startup, we will reset all the NIC allocation after eth3 + if (nicCount < 3) + nicMask |= (1 << nicCount); + + i++; + nicCount++; + } + + for (int j = 0; j < i; j++) + vmConfigSpec.getDeviceChange().add(deviceConfigSpecArray[j]); + + // + // Setup VM options + // + + // pass boot arguments through machine.id & perform customized options to VMX + ArrayList extraOptions = new ArrayList<>(); + configBasicExtraOption(extraOptions, vmSpec); + configNvpExtraOption(extraOptions, vmSpec, nicUuidToDvSwitchUuid); + configCustomExtraOption(extraOptions, vmSpec); + + // config for NCC + VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); + if (vmType.equals(VirtualMachine.Type.NetScalerVm)) { + NicTO mgmtNic = vmSpec.getNics()[0]; + OptionValue option = new OptionValue(); + option.setKey("machine.id"); + option.setValue("ip=" + mgmtNic.getIp() + "&netmask=" + mgmtNic.getNetmask() + "&gateway=" + mgmtNic.getGateway()); + extraOptions.add(option); + } + + // config VNC + String keyboardLayout = null; + if (vmSpec.getDetails() != null) + keyboardLayout = vmSpec.getDetails().get(VmDetailConstants.KEYBOARD); + vmConfigSpec.getExtraConfig().addAll( + Arrays.asList(vmwareResource.configureVnc(extraOptions.toArray(new OptionValue[0]), hyperHost, vmInternalCSName, vmSpec.getVncPassword(), keyboardLayout))); + + // config video card + vmwareResource.configureVideoCard(vmMo, vmSpec, vmConfigSpec); + + // Set OVF properties (if available) + Pair> ovfPropsMap = vmSpec.getOvfProperties(); + VmConfigInfo templateVappConfig; + List ovfProperties; + if (ovfPropsMap != null) { + String vmTemplate = ovfPropsMap.first(); + LOGGER.info("Find VM template " + vmTemplate); + VirtualMachineMO vmTemplateMO = dcMo.findVm(vmTemplate); + templateVappConfig = vmTemplateMO.getConfigInfo().getVAppConfig(); + ovfProperties = ovfPropsMap.second(); + // Set OVF properties (if available) + if (CollectionUtils.isNotEmpty(ovfProperties)) { + LOGGER.info("Copying OVF properties from template and setting them to the values the user provided"); + vmwareResource.copyVAppConfigsFromTemplate(templateVappConfig, ovfProperties, vmConfigSpec); + } + } + + setBootOptions(vmSpec, bootMode, vmConfigSpec); + + // + // Configure VM + // + if (!vmMo.configureVm(vmConfigSpec)) { + throw new Exception("Failed to configure VM before start. vmName: " + vmInternalCSName); + } + + if (vmSpec.getType() == VirtualMachine.Type.DomainRouter) { + hyperHost.setRestartPriorityForVM(vmMo, DasVmPriority.HIGH.value()); + } + + // Resizing root disk only when explicit requested by user + final Map vmDetails = cmd.getVirtualMachine().getDetails(); + if (rootDiskTO != null && !hasSnapshot && (vmDetails != null && vmDetails.containsKey(ApiConstants.ROOT_DISK_SIZE))) { + resizeRootDiskOnVMStart(vmMo, rootDiskTO, hyperHost, context); + } + + // + // Post Configuration + // + + vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMask)); + postNvpConfigBeforeStart(vmMo, vmSpec); + + Map> iqnToData = new HashMap<>(); + + postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToData, hyperHost, context); + + // + // Power-on VM + // + if (!vmMo.powerOn()) { + throw new Exception("Failed to start VM. vmName: " + vmInternalCSName + " with hostname " + vmNameOnVcenter); + } + + StartAnswer startAnswer = new StartAnswer(cmd); + + startAnswer.setIqnToData(iqnToData); + + // Since VM was successfully powered-on, if there was an existing VM in a different cluster that was unregistered, delete all the files associated with it. + if (existingVmName != null && existingVmFileLayout != null) { + List vmDatastoreNames = new ArrayList<>(); + for (DatastoreMO vmDatastore : vmMo.getAllDatastores()) { + vmDatastoreNames.add(vmDatastore.getName()); + } + // Don't delete files that are in a datastore that is being used by the new VM as well (zone-wide datastore). + List skipDatastores = new ArrayList<>(); + for (DatastoreMO existingDatastore : existingDatastores) { + if (vmDatastoreNames.contains(existingDatastore.getName())) { + skipDatastores.add(existingDatastore.getName()); + } + } + vmwareResource.deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true, skipDatastores); + } + + return startAnswer; + } catch (Throwable e) { + if (e instanceof RemoteException) { + LOGGER.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + vmwareResource.invalidateServiceContext(); + } + + String msg = "StartCommand failed due to " + VmwareHelper.getExceptionMessage(e); + LOGGER.warn(msg, e); + StartAnswer startAnswer = new StartAnswer(cmd, msg); + if (vmAlreadyExistsInVcenter) { + startAnswer.setContextParam("stopRetry", "true"); + } + + // Since VM start failed, if there was an existing VM in a different cluster that was unregistered, register it back. + if (existingVmName != null && existingVmFileInfo != null) { + LOGGER.debug("Since VM start failed, registering back an existing VM: " + existingVmName + " that was unregistered"); + try { + DatastoreFile fileInDatastore = new DatastoreFile(existingVmFileInfo.getVmPathName()); + DatastoreMO existingVmDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); + registerVm(existingVmName, existingVmDsMo, vmwareResource); + } catch (Exception ex) { + String message = "Failed to register an existing VM: " + existingVmName + " due to " + VmwareHelper.getExceptionMessage(ex); + LOGGER.warn(message, ex); + } + } + + return startAnswer; + } finally { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(String.format("finally done with %s", vmwareResource.getGson().toJson(cmd))); + } + } + } + + /** + * Registers the vm to the inventory given the vmx file. + * @param vmName + * @param dsMo + * @param vmwareResource + */ + private void registerVm(String vmName, DatastoreMO dsMo, VmwareResource vmwareResource) throws Exception { + + //1st param + VmwareHypervisorHost hyperHost = vmwareResource.getHyperHost(vmwareResource.getServiceContext()); + ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); + DatacenterMO dataCenterMo = new DatacenterMO(vmwareResource.getServiceContext(), dcMor); + ManagedObjectReference vmFolderMor = dataCenterMo.getVmFolder(); + + //2nd param + String vmxFilePath = dsMo.searchFileInSubFolders(vmName + ".vmx", false, VmwareManager.s_vmwareSearchExcludeFolder.value()); + + // 5th param + ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool(); + + ManagedObjectReference morTask = vmwareResource.getServiceContext().getService().registerVMTask(vmFolderMor, vmxFilePath, vmName, false, morPool, hyperHost.getMor()); + boolean result = vmwareResource.getServiceContext().getVimClient().waitForTask(morTask); + if (!result) { + throw new Exception("Unable to register vm due to " + TaskMO.getTaskFailureInfo(vmwareResource.getServiceContext(), morTask)); + } else { + vmwareResource.getServiceContext().waitForTaskProgressDone(morTask); + } + + } + + // Pair + private Pair composeVmNames(VirtualMachineTO vmSpec) { + String vmInternalCSName = vmSpec.getName(); + String vmNameOnVcenter = vmSpec.getName(); + if (VmwareResource.instanceNameFlag && vmSpec.getHostName() != null) { + vmNameOnVcenter = vmSpec.getHostName(); + } + return new Pair(vmInternalCSName, vmNameOnVcenter); + } + + private VirtualMachineGuestOsIdentifier translateGuestOsIdentifier(String cpuArchitecture, String guestOs, String cloudGuestOs) { + if (cpuArchitecture == null) { + LOGGER.warn("CPU arch is not set, default to i386. guest os: " + guestOs); + cpuArchitecture = "i386"; + } + + if (cloudGuestOs == null) { + LOGGER.warn("Guest OS mapping name is not set for guest os: " + guestOs); + } + + VirtualMachineGuestOsIdentifier identifier = null; + try { + if (cloudGuestOs != null) { + identifier = VirtualMachineGuestOsIdentifier.fromValue(cloudGuestOs); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Using mapping name : " + identifier.toString()); + } + } + } catch (IllegalArgumentException e) { + LOGGER.warn("Unable to find Guest OS Identifier in VMware for mapping name: " + cloudGuestOs + ". Continuing with defaults."); + } + if (identifier != null) { + return identifier; + } + + if (cpuArchitecture.equalsIgnoreCase("x86_64")) { + return VirtualMachineGuestOsIdentifier.OTHER_GUEST_64; + } + return VirtualMachineGuestOsIdentifier.OTHER_GUEST; + } + private DiskTO[] validateDisks(DiskTO[] disks) { + List validatedDisks = new ArrayList(); + + for (DiskTO vol : disks) { + if (vol.getType() != Volume.Type.ISO) { + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); + DataStoreTO primaryStore = volumeTO.getDataStore(); + if (primaryStore.getUuid() != null && !primaryStore.getUuid().isEmpty()) { + validatedDisks.add(vol); + } + } else if (vol.getType() == Volume.Type.ISO) { + TemplateObjectTO templateTO = (TemplateObjectTO) vol.getData(); + if (templateTO.getPath() != null && !templateTO.getPath().isEmpty()) { + validatedDisks.add(vol); + } + } else { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Drop invalid disk option, volumeTO: " + vmwareResource.getGson().toJson(vol)); + } + } + } + Collections.sort(validatedDisks, (d1, d2) -> d1.getDiskSeq().compareTo(d2.getDiskSeq())); + return validatedDisks.toArray(new DiskTO[0]); + } + private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, + DiskTO[] disks, Command cmd) throws Exception { + HashMap> mapIdToMors = new HashMap<>(); + + assert (hyperHost != null) && (context != null); + + for (DiskTO vol : disks) { + if (vol.getType() != Volume.Type.ISO) { + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); + DataStoreTO primaryStore = volumeTO.getDataStore(); + String poolUuid = primaryStore.getUuid(); + + if (mapIdToMors.get(poolUuid) == null) { + boolean isManaged = false; + Map details = vol.getDetails(); + + if (details != null) { + isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + if (isManaged) { + String iScsiName = details.get(DiskTO.IQN); // details should not be null for managed storage (it may or may not be null for non-managed storage) + String datastoreName = VmwareResource.getDatastoreName(iScsiName); + ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreName); + + // if the datastore is not present, we need to discover the iSCSI device that will support it, + // create the datastore, and create a VMDK file in the datastore + if (morDatastore == null) { + final String vmdkPath = vmwareResource.getVmdkPath(volumeTO.getPath()); + + morDatastore = getStorageProcessor().prepareManagedStorage(context, hyperHost, null, iScsiName, + details.get(DiskTO.STORAGE_HOST), Integer.parseInt(details.get(DiskTO.STORAGE_PORT)), + vmdkPath, + details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), + details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET), + Long.parseLong(details.get(DiskTO.VOLUME_SIZE)), cmd); + + DatastoreMO dsMo = new DatastoreMO(vmwareResource.getServiceContext(), morDatastore); + + final String datastoreVolumePath; + + if (vmdkPath != null) { + datastoreVolumePath = dsMo.getDatastorePath(vmdkPath + VmwareResource.VMDK_EXTENSION); + } else { + datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + VmwareResource.VMDK_EXTENSION); + } + + volumeTO.setPath(datastoreVolumePath); + vol.setPath(datastoreVolumePath); + } + + mapIdToMors.put(datastoreName, new Pair<>(morDatastore, new DatastoreMO(context, morDatastore))); + } else { + ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid); + + if (morDatastore == null) { + String msg = "Failed to get the mounted datastore for the volume's pool " + poolUuid; + + LOGGER.error(msg); + + throw new Exception(msg); + } + + mapIdToMors.put(poolUuid, new Pair<>(morDatastore, new DatastoreMO(context, morDatastore))); + } + } + } + } + + return mapIdToMors; + } + + private VmwareStorageProcessor getStorageProcessor() { + return vmwareResource.getStorageProcessor(); + } + + private DatastoreMO getDatastoreThatRootDiskIsOn(HashMap> dataStoresDetails, DiskTO disks[]) { + Pair rootDiskDataStoreDetails = null; + + for (DiskTO vol : disks) { + if (vol.getType() == Volume.Type.ROOT) { + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + if (managed) { + String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); + + rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); + + break; + } else { + DataStoreTO primaryStore = vol.getData().getDataStore(); + + rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + + break; + } + } + } + + if (rootDiskDataStoreDetails != null) { + return rootDiskDataStoreDetails.second(); + } + + return null; + } + + private void ensureDiskControllers(VirtualMachineMO vmMo, Pair controllerInfo) throws Exception { + if (vmMo == null) { + return; + } + + String msg; + String rootDiskController = controllerInfo.first(); + String dataDiskController = controllerInfo.second(); + String scsiDiskController; + String recommendedDiskController = null; + + if (VmwareHelper.isControllerOsRecommended(dataDiskController) || VmwareHelper.isControllerOsRecommended(rootDiskController)) { + recommendedDiskController = vmMo.getRecommendedDiskController(null); + } + scsiDiskController = HypervisorHostHelper.getScsiController(new Pair(rootDiskController, dataDiskController), recommendedDiskController); + if (scsiDiskController == null) { + return; + } + + vmMo.getScsiDeviceControllerKeyNoException(); + // This VM needs SCSI controllers. + // Get count of existing scsi controllers. Helps not to attempt to create more than the maximum allowed 4 + // Get maximum among the bus numbers in use by scsi controllers. Safe to pick maximum, because we always go sequential allocating bus numbers. + Ternary scsiControllerInfo = vmMo.getScsiControllerInfo(); + int requiredNumScsiControllers = VmwareHelper.MAX_SCSI_CONTROLLER_COUNT - scsiControllerInfo.first(); + int availableBusNum = scsiControllerInfo.second() + 1; // method returned current max. bus number + + if (requiredNumScsiControllers == 0) { + return; + } + if (scsiControllerInfo.first() > 0) { + // For VMs which already have a SCSI controller, do NOT attempt to add any more SCSI controllers & return the sub type. + // For Legacy VMs would have only 1 LsiLogic Parallel SCSI controller, and doesn't require more. + // For VMs created post device ordering support, 4 SCSI subtype controllers are ensured during deployment itself. No need to add more. + // For fresh VM deployment only, all required controllers should be ensured. + return; + } + ensureScsiDiskControllers(vmMo, scsiDiskController, requiredNumScsiControllers, availableBusNum); + } + + private void ensureScsiDiskControllers(VirtualMachineMO vmMo, String scsiDiskController, int requiredNumScsiControllers, int availableBusNum) throws Exception { + // Pick the sub type of scsi + if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.pvscsi) { + if (!vmMo.isPvScsiSupported()) { + String msg = "This VM doesn't support Vmware Paravirtual SCSI controller for virtual disks, because the virtual hardware version is less than 7."; + throw new Exception(msg); + } + vmMo.ensurePvScsiDeviceController(requiredNumScsiControllers, availableBusNum); + } else if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.lsisas1068) { + vmMo.ensureLsiLogicSasDeviceControllers(requiredNumScsiControllers, availableBusNum); + } else if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.buslogic) { + vmMo.ensureBusLogicDeviceControllers(requiredNumScsiControllers, availableBusNum); + } else if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.lsilogic) { + vmMo.ensureLsiLogicDeviceControllers(requiredNumScsiControllers, availableBusNum); + } + } + + private VirtualMachineMO takeVmFromOtherHyperHost(VmwareHypervisorHost hyperHost, String vmName) throws Exception { + + VirtualMachineMO vmMo = hyperHost.findVmOnPeerHyperHost(vmName); + if (vmMo != null) { + ManagedObjectReference morTargetPhysicalHost = hyperHost.findMigrationTarget(vmMo); + if (morTargetPhysicalHost == null) { + String msg = "VM " + vmName + " is on other host and we have no resource available to migrate and start it here"; + LOGGER.error(msg); + throw new Exception(msg); + } + + if (!vmMo.relocate(morTargetPhysicalHost)) { + String msg = "VM " + vmName + " is on other host and we failed to relocate it here"; + LOGGER.error(msg); + throw new Exception(msg); + } + + return vmMo; + } + return null; + } + + private void tearDownVm(VirtualMachineMO vmMo) throws Exception { + + if (vmMo == null) + return; + + boolean hasSnapshot = false; + hasSnapshot = vmMo.hasSnapshot(); + if (!hasSnapshot) + vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); + else + vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); + vmMo.ensureScsiDeviceController(); + } + + private static DiskTO getIsoDiskTO(DiskTO[] disks) { + for (DiskTO vol : disks) { + if (vol.getType() == Volume.Type.ISO) { + return vol; + } + } + return null; + } + + // isoUrl sample content : + // nfs://192.168.10.231/export/home/kelven/vmware-test/secondary/template/tmpl/2/200//200-2-80f7ee58-6eff-3a2d-bcb0-59663edf6d26.iso + private Pair getIsoDatastoreInfo(VmwareHypervisorHost hyperHost, String isoUrl) throws Exception { + + assert (isoUrl != null); + int isoFileNameStartPos = isoUrl.lastIndexOf("/"); + if (isoFileNameStartPos < 0) { + throw new Exception("Invalid ISO path info"); + } + + String isoFileName = isoUrl.substring(isoFileNameStartPos); + + int templateRootPos = isoUrl.indexOf("template/tmpl"); + templateRootPos = (templateRootPos < 0 ? isoUrl.indexOf(ConfigDrive.CONFIGDRIVEDIR) : templateRootPos); + if (templateRootPos < 0) { + throw new Exception("Invalid ISO path info"); + } + + String storeUrl = isoUrl.substring(0, templateRootPos - 1); + String isoPath = isoUrl.substring(templateRootPos, isoFileNameStartPos); + + ManagedObjectReference morDs = vmwareResource.prepareSecondaryDatastoreOnHost(storeUrl); + DatastoreMO dsMo = new DatastoreMO(vmwareResource.getServiceContext(), morDs); + + return new Pair(String.format("[%s] %s%s", dsMo.getName(), isoPath, isoFileName), morDs); + } + + private static DiskTO[] sortVolumesByDeviceId(DiskTO[] volumes) { + + List listForSort = new ArrayList(); + for (DiskTO vol : volumes) { + listForSort.add(vol); + } + Collections.sort(listForSort, new Comparator() { + + @Override + public int compare(DiskTO arg0, DiskTO arg1) { + if (arg0.getDiskSeq() < arg1.getDiskSeq()) { + return -1; + } else if (arg0.getDiskSeq().equals(arg1.getDiskSeq())) { + return 0; + } + + return 1; + } + }); + + return listForSort.toArray(new DiskTO[0]); + } + + private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) { + + int controllerKey; + if (matchingExistingDisk != null) { + LOGGER.info("Chose disk controller based on existing information: " + matchingExistingDisk.getDiskDeviceBusName()); + if (matchingExistingDisk.getDiskDeviceBusName().startsWith("ide")) + return ideControllerKey; + else + return scsiControllerKey; + } + + if (vol.getType() == Volume.Type.ROOT) { + Map vmDetails = vmSpec.getDetails(); + if (vmDetails != null && vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER) != null) { + if (vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER).equalsIgnoreCase("scsi")) { + LOGGER.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: " + + vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER)); + controllerKey = scsiControllerKey; + } else { + LOGGER.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: " + + vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER)); + controllerKey = ideControllerKey; + } + } else { + LOGGER.info("Chose disk controller for vol " + vol.getType() + " -> scsi. due to null root disk controller setting"); + controllerKey = scsiControllerKey; + } + + } else { + // DATA volume always use SCSI device + LOGGER.info("Chose disk controller for vol " + vol.getType() + " -> scsi"); + controllerKey = scsiControllerKey; + } + + return controllerKey; + } + + private String getDiskController(VirtualMachineMO vmMo, VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, Pair controllerInfo) throws Exception { + int controllerKey; + DiskControllerType controllerType = DiskControllerType.none; + if (matchingExistingDisk != null) { + String currentBusName = matchingExistingDisk.getDiskDeviceBusName(); + if (currentBusName != null) { + LOGGER.info("Chose disk controller based on existing information: " + currentBusName); + if (currentBusName.startsWith("ide")) { + controllerType = DiskControllerType.ide; + } else if (currentBusName.startsWith("scsi")) { + controllerType = DiskControllerType.scsi; + } + } + if (controllerType == DiskControllerType.scsi || controllerType == DiskControllerType.none) { + Ternary vmScsiControllerInfo = vmMo.getScsiControllerInfo(); + controllerType = vmScsiControllerInfo.third(); + } + return controllerType.toString(); + } + + if (vol.getType() == Volume.Type.ROOT) { + LOGGER.info("Chose disk controller for vol " + vol.getType() + " -> " + controllerInfo.first() + + ", based on root disk controller settings at global configuration setting."); + return controllerInfo.first(); + } else { + LOGGER.info("Chose disk controller for vol " + vol.getType() + " -> " + controllerInfo.second() + + ", based on default data disk controller setting i.e. Operating system recommended."); // Need to bring in global configuration setting & template level setting. + return controllerInfo.second(); + } + } + + private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, int ideControllerKey, + int scsiControllerKey, Map> iqnToData, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { + VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); + + for (DiskTO vol : sortedDisks) { + if (vol.getType() == Volume.Type.ISO) + continue; + + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); + + VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context); + assert (diskInfo != null); + + String[] diskChain = diskInfo.getDiskChain(); + assert (diskChain.length > 0); + + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + DatastoreFile file = new DatastoreFile(diskChain[0]); + + if (managed) { + DatastoreFile originalFile = new DatastoreFile(volumeTO.getPath()); + + if (!file.getFileBaseName().equalsIgnoreCase(originalFile.getFileBaseName())) { + if (LOGGER.isInfoEnabled()) + LOGGER.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + diskChain[0]); + } + } else { + if (!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) { + if (LOGGER.isInfoEnabled()) + LOGGER.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + file.getFileBaseName()); + } + } + + VolumeObjectTO volInSpec = getVolumeInSpec(vmSpec, volumeTO); + + if (volInSpec != null) { + if (managed) { + Map data = new HashMap<>(); + + String datastoreVolumePath = diskChain[0]; + + data.put(StartAnswer.PATH, datastoreVolumePath); + data.put(StartAnswer.IMAGE_FORMAT, Storage.ImageFormat.OVA.toString()); + + iqnToData.put(details.get(DiskTO.IQN), data); + + vol.setPath(datastoreVolumePath); + volumeTO.setPath(datastoreVolumePath); + volInSpec.setPath(datastoreVolumePath); + } else { + volInSpec.setPath(file.getFileBaseName()); + } + volInSpec.setChainInfo(vmwareResource.getGson().toJson(diskInfo)); + } + } + } + + private void setBootOptions(VirtualMachineTO vmSpec, String bootMode, VirtualMachineConfigSpec vmConfigSpec) { + VirtualMachineBootOptions bootOptions = null; + if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) { + vmConfigSpec.setFirmware("efi"); + if (vmSpec.getDetails().containsKey(ApiConstants.BootType.UEFI.toString()) && "secure".equalsIgnoreCase(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()))) { + if (bootOptions == null) { + bootOptions = new VirtualMachineBootOptions(); + } + bootOptions.setEfiSecureBootEnabled(true); + } + } + if (vmSpec.isEnterHardwareSetup()) { + if (bootOptions == null) { + bootOptions = new VirtualMachineBootOptions(); + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String.format("configuring VM '%s' to enter hardware setup",vmSpec.getName())); + } + bootOptions.setEnterBIOSSetup(vmSpec.isEnterHardwareSetup()); + } + if (bootOptions != null) { + vmConfigSpec.setBootOptions(bootOptions); + } + } + + // return the finalized disk chain for startup, from top to bottom + private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO vol, VirtualMachineDiskInfo diskInfo, + HashMap> dataStoresDetails) throws Exception { + + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); + DataStoreTO primaryStore = volumeTO.getDataStore(); + Map details = vol.getDetails(); + boolean isManaged = false; + String iScsiName = null; + + if (details != null) { + isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + iScsiName = details.get(DiskTO.IQN); + } + + // if the storage is managed, iScsiName should not be null + String datastoreName = isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); + Pair volumeDsDetails = dataStoresDetails.get(datastoreName); + + if (volumeDsDetails == null) { + throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); + } + + DatastoreMO dsMo = volumeDsDetails.second(); + + // we will honor vCenter's meta if it exists + if (diskInfo != null) { + // to deal with run-time upgrade to maintain the new datastore folder structure + String disks[] = diskInfo.getDiskChain(); + for (int i = 0; i < disks.length; i++) { + DatastoreFile file = new DatastoreFile(disks[i]); + if (!isManaged && file.getDir() != null && file.getDir().isEmpty()) { + LOGGER.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder"); + disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, file.getFileBaseName(), VmwareManager.s_vmwareSearchExcludeFolder.value()); + } + } + return disks; + } + + final String datastoreDiskPath; + + if (isManaged) { + String vmdkPath = new DatastoreFile(volumeTO.getPath()).getFileBaseName(); + + if (volumeTO.getVolumeType() == Volume.Type.ROOT) { + if (vmdkPath == null) { + vmdkPath = volumeTO.getName(); + } + + datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, vmdkPath); + } else { + if (vmdkPath == null) { + vmdkPath = dsMo.getName(); + } + + datastoreDiskPath = dsMo.getDatastorePath(vmdkPath + VmwareResource.VMDK_EXTENSION); + } + } else { + datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getPath(), VmwareManager.s_vmwareSearchExcludeFolder.value()); + } + + if (!dsMo.fileExists(datastoreDiskPath)) { + LOGGER.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath); + } + + return new String[]{datastoreDiskPath}; + } + + private void resizeRootDiskOnVMStart(VirtualMachineMO vmMo, DiskTO rootDiskTO, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { + final Pair vdisk = vmwareResource.getVirtualDiskInfo(vmMo, VmwareResource.appendFileType(rootDiskTO.getPath(), VmwareResource.VMDK_EXTENSION)); + assert (vdisk != null); + + Long reqSize = 0L; + final VolumeObjectTO volumeTO = ((VolumeObjectTO) rootDiskTO.getData()); + if (volumeTO != null) { + reqSize = volumeTO.getSize() / 1024; + } + final VirtualDisk disk = vdisk.first(); + if (reqSize > disk.getCapacityInKB()) { + final VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(vmMo.getDiskInfoBuilder(), rootDiskTO, hyperHost, context); + assert (diskInfo != null); + final String[] diskChain = diskInfo.getDiskChain(); + + if (diskChain != null && diskChain.length > 1) { + LOGGER.warn("Disk chain length for the VM is greater than one, this is not supported"); + throw new CloudRuntimeException("Unsupported VM disk chain length: " + diskChain.length); + } + + boolean resizingSupported = false; + String deviceBusName = diskInfo.getDiskDeviceBusName(); + if (deviceBusName != null && (deviceBusName.toLowerCase().contains("scsi") || deviceBusName.toLowerCase().contains("lsi"))) { + resizingSupported = true; + } + if (!resizingSupported) { + LOGGER.warn("Resizing of root disk is only support for scsi device/bus, the provide VM's disk device bus name is " + diskInfo.getDiskDeviceBusName()); + throw new CloudRuntimeException("Unsupported VM root disk device bus: " + diskInfo.getDiskDeviceBusName()); + } + + disk.setCapacityInKB(reqSize); + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + deviceConfigSpec.setDevice(disk); + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + vmConfigSpec.getDeviceChange().add(deviceConfigSpec); + if (!vmMo.configureVm(vmConfigSpec)) { + throw new Exception("Failed to configure VM for given root disk size. vmName: " + vmMo.getName()); + } + } + } + + private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) throws Exception { + /** + * We need to configure the port on the DV switch after the host is + * connected. So make this happen between the configure and start of + * the VM + */ + int nicIndex = 0; + for (NicTO nicTo : sortNicsByDeviceId(vmSpec.getNics())) { + if (nicTo.getBroadcastType() == Networks.BroadcastDomainType.Lswitch) { + // We need to create a port with a unique vlan and pass the key to the nic device + LOGGER.trace("Nic " + nicTo.toString() + " is connected to an NVP logicalswitch"); + VirtualDevice nicVirtualDevice = vmMo.getNicDeviceByIndex(nicIndex); + if (nicVirtualDevice == null) { + throw new Exception("Failed to find a VirtualDevice for nic " + nicIndex); //FIXME Generic exceptions are bad + } + VirtualDeviceBackingInfo backing = nicVirtualDevice.getBacking(); + if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) { + // This NIC is connected to a Distributed Virtual Switch + VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing; + DistributedVirtualSwitchPortConnection port = portInfo.getPort(); + String portKey = port.getPortKey(); + String portGroupKey = port.getPortgroupKey(); + String dvSwitchUuid = port.getSwitchUuid(); + + LOGGER.debug("NIC " + nicTo.toString() + " is connected to dvSwitch " + dvSwitchUuid + " pg " + portGroupKey + " port " + portKey); + + ManagedObjectReference dvSwitchManager = vmMo.getContext().getVimClient().getServiceContent().getDvSwitchManager(); + ManagedObjectReference dvSwitch = vmMo.getContext().getVimClient().getService().queryDvsByUuid(dvSwitchManager, dvSwitchUuid); + + // Get all ports + DistributedVirtualSwitchPortCriteria criteria = new DistributedVirtualSwitchPortCriteria(); + criteria.setInside(true); + criteria.getPortgroupKey().add(portGroupKey); + List dvPorts = vmMo.getContext().getVimClient().getService().fetchDVPorts(dvSwitch, criteria); + + DistributedVirtualPort vmDvPort = null; + List usedVlans = new ArrayList(); + for (DistributedVirtualPort dvPort : dvPorts) { + // Find the port for this NIC by portkey + if (portKey.equals(dvPort.getKey())) { + vmDvPort = dvPort; + } + VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPort.getConfig().getSetting(); + VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); + LOGGER.trace("Found port " + dvPort.getKey() + " with vlan " + vlanId.getVlanId()); + if (vlanId.getVlanId() > 0 && vlanId.getVlanId() < 4095) { + usedVlans.add(vlanId.getVlanId()); + } + } + + if (vmDvPort == null) { + throw new Exception("Empty port list from dvSwitch for nic " + nicTo.toString()); + } + + DVPortConfigInfo dvPortConfigInfo = vmDvPort.getConfig(); + VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPortConfigInfo.getSetting(); + + VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); + BoolPolicy blocked = settings.getBlocked(); + if (blocked.isValue() == Boolean.TRUE) { + LOGGER.trace("Port is blocked, set a vlanid and unblock"); + DVPortConfigSpec dvPortConfigSpec = new DVPortConfigSpec(); + VMwareDVSPortSetting edittedSettings = new VMwareDVSPortSetting(); + // Unblock + blocked.setValue(Boolean.FALSE); + blocked.setInherited(Boolean.FALSE); + edittedSettings.setBlocked(blocked); + // Set vlan + int i; + for (i = 1; i < 4095; i++) { + if (!usedVlans.contains(i)) + break; + } + vlanId.setVlanId(i); // FIXME should be a determined + // based on usage + vlanId.setInherited(false); + edittedSettings.setVlan(vlanId); + + dvPortConfigSpec.setSetting(edittedSettings); + dvPortConfigSpec.setOperation("edit"); + dvPortConfigSpec.setKey(portKey); + List dvPortConfigSpecs = new ArrayList(); + dvPortConfigSpecs.add(dvPortConfigSpec); + ManagedObjectReference task = vmMo.getContext().getVimClient().getService().reconfigureDVPortTask(dvSwitch, dvPortConfigSpecs); + if (!vmMo.getContext().getVimClient().waitForTask(task)) { + throw new Exception("Failed to configure the dvSwitch port for nic " + nicTo.toString()); + } + LOGGER.debug("NIC " + nicTo.toString() + " connected to vlan " + i); + } else { + LOGGER.trace("Port already configured and set to vlan " + vlanId.getVlanId()); + } + } else if (backing instanceof VirtualEthernetCardNetworkBackingInfo) { + // This NIC is connected to a Virtual Switch + // Nothing to do + } else if (backing instanceof VirtualEthernetCardOpaqueNetworkBackingInfo) { + //if NSX API VERSION >= 4.2, connect to br-int (nsx.network), do not create portgroup else previous behaviour + //OK, connected to OpaqueNetwork + } else { + LOGGER.error("nic device backing is of type " + backing.getClass().getName()); + throw new Exception("Incompatible backing for a VirtualDevice for nic " + nicIndex); //FIXME Generic exceptions are bad + } + } + nicIndex++; + } + } + + private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context) + throws Exception { + if (diskInfoBuilder != null) { + VolumeObjectTO volume = (VolumeObjectTO) vol.getData(); + + String dsName = null; + String diskBackingFileBaseName = null; + + Map details = vol.getDetails(); + boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + + if (isManaged) { + String iScsiName = details.get(DiskTO.IQN); + + // if the storage is managed, iScsiName should not be null + dsName = VmwareResource.getDatastoreName(iScsiName); + + diskBackingFileBaseName = new DatastoreFile(volume.getPath()).getFileBaseName(); + } else { + ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, volume.getDataStore().getUuid()); + DatastoreMO dsMo = new DatastoreMO(context, morDs); + + dsName = dsMo.getName(); + + diskBackingFileBaseName = volume.getPath(); + } + + VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName); + if (diskInfo != null) { + LOGGER.info("Found existing disk info from volume path: " + volume.getPath()); + return diskInfo; + } else { + String chainInfo = volume.getChainInfo(); + if (chainInfo != null) { + VirtualMachineDiskInfo infoInChain = vmwareResource.getGson().fromJson(chainInfo, VirtualMachineDiskInfo.class); + if (infoInChain != null) { + String[] disks = infoInChain.getDiskChain(); + if (disks.length > 0) { + for (String diskPath : disks) { + DatastoreFile file = new DatastoreFile(diskPath); + diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName(), dsName); + if (diskInfo != null) { + LOGGER.info("Found existing disk from chain info: " + diskPath); + return diskInfo; + } + } + } + + if (diskInfo == null) { + diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName()); + if (diskInfo != null) { + LOGGER.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName()); + return diskInfo; + } + } + } + } + } + } + + return null; + } + + private static VolumeObjectTO getVolumeInSpec(VirtualMachineTO vmSpec, VolumeObjectTO srcVol) { + for (DiskTO disk : vmSpec.getDisks()) { + if (disk.getData() instanceof VolumeObjectTO) { + VolumeObjectTO vol = (VolumeObjectTO) disk.getData(); + if (vol.getId() == srcVol.getId()) + return vol; + } + } + + return null; + } + + /** + * Generate the mac sequence from the nics. + */ + protected String generateMacSequence(NicTO[] nics) { + if (nics.length == 0) { + return ""; + } + + StringBuffer sbMacSequence = new StringBuffer(); + for (NicTO nicTo : sortNicsByDeviceId(nics)) { + sbMacSequence.append(nicTo.getMac()).append("|"); + } + if (!sbMacSequence.toString().isEmpty()) { + sbMacSequence.deleteCharAt(sbMacSequence.length() - 1); //Remove extra '|' char appended at the end + } + + return sbMacSequence.toString(); + } + + static NicTO[] sortNicsByDeviceId(NicTO[] nics) { + + List listForSort = new ArrayList(); + for (NicTO nic : nics) { + listForSort.add(nic); + } + Collections.sort(listForSort, new Comparator() { + + @Override + public int compare(NicTO arg0, NicTO arg1) { + if (arg0.getDeviceId() < arg1.getDeviceId()) { + return -1; + } else if (arg0.getDeviceId() == arg1.getDeviceId()) { + return 0; + } + + return 1; + } + }); + + return listForSort.toArray(new NicTO[0]); + } + + private static void configBasicExtraOption(List extraOptions, VirtualMachineTO vmSpec) { + OptionValue newVal = new OptionValue(); + newVal.setKey("machine.id"); + newVal.setValue(vmSpec.getBootArgs()); + extraOptions.add(newVal); + + newVal = new OptionValue(); + newVal.setKey("devices.hotplug"); + newVal.setValue("true"); + extraOptions.add(newVal); + } + + private static void configNvpExtraOption(List extraOptions, VirtualMachineTO vmSpec, Map nicUuidToDvSwitchUuid) { + /** + * Extra Config : nvp.vm-uuid = uuid + * - Required for Nicira NVP integration + */ + OptionValue newVal = new OptionValue(); + newVal.setKey("nvp.vm-uuid"); + newVal.setValue(vmSpec.getUuid()); + extraOptions.add(newVal); + + /** + * Extra Config : nvp.iface-id. = uuid + * - Required for Nicira NVP integration + */ + int nicNum = 0; + for (NicTO nicTo : sortNicsByDeviceId(vmSpec.getNics())) { + if (nicTo.getUuid() != null) { + newVal = new OptionValue(); + newVal.setKey("nvp.iface-id." + nicNum); + newVal.setValue(nicTo.getUuid()); + extraOptions.add(newVal); + } + nicNum++; + } + } + + private static void configCustomExtraOption(List extraOptions, VirtualMachineTO vmSpec) { + // we no longer to validation anymore + for (Map.Entry entry : vmSpec.getDetails().entrySet()) { + if (entry.getKey().equalsIgnoreCase(VmDetailConstants.BOOT_MODE)) { + continue; + } + OptionValue newVal = new OptionValue(); + newVal.setKey(entry.getKey()); + newVal.setValue(entry.getValue()); + extraOptions.add(newVal); + } + } + +} \ No newline at end of file diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index e8c69d622173..9e6b41c74a7c 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -44,13 +44,10 @@ import javax.naming.ConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; -import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; -import org.apache.cloudstack.storage.configdrive.ConfigDrive; import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; -import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo; import org.apache.cloudstack.vm.UnmanagedInstanceTO; @@ -183,7 +180,6 @@ import com.cloud.agent.api.storage.ResizeVolumeAnswer; import com.cloud.agent.api.storage.ResizeVolumeCommand; import com.cloud.agent.api.to.DataStoreTO; -import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.NicTO; @@ -217,7 +213,6 @@ import com.cloud.hypervisor.vmware.mo.HostStorageSystemMO; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.NetworkDetails; -import com.cloud.hypervisor.vmware.mo.TaskMO; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; @@ -256,7 +251,6 @@ import com.cloud.utils.mgmt.JmxUtil; import com.cloud.utils.mgmt.PropertyMapDynamicBean; import com.cloud.utils.net.NetUtils; -import com.cloud.utils.nicira.nvp.plugin.NiciraNvpApiVersion; import com.cloud.utils.script.Script; import com.cloud.utils.ssh.SshHelper; import com.cloud.vm.VirtualMachine; @@ -267,12 +261,8 @@ import com.google.gson.Gson; import com.vmware.vim25.AboutInfo; import com.vmware.vim25.ArrayUpdateOperation; -import com.vmware.vim25.BoolPolicy; import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.CustomFieldStringValue; -import com.vmware.vim25.DVPortConfigInfo; -import com.vmware.vim25.DVPortConfigSpec; -import com.vmware.vim25.DasVmPriority; import com.vmware.vim25.DatastoreInfo; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DistributedVirtualPort; @@ -316,11 +306,9 @@ import com.vmware.vim25.VirtualEthernetCard; import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; -import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo; import com.vmware.vim25.VirtualIDEController; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineBootOptions; -import com.vmware.vim25.VirtualMachineFileInfo; import com.vmware.vim25.VirtualMachineFileLayoutEx; import com.vmware.vim25.VirtualMachineFileLayoutExFileInfo; import com.vmware.vim25.VirtualMachineGuestOsIdentifier; @@ -332,7 +320,6 @@ import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VirtualPCNet32; import com.vmware.vim25.VirtualSCSIController; -import com.vmware.vim25.VirtualUSBController; import com.vmware.vim25.VirtualVmxnet2; import com.vmware.vim25.VirtualVmxnet3; import com.vmware.vim25.VmConfigInfo; @@ -346,13 +333,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa public static final String VMDK_EXTENSION = ".vmdk"; private static final Random RANDOM = new Random(System.nanoTime()); + private final StartCommandExecutor startCommandExecutor = new StartCommandExecutor(this); + + // FR37 Does this need to be a setting? + protected final int shutdownWaitMs = 300000; // wait up to 5 minutes for shutdown protected String _name; protected final long _opsTimeout = 900000; // 15 minutes time out to time - protected final int _shutdownWaitMs = 300000; // wait up to 5 minutes for shutdown - // out an operation protected final int _retry = 24; protected final int _sleep = 10000; @@ -360,7 +349,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected final int MazCmdMBean = 100; protected String _url; - protected String _dcId; + protected String dcId; protected String _pod; protected String _cluster; protected String _username; @@ -375,7 +364,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected Map _vsmCredentials = null; protected int _portsPerDvPortGroup; protected boolean _fullCloneFlag = false; - protected boolean _instanceNameFlag = false; + // FR37 move to global seting(s) + protected static boolean instanceNameFlag = false; protected boolean _recycleHungWorker = false; protected DiskControllerType _rootDiskController = DiskControllerType.ide; @@ -386,7 +376,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected List _cmdMBeans = new ArrayList(); - protected Gson _gson; + protected Gson gson; protected volatile long _cmdSequence = 1; @@ -408,12 +398,24 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected static final String s_relativePathSystemVmKeyFileInstallDir = "scripts/vm/systemvm/id_rsa.cloud"; protected static final String s_defaultPathSystemVmKeyFile = "/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud"; - public Gson getGson() { - return _gson; + public VmwareResource() { + gson = GsonHelper.getGsonLogger(); } - public VmwareResource() { - _gson = GsonHelper.getGsonLogger(); + public VmwareStorageProcessor getStorageProcessor() { + return _storageProcessor; + } + + public int getShutdownWaitMs() { + return shutdownWaitMs; + } + + public String getDcId() { + return dcId; + } + + public Gson getGson() { + return gson; } private String getCommandLogTitle(Command cmd) { @@ -443,7 +445,7 @@ public Answer executeRequest(Command cmd) { Date startTime = DateUtil.currentGMTTime(); PropertyMapDynamicBean mbean = new PropertyMapDynamicBean(); mbean.addProp("StartTime", DateUtil.getDateDisplayString(TimeZone.getDefault(), startTime)); - mbean.addProp("Command", _gson.toJson(cmd)); + mbean.addProp("Command", gson.toJson(cmd)); mbean.addProp("Sequence", String.valueOf(cmdSequence)); mbean.addProp("Name", cmd.getClass().getSimpleName()); @@ -529,7 +531,7 @@ public Answer executeRequest(Command cmd) { } else if (clz == NetworkUsageCommand.class) { answer = execute((NetworkUsageCommand) cmd); } else if (clz == StartCommand.class) { - answer = execute((StartCommand) cmd); + answer = startCommandExecutor.execute((StartCommand)cmd); } else if (clz == CheckSshCommand.class) { answer = execute((CheckSshCommand) cmd); } else if (clz == CheckNetworkCommand.class) { @@ -575,7 +577,7 @@ public Answer executeRequest(Command cmd) { Date doneTime = DateUtil.currentGMTTime(); mbean.addProp("DoneTime", DateUtil.getDateDisplayString(TimeZone.getDefault(), doneTime)); - mbean.addProp("Answer", _gson.toJson(answer)); + mbean.addProp("Answer", gson.toJson(answer)); synchronized (this) { try { @@ -636,7 +638,7 @@ protected void reconfigureProcessorByHandler(EnumMap validatedDisks = new ArrayList(); - - for (DiskTO vol : disks) { - if (vol.getType() != Volume.Type.ISO) { - VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); - DataStoreTO primaryStore = volumeTO.getDataStore(); - if (primaryStore.getUuid() != null && !primaryStore.getUuid().isEmpty()) { - validatedDisks.add(vol); - } - } else if (vol.getType() == Volume.Type.ISO) { - TemplateObjectTO templateTO = (TemplateObjectTO) vol.getData(); - if (templateTO.getPath() != null && !templateTO.getPath().isEmpty()) { - validatedDisks.add(vol); - } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Drop invalid disk option, volumeTO: " + _gson.toJson(vol)); - } - } - } - Collections.sort(validatedDisks, (d1, d2) -> d1.getDiskSeq().compareTo(d2.getDiskSeq())); - return validatedDisks.toArray(new DiskTO[0]); - } - - private static DiskTO getIsoDiskTO(DiskTO[] disks) { - for (DiskTO vol : disks) { - if (vol.getType() == Volume.Type.ISO) { - return vol; - } - } - return null; - } - protected ScaleVmAnswer execute(ScaleVmCommand cmd) { VmwareContext context = getServiceContext(); @@ -1651,798 +1592,17 @@ protected ScaleVmAnswer execute(ScaleVmCommand cmd) { return new ScaleVmAnswer(cmd, true, null); } - protected void ensureDiskControllers(VirtualMachineMO vmMo, Pair controllerInfo) throws Exception { - if (vmMo == null) { - return; - } - - String msg; - String rootDiskController = controllerInfo.first(); - String dataDiskController = controllerInfo.second(); - String scsiDiskController; - String recommendedDiskController = null; - - if (VmwareHelper.isControllerOsRecommended(dataDiskController) || VmwareHelper.isControllerOsRecommended(rootDiskController)) { - recommendedDiskController = vmMo.getRecommendedDiskController(null); - } - scsiDiskController = HypervisorHostHelper.getScsiController(new Pair(rootDiskController, dataDiskController), recommendedDiskController); - if (scsiDiskController == null) { - return; - } - - vmMo.getScsiDeviceControllerKeyNoException(); - // This VM needs SCSI controllers. - // Get count of existing scsi controllers. Helps not to attempt to create more than the maximum allowed 4 - // Get maximum among the bus numbers in use by scsi controllers. Safe to pick maximum, because we always go sequential allocating bus numbers. - Ternary scsiControllerInfo = vmMo.getScsiControllerInfo(); - int requiredNumScsiControllers = VmwareHelper.MAX_SCSI_CONTROLLER_COUNT - scsiControllerInfo.first(); - int availableBusNum = scsiControllerInfo.second() + 1; // method returned current max. bus number - - if (requiredNumScsiControllers == 0) { - return; - } - if (scsiControllerInfo.first() > 0) { - // For VMs which already have a SCSI controller, do NOT attempt to add any more SCSI controllers & return the sub type. - // For Legacy VMs would have only 1 LsiLogic Parallel SCSI controller, and doesn't require more. - // For VMs created post device ordering support, 4 SCSI subtype controllers are ensured during deployment itself. No need to add more. - // For fresh VM deployment only, all required controllers should be ensured. - return; - } - ensureScsiDiskControllers(vmMo, scsiDiskController, requiredNumScsiControllers, availableBusNum); - } - - private void ensureScsiDiskControllers(VirtualMachineMO vmMo, String scsiDiskController, int requiredNumScsiControllers, int availableBusNum) throws Exception { - // Pick the sub type of scsi - if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.pvscsi) { - if (!vmMo.isPvScsiSupported()) { - String msg = "This VM doesn't support Vmware Paravirtual SCSI controller for virtual disks, because the virtual hardware version is less than 7."; - throw new Exception(msg); - } - vmMo.ensurePvScsiDeviceController(requiredNumScsiControllers, availableBusNum); - } else if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.lsisas1068) { - vmMo.ensureLsiLogicSasDeviceControllers(requiredNumScsiControllers, availableBusNum); - } else if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.buslogic) { - vmMo.ensureBusLogicDeviceControllers(requiredNumScsiControllers, availableBusNum); - } else if (DiskControllerType.getType(scsiDiskController) == DiskControllerType.lsilogic) { - vmMo.ensureLsiLogicDeviceControllers(requiredNumScsiControllers, availableBusNum); - } - } - protected StartAnswer execute(StartCommand cmd) { - if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource StartCommand: " + _gson.toJson(cmd)); - } // FR37 if startcommand contains a secendary storage URL or some flag or other type of indicator, deploy OVA as is - String secStorUrl = cmd.getSecondaryStorage(); - if (StringUtils.isNotEmpty(secStorUrl)) { - if (s_logger.isTraceEnabled()) { - s_logger.trace(String.format("deploying OVA as is from %s", secStorUrl)); - } - } - VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - boolean vmAlreadyExistsInVcenter = false; - - String existingVmName = null; - VirtualMachineFileInfo existingVmFileInfo = null; - VirtualMachineFileLayoutEx existingVmFileLayout = null; - List existingDatastores = new ArrayList(); - - Pair names = composeVmNames(vmSpec); - String vmInternalCSName = names.first(); - String vmNameOnVcenter = names.second(); - String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER); - String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); - DiskTO rootDiskTO = null; - String bootMode = null; - if (vmSpec.getDetails().containsKey(VmDetailConstants.BOOT_MODE)) { - bootMode = vmSpec.getDetails().get(VmDetailConstants.BOOT_MODE); - } - if (null == bootMode) { - bootMode = ApiConstants.BootType.BIOS.toString(); - } // If root disk controller is scsi, then data disk controller would also be scsi instead of using 'osdefault' // This helps avoid mix of different scsi subtype controllers in instance. - if (DiskControllerType.osdefault == DiskControllerType.getType(dataDiskController) && DiskControllerType.lsilogic == DiskControllerType.getType(rootDiskController)) { - dataDiskController = DiskControllerType.scsi.toString(); - } // Validate the controller types - dataDiskController = DiskControllerType.getType(dataDiskController).toString(); - rootDiskController = DiskControllerType.getType(rootDiskController).toString(); - - if (DiskControllerType.getType(rootDiskController) == DiskControllerType.none) { - throw new CloudRuntimeException("Invalid root disk controller detected : " + rootDiskController); - } - if (DiskControllerType.getType(dataDiskController) == DiskControllerType.none) { - throw new CloudRuntimeException("Invalid data disk controller detected : " + dataDiskController); - } - - Pair controllerInfo = new Pair(rootDiskController, dataDiskController); - Boolean systemVm = vmSpec.getType().isUsedBySystem(); // Thus, vmInternalCSName always holds i-x-y, the cloudstack generated internal VM name. - VmwareContext context = getServiceContext(); - DatacenterMO dcMo = null; - try { - VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - - VmwareHypervisorHost hyperHost = getHyperHost(context); - dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter()); - - // Validate VM name is unique in Datacenter - VirtualMachineMO vmInVcenter = dcMo.checkIfVmAlreadyExistsInVcenter(vmNameOnVcenter, vmInternalCSName); - if (vmInVcenter != null) { - vmAlreadyExistsInVcenter = true; - String msg = "VM with name: " + vmNameOnVcenter + " already exists in vCenter."; - s_logger.error(msg); - throw new Exception(msg); - } - String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value(); - DiskTO[] disks = validateDisks(vmSpec.getDisks()); - assert (disks.length > 0); - NicTO[] nics = vmSpec.getNics(); - - HashMap> dataStoresDetails = inferDatastoreDetailsFromDiskInfo(hyperHost, context, disks, cmd); - if ((dataStoresDetails == null) || (dataStoresDetails.isEmpty())) { - String msg = "Unable to locate datastore details of the volumes to be attached"; - s_logger.error(msg); - throw new Exception(msg); - } - - DatastoreMO dsRootVolumeIsOn = getDatastoreThatRootDiskIsOn(dataStoresDetails, disks); - if (dsRootVolumeIsOn == null) { - String msg = "Unable to locate datastore details of root volume"; - s_logger.error(msg); - throw new Exception(msg); - } - - VirtualMachineDiskInfoBuilder diskInfoBuilder = null; - VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); - DiskControllerType systemVmScsiControllerType = DiskControllerType.lsilogic; - int firstScsiControllerBusNum = 0; - int numScsiControllerForSystemVm = 1; - boolean hasSnapshot = false; - if (vmMo != null) { - s_logger.info("VM " + vmInternalCSName + " already exists, tear down devices for reconfiguration"); - if (getVmPowerState(vmMo) != PowerState.PowerOff) - vmMo.safePowerOff(_shutdownWaitMs); - - // retrieve disk information before we tear down - diskInfoBuilder = vmMo.getDiskInfoBuilder(); - hasSnapshot = vmMo.hasSnapshot(); - if (!hasSnapshot) - vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); - else - vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); - if (systemVm) { - ensureScsiDiskControllers(vmMo, systemVmScsiControllerType.toString(), numScsiControllerForSystemVm, firstScsiControllerBusNum); - } else { - ensureDiskControllers(vmMo, controllerInfo); - } - } else { - ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter(); - assert (morDc != null); - - vmMo = hyperHost.findVmOnPeerHyperHost(vmInternalCSName); - if (vmMo != null) { - if (s_logger.isInfoEnabled()) { - s_logger.info("Found vm " + vmInternalCSName + " at other host, relocate to " + hyperHost.getHyperHostName()); - } - - takeVmFromOtherHyperHost(hyperHost, vmInternalCSName); - - if (getVmPowerState(vmMo) != PowerState.PowerOff) - vmMo.safePowerOff(_shutdownWaitMs); - - diskInfoBuilder = vmMo.getDiskInfoBuilder(); - hasSnapshot = vmMo.hasSnapshot(); - if (!hasSnapshot) - vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); - else - vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); - - if (systemVm) { - // System volumes doesn't require more than 1 SCSI controller as there is no requirement for data volumes. - ensureScsiDiskControllers(vmMo, systemVmScsiControllerType.toString(), numScsiControllerForSystemVm, firstScsiControllerBusNum); - } else { - ensureDiskControllers(vmMo, controllerInfo); - } - } else { - // If a VM with the same name is found in a different cluster in the DC, unregister the old VM and configure a new VM (cold-migration). - VirtualMachineMO existingVmInDc = dcMo.findVm(vmInternalCSName); - if (existingVmInDc != null) { - s_logger.debug("Found VM: " + vmInternalCSName + " on a host in a different cluster. Unregistering the exisitng VM."); - existingVmName = existingVmInDc.getName(); - existingVmFileInfo = existingVmInDc.getFileInfo(); - existingVmFileLayout = existingVmInDc.getFileLayout(); - existingDatastores = existingVmInDc.getAllDatastores(); - existingVmInDc.unregisterVm(); - } - Pair rootDiskDataStoreDetails = null; - for (DiskTO vol : disks) { - if (vol.getType() == Volume.Type.ROOT) { - Map details = vol.getDetails(); - boolean managed = false; - - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - if (managed) { - String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); - - rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); - } else { - DataStoreTO primaryStore = vol.getData().getDataStore(); - - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); - } - } - } - - assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); - - boolean vmFolderExists = rootDiskDataStoreDetails.second().folderExists(String.format("[%s]", rootDiskDataStoreDetails.second().getName()), vmNameOnVcenter); - String vmxFileFullPath = dsRootVolumeIsOn.searchFileInSubFolders(vmNameOnVcenter + ".vmx", false, VmwareManager.s_vmwareSearchExcludeFolder.value()); - if (vmFolderExists && vmxFileFullPath != null) { // VM can be registered only if .vmx is present. - registerVm(vmNameOnVcenter, dsRootVolumeIsOn); - vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); - if (vmMo != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Found registered vm " + vmInternalCSName + " at host " + hyperHost.getHyperHostName()); - } - } - tearDownVm(vmMo); - } else if (!hyperHost.createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed().intValue(), getReservedCpuMHZ(vmSpec), - vmSpec.getLimitCpuUse(), (int) (vmSpec.getMaxRam() / ResourceType.bytesToMiB), getReservedMemoryMb(vmSpec), guestOsId, rootDiskDataStoreDetails.first(), false, - controllerInfo, systemVm)) { - throw new Exception("Failed to create VM. vmName: " + vmInternalCSName); - } - } - - vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); - if (vmMo == null) { - throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmInternalCSName); - } - } - - int totalChangeDevices = disks.length + nics.length; - // vApp cdrom device - // HACK ALERT: ovf properties might not be the only or defining feature of vApps; needs checking - if (s_logger.isTraceEnabled()) { - s_logger.trace("adding divice tie device count for vApp config ISO"); - } - if (vmSpec.getOvfProperties() != null) { - totalChangeDevices++; - } - - DiskTO volIso = null; - if (vmSpec.getType() != VirtualMachine.Type.User) { - // system VM needs a patch ISO - totalChangeDevices++; - } else { - volIso = getIsoDiskTO(disks); - if (volIso == null) - totalChangeDevices++; - } - - VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); - - VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), getReservedCpuMHZ(vmSpec), (int) (vmSpec.getMaxRam() / (1024 * 1024)), - getReservedMemoryMb(vmSpec), guestOsId, vmSpec.getLimitCpuUse()); - - // Check for multi-cores per socket settings - int numCoresPerSocket = 1; - String coresPerSocket = vmSpec.getDetails().get(VmDetailConstants.CPU_CORE_PER_SOCKET); - if (coresPerSocket != null) { - String apiVersion = HypervisorHostHelper.getVcenterApiVersion(vmMo.getContext()); - // Property 'numCoresPerSocket' is supported since vSphere API 5.0 - if (apiVersion.compareTo("5.0") >= 0) { - numCoresPerSocket = NumbersUtil.parseInt(coresPerSocket, 1); - vmConfigSpec.setNumCoresPerSocket(numCoresPerSocket); - } - } - - // Check for hotadd settings - vmConfigSpec.setMemoryHotAddEnabled(vmMo.isMemoryHotAddSupported(guestOsId)); - - String hostApiVersion = ((HostMO) hyperHost).getHostAboutInfo().getApiVersion(); - if (numCoresPerSocket > 1 && hostApiVersion.compareTo("5.0") < 0) { - s_logger.warn("Dynamic scaling of CPU is not supported for Virtual Machines with multi-core vCPUs in case of ESXi hosts 4.1 and prior. Hence CpuHotAdd will not be" - + " enabled for Virtual Machine: " + vmInternalCSName); - vmConfigSpec.setCpuHotAddEnabled(false); - } else { - vmConfigSpec.setCpuHotAddEnabled(vmMo.isCpuHotAddSupported(guestOsId)); - } - - configNestedHVSupport(vmMo, vmSpec, vmConfigSpec); - - VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[totalChangeDevices]; - int i = 0; - int ideUnitNumber = 0; - int scsiUnitNumber = 0; - int ideControllerKey = vmMo.getIDEDeviceControllerKey(); - int scsiControllerKey = vmMo.getGenericScsiDeviceControllerKeyNoException(); - int controllerKey; - - // - // Setup ISO device - // - - // vAPP ISO - // FR37 the native deploy mechs should create this for us - if (vmSpec.getOvfProperties() != null) { - if (s_logger.isTraceEnabled()) { - // FR37 TODO add more usefull info (if we keep this bit - s_logger.trace("adding iso for properties for 'xxx'"); - } - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - Pair isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1); - deviceConfigSpecArray[i].setDevice(isoInfo.first()); - if (isoInfo.second()) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare vApp ISO volume at existing device " + _gson.toJson(isoInfo.first())); - - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare vApp ISO volume at existing device " + _gson.toJson(isoInfo.first())); - - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); - } - i++; - } - - // prepare systemvm patch ISO - if (vmSpec.getType() != VirtualMachine.Type.User) { - // attach ISO (for patching of system VM) - Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); - String secStoreUrl = secStoreUrlAndId.first(); - Long secStoreId = secStoreUrlAndId.second(); - if (secStoreUrl == null) { - String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; - throw new Exception(msg); - } - mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); - - ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); - if (morSecDs == null) { - String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl; - throw new Exception(msg); - } - DatastoreMO secDsMo = new DatastoreMO(hyperHost.getContext(), morSecDs); - - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - Pair isoInfo = VmwareHelper.prepareIsoDevice(vmMo, - String.format("[%s] systemvm/%s", secDsMo.getName(), mgr.getSystemVMIsoFileNameOnDatastore()), secDsMo.getMor(), true, true, ideUnitNumber++, i + 1); - deviceConfigSpecArray[i].setDevice(isoInfo.first()); - if (isoInfo.second()) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first())); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first())); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); - } - i++; - } else { - // Note: we will always plug a CDROM device - if (volIso != null) { - for (DiskTO vol : disks) { - if (vol.getType() == Volume.Type.ISO) { - - TemplateObjectTO iso = (TemplateObjectTO) vol.getData(); - - if (iso.getPath() != null && !iso.getPath().isEmpty()) { - DataStoreTO imageStore = iso.getDataStore(); - if (!(imageStore instanceof NfsTO)) { - s_logger.debug("unsupported protocol"); - throw new Exception("unsupported protocol"); - } - NfsTO nfsImageStore = (NfsTO) imageStore; - String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath(); - Pair isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath); - assert (isoDatastoreInfo != null); - assert (isoDatastoreInfo.second() != null); - - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - Pair isoInfo = - VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber++, i + 1); - deviceConfigSpecArray[i].setDevice(isoInfo.first()); - if (isoInfo.second()) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first())); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first())); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); - } - } - i++; - } - } - } else { - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - Pair isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, ideUnitNumber++, i + 1); - deviceConfigSpecArray[i].setDevice(isoInfo.first()); - if (isoInfo.second()) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first())); - - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first())); - - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); - } - i++; - } - } - - - // - // Setup ROOT/DATA disk devices - // - DiskTO[] sortedDisks = sortVolumesByDeviceId(disks); - for (DiskTO vol : sortedDisks) { - if (vol.getType() == Volume.Type.ISO) - continue; - - VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context); - controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey); - String diskController = getDiskController(vmMo, matchingExistingDisk, vol, new Pair(rootDiskController, dataDiskController)); - - if (DiskControllerType.getType(diskController) == DiskControllerType.osdefault) { - diskController = vmMo.getRecommendedDiskController(null); - } - if (DiskControllerType.getType(diskController) == DiskControllerType.ide) { - controllerKey = vmMo.getIDEControllerKey(ideUnitNumber); - if (vol.getType() == Volume.Type.DATADISK) { - // Could be result of flip due to user configured setting or "osdefault" for data disks - // Ensure maximum of 2 data volumes over IDE controller, 3 includeing root volume - if (vmMo.getNumberOfVirtualDisks() > 3) { - throw new CloudRuntimeException("Found more than 3 virtual disks attached to this VM [" + vmMo.getVmName() + "]. Unable to implement the disks over " - + diskController + " controller, as maximum number of devices supported over IDE controller is 4 includeing CDROM device."); - } - } - } else { - controllerKey = vmMo.getScsiDiskControllerKeyNoException(diskController); - if (controllerKey == -1) { - // This may happen for ROOT legacy VMs which doesn't have recommended disk controller when global configuration parameter 'vmware.root.disk.controller' is set to "osdefault" - // Retrieve existing controller and use. - Ternary vmScsiControllerInfo = vmMo.getScsiControllerInfo(); - DiskControllerType existingControllerType = vmScsiControllerInfo.third(); - controllerKey = vmMo.getScsiDiskControllerKeyNoException(existingControllerType.toString()); - } - } - if (!hasSnapshot) { - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - - VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); - DataStoreTO primaryStore = volumeTO.getDataStore(); - Map details = vol.getDetails(); - boolean managed = false; - String iScsiName = null; - - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - iScsiName = details.get(DiskTO.IQN); - } - - // if the storage is managed, iScsiName should not be null - String datastoreName = managed ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); - Pair volumeDsDetails = dataStoresDetails.get(datastoreName); - - assert (volumeDsDetails != null); - - String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, vol, matchingExistingDisk, dataStoresDetails); - if (controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) - scsiUnitNumber++; - VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, diskChain, volumeDsDetails.first(), - (controllerKey == vmMo.getIDEControllerKey(ideUnitNumber)) ? ((ideUnitNumber++) % VmwareHelper.MAX_IDE_CONTROLLER_COUNT) : scsiUnitNumber++, i + 1); - - if (vol.getType() == Volume.Type.ROOT) - rootDiskTO = vol; - deviceConfigSpecArray[i].setDevice(device); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare volume at new device " + _gson.toJson(device)); - - i++; - } else { - if (controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) - scsiUnitNumber++; - if (controllerKey == vmMo.getIDEControllerKey(ideUnitNumber)) - ideUnitNumber++; - else - scsiUnitNumber++; - } - } - - // - // Setup USB devices - // - if (guestOsId.startsWith("darwin")) { //Mac OS - VirtualDevice[] devices = vmMo.getMatchedDevices(new Class[]{VirtualUSBController.class}); - if (devices.length == 0) { - s_logger.debug("No USB Controller device on VM Start. Add USB Controller device for Mac OS VM " + vmInternalCSName); - - //For Mac OS X systems, the EHCI+UHCI controller is enabled by default and is required for USB mouse and keyboard access. - VirtualDevice usbControllerDevice = VmwareHelper.prepareUSBControllerDevice(); - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - deviceConfigSpecArray[i].setDevice(usbControllerDevice); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare USB controller at new device " + _gson.toJson(deviceConfigSpecArray[i])); - - i++; - } else { - s_logger.debug("USB Controller device exists on VM Start for Mac OS VM " + vmInternalCSName); - } - } - - // - // Setup NIC devices - // - VirtualDevice nic; - int nicMask = 0; - int nicCount = 0; - - if (vmSpec.getType() == VirtualMachine.Type.DomainRouter) { - int extraPublicNics = mgr.getRouterExtraPublicNics(); - if (extraPublicNics > 0 && vmSpec.getDetails().containsKey("PeerRouterInstanceName")) { - //Set identical MAC address for RvR on extra public interfaces - String peerRouterInstanceName = vmSpec.getDetails().get("PeerRouterInstanceName"); - - VirtualMachineMO peerVmMo = hyperHost.findVmOnHyperHost(peerRouterInstanceName); - if (peerVmMo == null) { - peerVmMo = hyperHost.findVmOnPeerHyperHost(peerRouterInstanceName); - } - - if (peerVmMo != null) { - String oldMacSequence = generateMacSequence(nics); - - for (int nicIndex = nics.length - extraPublicNics; nicIndex < nics.length; nicIndex++) { - VirtualDevice nicDevice = peerVmMo.getNicDeviceByIndex(nics[nicIndex].getDeviceId()); - if (nicDevice != null) { - String mac = ((VirtualEthernetCard) nicDevice).getMacAddress(); - if (mac != null) { - s_logger.info("Use same MAC as previous RvR, the MAC is " + mac + " for extra NIC with device id: " + nics[nicIndex].getDeviceId()); - nics[nicIndex].setMac(mac); - } - } - } - - if (!StringUtils.isBlank(vmSpec.getBootArgs())) { - String newMacSequence = generateMacSequence(nics); - vmSpec.setBootArgs(replaceNicsMacSequenceInBootArgs(oldMacSequence, newMacSequence, vmSpec)); - } - } - } - } - - VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.valueOf(vmSpec.getDetails().get(VmDetailConstants.NIC_ADAPTER)); - if (s_logger.isDebugEnabled()) - s_logger.debug("VM " + vmInternalCSName + " will be started with NIC device type: " + nicDeviceType); - - NiciraNvpApiVersion.logNiciraApiVersion(); - - Map nicUuidToDvSwitchUuid = new HashMap(); - for (NicTO nicTo : sortNicsByDeviceId(nics)) { - s_logger.info("Prepare NIC device based on NicTO: " + _gson.toJson(nicTo)); - - boolean configureVServiceInNexus = (nicTo.getType() == TrafficType.Guest) && (vmSpec.getDetails().containsKey("ConfigureVServiceInNexus")); - VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); - Pair networkInfo = prepareNetworkFromNicInfo(vmMo.getRunningHost(), nicTo, configureVServiceInNexus, vmType); - if ((nicTo.getBroadcastType() != BroadcastDomainType.Lswitch) - || (nicTo.getBroadcastType() == BroadcastDomainType.Lswitch && NiciraNvpApiVersion.isApiVersionLowerThan("4.2"))) { - if (VmwareHelper.isDvPortGroup(networkInfo.first())) { - String dvSwitchUuid; - ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter(); - DatacenterMO dataCenterMo = new DatacenterMO(context, dcMor); - ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first()); - dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor); - s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid); - nic = VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid, - nicTo.getMac(), i + 1, true, true); - if (nicTo.getUuid() != null) { - nicUuidToDvSwitchUuid.put(nicTo.getUuid(), dvSwitchUuid); - } - } else { - s_logger.info("Preparing NIC device on network " + networkInfo.second()); - nic = VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), - nicTo.getMac(), i + 1, true, true); - } - } else { - //if NSX API VERSION >= 4.2, connect to br-int (nsx.network), do not create portgroup else previous behaviour - nic = VmwareHelper.prepareNicOpaque(vmMo, nicDeviceType, networkInfo.second(), - nicTo.getMac(), i + 1, true, true); - } - - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - deviceConfigSpecArray[i].setDevice(nic); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare NIC at new device " + _gson.toJson(deviceConfigSpecArray[i])); - - // this is really a hacking for DomR, upon DomR startup, we will reset all the NIC allocation after eth3 - if (nicCount < 3) - nicMask |= (1 << nicCount); - - i++; - nicCount++; - } - - for (int j = 0; j < i; j++) - vmConfigSpec.getDeviceChange().add(deviceConfigSpecArray[j]); - - // - // Setup VM options - // - - // pass boot arguments through machine.id & perform customized options to VMX - ArrayList extraOptions = new ArrayList(); - configBasicExtraOption(extraOptions, vmSpec); - configNvpExtraOption(extraOptions, vmSpec, nicUuidToDvSwitchUuid); - configCustomExtraOption(extraOptions, vmSpec); - - // config for NCC - VirtualMachine.Type vmType = cmd.getVirtualMachine().getType(); - if (vmType.equals(VirtualMachine.Type.NetScalerVm)) { - NicTO mgmtNic = vmSpec.getNics()[0]; - OptionValue option = new OptionValue(); - option.setKey("machine.id"); - option.setValue("ip=" + mgmtNic.getIp() + "&netmask=" + mgmtNic.getNetmask() + "&gateway=" + mgmtNic.getGateway()); - extraOptions.add(option); - } - - // config VNC - String keyboardLayout = null; - if (vmSpec.getDetails() != null) - keyboardLayout = vmSpec.getDetails().get(VmDetailConstants.KEYBOARD); - vmConfigSpec.getExtraConfig() - .addAll(Arrays.asList(configureVnc(extraOptions.toArray(new OptionValue[0]), hyperHost, vmInternalCSName, vmSpec.getVncPassword(), keyboardLayout))); - - // config video card - configureVideoCard(vmMo, vmSpec, vmConfigSpec); - - // Set OVF properties (if available) - Pair> ovfPropsMap = vmSpec.getOvfProperties(); - VmConfigInfo templateVappConfig = null; - List ovfProperties = null; - if (ovfPropsMap != null) { - String vmTemplate = ovfPropsMap.first(); - s_logger.info("Find VM template " + vmTemplate); - VirtualMachineMO vmTemplateMO = dcMo.findVm(vmTemplate); - templateVappConfig = vmTemplateMO.getConfigInfo().getVAppConfig(); - ovfProperties = ovfPropsMap.second(); - // Set OVF properties (if available) - if (CollectionUtils.isNotEmpty(ovfProperties)) { - s_logger.info("Copying OVF properties from template and setting them to the values the user provided"); - copyVAppConfigsFromTemplate(templateVappConfig, ovfProperties, vmConfigSpec); - } - } - - setBootOptions(vmSpec, bootMode, vmConfigSpec); - - // - // Configure VM - // - if (!vmMo.configureVm(vmConfigSpec)) { - throw new Exception("Failed to configure VM before start. vmName: " + vmInternalCSName); - } - - if (vmSpec.getType() == VirtualMachine.Type.DomainRouter) { - hyperHost.setRestartPriorityForVM(vmMo, DasVmPriority.HIGH.value()); - } - - // Resizing root disk only when explicit requested by user - final Map vmDetails = cmd.getVirtualMachine().getDetails(); - if (rootDiskTO != null && !hasSnapshot && (vmDetails != null && vmDetails.containsKey(ApiConstants.ROOT_DISK_SIZE))) { - resizeRootDiskOnVMStart(vmMo, rootDiskTO, hyperHost, context); - } - - // - // Post Configuration - // - - vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_NIC_MASK, String.valueOf(nicMask)); - postNvpConfigBeforeStart(vmMo, vmSpec); - - Map> iqnToData = new HashMap<>(); - - postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToData, hyperHost, context); - - // - // Power-on VM - // - if (!vmMo.powerOn()) { - throw new Exception("Failed to start VM. vmName: " + vmInternalCSName + " with hostname " + vmNameOnVcenter); - } - - StartAnswer startAnswer = new StartAnswer(cmd); - - startAnswer.setIqnToData(iqnToData); - - // Since VM was successfully powered-on, if there was an existing VM in a different cluster that was unregistered, delete all the files associated with it. - if (existingVmName != null && existingVmFileLayout != null) { - List vmDatastoreNames = new ArrayList(); - for (DatastoreMO vmDatastore : vmMo.getAllDatastores()) { - vmDatastoreNames.add(vmDatastore.getName()); - } - // Don't delete files that are in a datastore that is being used by the new VM as well (zone-wide datastore). - List skipDatastores = new ArrayList(); - for (DatastoreMO existingDatastore : existingDatastores) { - if (vmDatastoreNames.contains(existingDatastore.getName())) { - skipDatastores.add(existingDatastore.getName()); - } - } - deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true, skipDatastores); - } - - return startAnswer; - } catch (Throwable e) { - if (e instanceof RemoteException) { - s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); - invalidateServiceContext(); - } - - String msg = "StartCommand failed due to " + VmwareHelper.getExceptionMessage(e); - s_logger.warn(msg, e); - StartAnswer startAnswer = new StartAnswer(cmd, msg); - if (vmAlreadyExistsInVcenter) { - startAnswer.setContextParam("stopRetry", "true"); - } - - // Since VM start failed, if there was an existing VM in a different cluster that was unregistered, register it back. - if (existingVmName != null && existingVmFileInfo != null) { - s_logger.debug("Since VM start failed, registering back an existing VM: " + existingVmName + " that was unregistered"); - try { - DatastoreFile fileInDatastore = new DatastoreFile(existingVmFileInfo.getVmPathName()); - DatastoreMO existingVmDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); - registerVm(existingVmName, existingVmDsMo); - } catch (Exception ex) { - String message = "Failed to register an existing VM: " + existingVmName + " due to " + VmwareHelper.getExceptionMessage(ex); - s_logger.warn(message, ex); - } - } - - return startAnswer; - } finally { - } - } - - private void setBootOptions(VirtualMachineTO vmSpec, String bootMode, VirtualMachineConfigSpec vmConfigSpec) { - VirtualMachineBootOptions bootOptions = null; - if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) { - vmConfigSpec.setFirmware("efi"); - if (vmSpec.getDetails().containsKey(ApiConstants.BootType.UEFI.toString()) && "secure".equalsIgnoreCase(vmSpec.getDetails().get(ApiConstants.BootType.UEFI.toString()))) { - if (bootOptions == null) { - bootOptions = new VirtualMachineBootOptions(); - } - bootOptions.setEfiSecureBootEnabled(true); - } - } - if (vmSpec.isEnterHardwareSetup()) { - if (bootOptions == null) { - bootOptions = new VirtualMachineBootOptions(); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug(String.format("configuring VM '%s' to enter hardware setup",vmSpec.getName())); - } - bootOptions.setEnterBIOSSetup(vmSpec.isEnterHardwareSetup()); - } - if (bootOptions != null) { - vmConfigSpec.setBootOptions(bootOptions); - } + return startCommandExecutor.execute(cmd); } /** @@ -2525,7 +1685,7 @@ protected void copyVAppConfigsFromTemplate(VmConfigInfo vAppConfig, vmConfig.setVAppConfig(vmConfigSpec); } - private String appendFileType(String path, String fileType) { + static String appendFileType(String path, String fileType) { if (path.toLowerCase().endsWith(fileType.toLowerCase())) { return path; } @@ -2533,68 +1693,6 @@ private String appendFileType(String path, String fileType) { return path + fileType; } - private void resizeRootDiskOnVMStart(VirtualMachineMO vmMo, DiskTO rootDiskTO, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { - final Pair vdisk = getVirtualDiskInfo(vmMo, appendFileType(rootDiskTO.getPath(), VMDK_EXTENSION)); - assert (vdisk != null); - - Long reqSize = 0L; - final VolumeObjectTO volumeTO = ((VolumeObjectTO) rootDiskTO.getData()); - if (volumeTO != null) { - reqSize = volumeTO.getSize() / 1024; - } - final VirtualDisk disk = vdisk.first(); - if (reqSize > disk.getCapacityInKB()) { - final VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(vmMo.getDiskInfoBuilder(), rootDiskTO, hyperHost, context); - assert (diskInfo != null); - final String[] diskChain = diskInfo.getDiskChain(); - - if (diskChain != null && diskChain.length > 1) { - s_logger.warn("Disk chain length for the VM is greater than one, this is not supported"); - throw new CloudRuntimeException("Unsupported VM disk chain length: " + diskChain.length); - } - - boolean resizingSupported = false; - String deviceBusName = diskInfo.getDiskDeviceBusName(); - if (deviceBusName != null && (deviceBusName.toLowerCase().contains("scsi") || deviceBusName.toLowerCase().contains("lsi"))) { - resizingSupported = true; - } - if (!resizingSupported) { - s_logger.warn("Resizing of root disk is only support for scsi device/bus, the provide VM's disk device bus name is " + diskInfo.getDiskDeviceBusName()); - throw new CloudRuntimeException("Unsupported VM root disk device bus: " + diskInfo.getDiskDeviceBusName()); - } - - disk.setCapacityInKB(reqSize); - VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); - VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); - deviceConfigSpec.setDevice(disk); - deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); - vmConfigSpec.getDeviceChange().add(deviceConfigSpec); - if (!vmMo.configureVm(vmConfigSpec)) { - throw new Exception("Failed to configure VM for given root disk size. vmName: " + vmMo.getName()); - } - } - } - - - /** - * Generate the mac sequence from the nics. - */ - protected String generateMacSequence(NicTO[] nics) { - if (nics.length == 0) { - return ""; - } - - StringBuffer sbMacSequence = new StringBuffer(); - for (NicTO nicTo : sortNicsByDeviceId(nics)) { - sbMacSequence.append(nicTo.getMac()).append("|"); - } - if (!sbMacSequence.toString().isEmpty()) { - sbMacSequence.deleteCharAt(sbMacSequence.length() - 1); //Remove extra '|' char appended at the end - } - - return sbMacSequence.toString(); - } - /** * Update boot args with the new nic mac addresses. */ @@ -2659,128 +1757,36 @@ protected void modifyVmVideoCardVRamSize(VirtualMachineVideoCard videoCard, Virt } } - /** - * Add edit spec on {@code vmConfigSpec} to modify svga vram size - * - * @param videoCard video card device to edit providing the svga vram size - * @param svgaVmramSize new svga vram size (in KB) - * @param vmConfigSpec virtual machine spec - */ - protected void configureSpecVideoCardNewVRamSize(VirtualMachineVideoCard videoCard, long svgaVmramSize, VirtualMachineConfigSpec vmConfigSpec) { - videoCard.setVideoRamSizeInKB(svgaVmramSize); - videoCard.setUseAutoDetect(false); - - VirtualDeviceConfigSpec arrayVideoCardConfigSpecs = new VirtualDeviceConfigSpec(); - arrayVideoCardConfigSpecs.setDevice(videoCard); - arrayVideoCardConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.EDIT); - - vmConfigSpec.getDeviceChange().add(arrayVideoCardConfigSpecs); - } - - private void tearDownVm(VirtualMachineMO vmMo) throws Exception { - - if (vmMo == null) - return; - - boolean hasSnapshot = false; - hasSnapshot = vmMo.hasSnapshot(); - if (!hasSnapshot) - vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); - else - vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); - vmMo.ensureScsiDeviceController(); - } - - int getReservedMemoryMb(VirtualMachineTO vmSpec) { - if (vmSpec.getDetails().get(VMwareGuru.VmwareReserveMemory.key()).equalsIgnoreCase("true")) { - return (int) (vmSpec.getMinRam() / ResourceType.bytesToMiB); - } - return 0; - } - - int getReservedCpuMHZ(VirtualMachineTO vmSpec) { - if (vmSpec.getDetails().get(VMwareGuru.VmwareReserveCpu.key()).equalsIgnoreCase("true")) { - return vmSpec.getMinSpeed() * vmSpec.getCpus(); - } - return 0; - } - - // return the finalized disk chain for startup, from top to bottom - private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO vol, VirtualMachineDiskInfo diskInfo, - HashMap> dataStoresDetails) throws Exception { - - VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); - DataStoreTO primaryStore = volumeTO.getDataStore(); - Map details = vol.getDetails(); - boolean isManaged = false; - String iScsiName = null; - - if (details != null) { - isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - iScsiName = details.get(DiskTO.IQN); - } - - // if the storage is managed, iScsiName should not be null - String datastoreName = isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid(); - Pair volumeDsDetails = dataStoresDetails.get(datastoreName); - - if (volumeDsDetails == null) { - throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host."); - } - - DatastoreMO dsMo = volumeDsDetails.second(); - - // we will honor vCenter's meta if it exists - if (diskInfo != null) { - // to deal with run-time upgrade to maintain the new datastore folder structure - String disks[] = diskInfo.getDiskChain(); - for (int i = 0; i < disks.length; i++) { - DatastoreFile file = new DatastoreFile(disks[i]); - if (!isManaged && file.getDir() != null && file.getDir().isEmpty()) { - s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder"); - disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, file.getFileBaseName(), VmwareManager.s_vmwareSearchExcludeFolder.value()); - } - } - return disks; - } - - final String datastoreDiskPath; - - if (isManaged) { - String vmdkPath = new DatastoreFile(volumeTO.getPath()).getFileBaseName(); - - if (volumeTO.getVolumeType() == Volume.Type.ROOT) { - if (vmdkPath == null) { - vmdkPath = volumeTO.getName(); - } + /** + * Add edit spec on {@code vmConfigSpec} to modify svga vram size + * + * @param videoCard video card device to edit providing the svga vram size + * @param svgaVmramSize new svga vram size (in KB) + * @param vmConfigSpec virtual machine spec + */ + protected void configureSpecVideoCardNewVRamSize(VirtualMachineVideoCard videoCard, long svgaVmramSize, VirtualMachineConfigSpec vmConfigSpec) { + videoCard.setVideoRamSizeInKB(svgaVmramSize); + videoCard.setUseAutoDetect(false); - datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, vmdkPath); - } else { - if (vmdkPath == null) { - vmdkPath = dsMo.getName(); - } + VirtualDeviceConfigSpec arrayVideoCardConfigSpecs = new VirtualDeviceConfigSpec(); + arrayVideoCardConfigSpecs.setDevice(videoCard); + arrayVideoCardConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.EDIT); - datastoreDiskPath = dsMo.getDatastorePath(vmdkPath + VMDK_EXTENSION); - } - } else { - datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getPath(), VmwareManager.s_vmwareSearchExcludeFolder.value()); - } + vmConfigSpec.getDeviceChange().add(arrayVideoCardConfigSpecs); + } - if (!dsMo.fileExists(datastoreDiskPath)) { - s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath); + int getReservedMemoryMb(VirtualMachineTO vmSpec) { + if (vmSpec.getDetails().get(VMwareGuru.VmwareReserveMemory.key()).equalsIgnoreCase("true")) { + return (int) (vmSpec.getMinRam() / ResourceType.bytesToMiB); } - - return new String[]{datastoreDiskPath}; + return 0; } - // Pair - private Pair composeVmNames(VirtualMachineTO vmSpec) { - String vmInternalCSName = vmSpec.getName(); - String vmNameOnVcenter = vmSpec.getName(); - if (_instanceNameFlag && vmSpec.getHostName() != null) { - vmNameOnVcenter = vmSpec.getHostName(); + int getReservedCpuMHZ(VirtualMachineTO vmSpec) { + if (vmSpec.getDetails().get(VMwareGuru.VmwareReserveCpu.key()).equalsIgnoreCase("true")) { + return vmSpec.getMinSpeed() * vmSpec.getCpus(); } - return new Pair(vmInternalCSName, vmNameOnVcenter); + return 0; } protected void configNestedHVSupport(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, VirtualMachineConfigSpec vmConfigSpec) throws Exception { @@ -2808,357 +1814,6 @@ protected void configNestedHVSupport(VirtualMachineMO vmMo, VirtualMachineTO vmS } } - private static void configBasicExtraOption(List extraOptions, VirtualMachineTO vmSpec) { - OptionValue newVal = new OptionValue(); - newVal.setKey("machine.id"); - newVal.setValue(vmSpec.getBootArgs()); - extraOptions.add(newVal); - - newVal = new OptionValue(); - newVal.setKey("devices.hotplug"); - newVal.setValue("true"); - extraOptions.add(newVal); - } - - private static void configNvpExtraOption(List extraOptions, VirtualMachineTO vmSpec, Map nicUuidToDvSwitchUuid) { - /** - * Extra Config : nvp.vm-uuid = uuid - * - Required for Nicira NVP integration - */ - OptionValue newVal = new OptionValue(); - newVal.setKey("nvp.vm-uuid"); - newVal.setValue(vmSpec.getUuid()); - extraOptions.add(newVal); - - /** - * Extra Config : nvp.iface-id. = uuid - * - Required for Nicira NVP integration - */ - int nicNum = 0; - for (NicTO nicTo : sortNicsByDeviceId(vmSpec.getNics())) { - if (nicTo.getUuid() != null) { - newVal = new OptionValue(); - newVal.setKey("nvp.iface-id." + nicNum); - newVal.setValue(nicTo.getUuid()); - extraOptions.add(newVal); - } - nicNum++; - } - } - - private static void configCustomExtraOption(List extraOptions, VirtualMachineTO vmSpec) { - // we no longer to validation anymore - for (Map.Entry entry : vmSpec.getDetails().entrySet()) { - if (entry.getKey().equalsIgnoreCase(VmDetailConstants.BOOT_MODE)) { - continue; - } - OptionValue newVal = new OptionValue(); - newVal.setKey(entry.getKey()); - newVal.setValue(entry.getValue()); - extraOptions.add(newVal); - } - } - - private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) throws Exception { - /** - * We need to configure the port on the DV switch after the host is - * connected. So make this happen between the configure and start of - * the VM - */ - int nicIndex = 0; - for (NicTO nicTo : sortNicsByDeviceId(vmSpec.getNics())) { - if (nicTo.getBroadcastType() == BroadcastDomainType.Lswitch) { - // We need to create a port with a unique vlan and pass the key to the nic device - s_logger.trace("Nic " + nicTo.toString() + " is connected to an NVP logicalswitch"); - VirtualDevice nicVirtualDevice = vmMo.getNicDeviceByIndex(nicIndex); - if (nicVirtualDevice == null) { - throw new Exception("Failed to find a VirtualDevice for nic " + nicIndex); //FIXME Generic exceptions are bad - } - VirtualDeviceBackingInfo backing = nicVirtualDevice.getBacking(); - if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) { - // This NIC is connected to a Distributed Virtual Switch - VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing; - DistributedVirtualSwitchPortConnection port = portInfo.getPort(); - String portKey = port.getPortKey(); - String portGroupKey = port.getPortgroupKey(); - String dvSwitchUuid = port.getSwitchUuid(); - - s_logger.debug("NIC " + nicTo.toString() + " is connected to dvSwitch " + dvSwitchUuid + " pg " + portGroupKey + " port " + portKey); - - ManagedObjectReference dvSwitchManager = vmMo.getContext().getVimClient().getServiceContent().getDvSwitchManager(); - ManagedObjectReference dvSwitch = vmMo.getContext().getVimClient().getService().queryDvsByUuid(dvSwitchManager, dvSwitchUuid); - - // Get all ports - DistributedVirtualSwitchPortCriteria criteria = new DistributedVirtualSwitchPortCriteria(); - criteria.setInside(true); - criteria.getPortgroupKey().add(portGroupKey); - List dvPorts = vmMo.getContext().getVimClient().getService().fetchDVPorts(dvSwitch, criteria); - - DistributedVirtualPort vmDvPort = null; - List usedVlans = new ArrayList(); - for (DistributedVirtualPort dvPort : dvPorts) { - // Find the port for this NIC by portkey - if (portKey.equals(dvPort.getKey())) { - vmDvPort = dvPort; - } - VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPort.getConfig().getSetting(); - VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); - s_logger.trace("Found port " + dvPort.getKey() + " with vlan " + vlanId.getVlanId()); - if (vlanId.getVlanId() > 0 && vlanId.getVlanId() < 4095) { - usedVlans.add(vlanId.getVlanId()); - } - } - - if (vmDvPort == null) { - throw new Exception("Empty port list from dvSwitch for nic " + nicTo.toString()); - } - - DVPortConfigInfo dvPortConfigInfo = vmDvPort.getConfig(); - VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPortConfigInfo.getSetting(); - - VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); - BoolPolicy blocked = settings.getBlocked(); - if (blocked.isValue() == Boolean.TRUE) { - s_logger.trace("Port is blocked, set a vlanid and unblock"); - DVPortConfigSpec dvPortConfigSpec = new DVPortConfigSpec(); - VMwareDVSPortSetting edittedSettings = new VMwareDVSPortSetting(); - // Unblock - blocked.setValue(Boolean.FALSE); - blocked.setInherited(Boolean.FALSE); - edittedSettings.setBlocked(blocked); - // Set vlan - int i; - for (i = 1; i < 4095; i++) { - if (!usedVlans.contains(i)) - break; - } - vlanId.setVlanId(i); // FIXME should be a determined - // based on usage - vlanId.setInherited(false); - edittedSettings.setVlan(vlanId); - - dvPortConfigSpec.setSetting(edittedSettings); - dvPortConfigSpec.setOperation("edit"); - dvPortConfigSpec.setKey(portKey); - List dvPortConfigSpecs = new ArrayList(); - dvPortConfigSpecs.add(dvPortConfigSpec); - ManagedObjectReference task = vmMo.getContext().getVimClient().getService().reconfigureDVPortTask(dvSwitch, dvPortConfigSpecs); - if (!vmMo.getContext().getVimClient().waitForTask(task)) { - throw new Exception("Failed to configure the dvSwitch port for nic " + nicTo.toString()); - } - s_logger.debug("NIC " + nicTo.toString() + " connected to vlan " + i); - } else { - s_logger.trace("Port already configured and set to vlan " + vlanId.getVlanId()); - } - } else if (backing instanceof VirtualEthernetCardNetworkBackingInfo) { - // This NIC is connected to a Virtual Switch - // Nothing to do - } else if (backing instanceof VirtualEthernetCardOpaqueNetworkBackingInfo) { - //if NSX API VERSION >= 4.2, connect to br-int (nsx.network), do not create portgroup else previous behaviour - //OK, connected to OpaqueNetwork - } else { - s_logger.error("nic device backing is of type " + backing.getClass().getName()); - throw new Exception("Incompatible backing for a VirtualDevice for nic " + nicIndex); //FIXME Generic exceptions are bad - } - } - nicIndex++; - } - } - - private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context) - throws Exception { - if (diskInfoBuilder != null) { - VolumeObjectTO volume = (VolumeObjectTO) vol.getData(); - - String dsName = null; - String diskBackingFileBaseName = null; - - Map details = vol.getDetails(); - boolean isManaged = details != null && Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - - if (isManaged) { - String iScsiName = details.get(DiskTO.IQN); - - // if the storage is managed, iScsiName should not be null - dsName = VmwareResource.getDatastoreName(iScsiName); - - diskBackingFileBaseName = new DatastoreFile(volume.getPath()).getFileBaseName(); - } else { - ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, volume.getDataStore().getUuid()); - DatastoreMO dsMo = new DatastoreMO(context, morDs); - - dsName = dsMo.getName(); - - diskBackingFileBaseName = volume.getPath(); - } - - VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(diskBackingFileBaseName, dsName); - if (diskInfo != null) { - s_logger.info("Found existing disk info from volume path: " + volume.getPath()); - return diskInfo; - } else { - String chainInfo = volume.getChainInfo(); - if (chainInfo != null) { - VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); - if (infoInChain != null) { - String[] disks = infoInChain.getDiskChain(); - if (disks.length > 0) { - for (String diskPath : disks) { - DatastoreFile file = new DatastoreFile(diskPath); - diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName(), dsName); - if (diskInfo != null) { - s_logger.info("Found existing disk from chain info: " + diskPath); - return diskInfo; - } - } - } - - if (diskInfo == null) { - diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName()); - if (diskInfo != null) { - s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName()); - return diskInfo; - } - } - } - } - } - } - - return null; - } - - private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) { - - int controllerKey; - if (matchingExistingDisk != null) { - s_logger.info("Chose disk controller based on existing information: " + matchingExistingDisk.getDiskDeviceBusName()); - if (matchingExistingDisk.getDiskDeviceBusName().startsWith("ide")) - return ideControllerKey; - else - return scsiControllerKey; - } - - if (vol.getType() == Volume.Type.ROOT) { - Map vmDetails = vmSpec.getDetails(); - if (vmDetails != null && vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER) != null) { - if (vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER).equalsIgnoreCase("scsi")) { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: " - + vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER)); - controllerKey = scsiControllerKey; - } else { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: " - + vmDetails.get(VmDetailConstants.ROOT_DISK_CONTROLLER)); - controllerKey = ideControllerKey; - } - } else { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi. due to null root disk controller setting"); - controllerKey = scsiControllerKey; - } - - } else { - // DATA volume always use SCSI device - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi"); - controllerKey = scsiControllerKey; - } - - return controllerKey; - } - - private String getDiskController(VirtualMachineMO vmMo, VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol, Pair controllerInfo) throws Exception { - int controllerKey; - DiskControllerType controllerType = DiskControllerType.none; - if (matchingExistingDisk != null) { - String currentBusName = matchingExistingDisk.getDiskDeviceBusName(); - if (currentBusName != null) { - s_logger.info("Chose disk controller based on existing information: " + currentBusName); - if (currentBusName.startsWith("ide")) { - controllerType = DiskControllerType.ide; - } else if (currentBusName.startsWith("scsi")) { - controllerType = DiskControllerType.scsi; - } - } - if (controllerType == DiskControllerType.scsi || controllerType == DiskControllerType.none) { - Ternary vmScsiControllerInfo = vmMo.getScsiControllerInfo(); - controllerType = vmScsiControllerInfo.third(); - } - return controllerType.toString(); - } - - if (vol.getType() == Volume.Type.ROOT) { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> " + controllerInfo.first() - + ", based on root disk controller settings at global configuration setting."); - return controllerInfo.first(); - } else { - s_logger.info("Chose disk controller for vol " + vol.getType() + " -> " + controllerInfo.second() - + ", based on default data disk controller setting i.e. Operating system recommended."); // Need to bring in global configuration setting & template level setting. - return controllerInfo.second(); - } - } - - private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, int ideControllerKey, - int scsiControllerKey, Map> iqnToData, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { - VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); - - for (DiskTO vol : sortedDisks) { - if (vol.getType() == Volume.Type.ISO) - continue; - - VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); - - VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context); - assert (diskInfo != null); - - String[] diskChain = diskInfo.getDiskChain(); - assert (diskChain.length > 0); - - Map details = vol.getDetails(); - boolean managed = false; - - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - DatastoreFile file = new DatastoreFile(diskChain[0]); - - if (managed) { - DatastoreFile originalFile = new DatastoreFile(volumeTO.getPath()); - - if (!file.getFileBaseName().equalsIgnoreCase(originalFile.getFileBaseName())) { - if (s_logger.isInfoEnabled()) - s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + diskChain[0]); - } - } else { - if (!file.getFileBaseName().equalsIgnoreCase(volumeTO.getPath())) { - if (s_logger.isInfoEnabled()) - s_logger.info("Detected disk-chain top file change on volume: " + volumeTO.getId() + " " + volumeTO.getPath() + " -> " + file.getFileBaseName()); - } - } - - VolumeObjectTO volInSpec = getVolumeInSpec(vmSpec, volumeTO); - - if (volInSpec != null) { - if (managed) { - Map data = new HashMap<>(); - - String datastoreVolumePath = diskChain[0]; - - data.put(StartAnswer.PATH, datastoreVolumePath); - data.put(StartAnswer.IMAGE_FORMAT, Storage.ImageFormat.OVA.toString()); - - iqnToData.put(details.get(DiskTO.IQN), data); - - vol.setPath(datastoreVolumePath); - volumeTO.setPath(datastoreVolumePath); - volInSpec.setPath(datastoreVolumePath); - } else { - volInSpec.setPath(file.getFileBaseName()); - } - volInSpec.setChainInfo(_gson.toJson(diskInfo)); - } - } - } - private void checkAndDeleteDatastoreFile(String filePath, List skipDatastores, DatastoreMO dsMo, DatacenterMO dcMo) throws Exception { if (dsMo != null && dcMo != null && (skipDatastores == null || !skipDatastores.contains(dsMo.getName()))) { s_logger.debug("Deleting file: " + filePath); @@ -3166,7 +1821,7 @@ private void checkAndDeleteDatastoreFile(String filePath, List skipDatas } } - private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks, List skipDatastores) throws Exception { + void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks, List skipDatastores) throws Exception { s_logger.debug("Deleting files associated with an existing VM that was unregistered"); DatastoreFile vmFolder = null; try { @@ -3200,64 +1855,6 @@ else if (file.getType().equals("config")) } } - private static VolumeObjectTO getVolumeInSpec(VirtualMachineTO vmSpec, VolumeObjectTO srcVol) { - for (DiskTO disk : vmSpec.getDisks()) { - if (disk.getData() instanceof VolumeObjectTO) { - VolumeObjectTO vol = (VolumeObjectTO) disk.getData(); - if (vol.getId() == srcVol.getId()) - return vol; - } - } - - return null; - } - - private static NicTO[] sortNicsByDeviceId(NicTO[] nics) { - - List listForSort = new ArrayList(); - for (NicTO nic : nics) { - listForSort.add(nic); - } - Collections.sort(listForSort, new Comparator() { - - @Override - public int compare(NicTO arg0, NicTO arg1) { - if (arg0.getDeviceId() < arg1.getDeviceId()) { - return -1; - } else if (arg0.getDeviceId() == arg1.getDeviceId()) { - return 0; - } - - return 1; - } - }); - - return listForSort.toArray(new NicTO[0]); - } - - private static DiskTO[] sortVolumesByDeviceId(DiskTO[] volumes) { - - List listForSort = new ArrayList(); - for (DiskTO vol : volumes) { - listForSort.add(vol); - } - Collections.sort(listForSort, new Comparator() { - - @Override - public int compare(DiskTO arg0, DiskTO arg1) { - if (arg0.getDiskSeq() < arg1.getDiskSeq()) { - return -1; - } else if (arg0.getDiskSeq().equals(arg1.getDiskSeq())) { - return 0; - } - - return 1; - } - }); - - return listForSort.toArray(new DiskTO[0]); - } - /** * Only call this for managed storage. * Ex. "[-iqn.2010-01.com.solidfire:4nhe.vol-1.27-0] i-2-18-VM/ROOT-18.vmdk" should return "i-2-18-VM/ROOT-18" @@ -3277,9 +1874,7 @@ public String getVmdkPath(String path) { path = path.substring(startIndex + search.length()); - final String search2 = VMDK_EXTENSION; - - int endIndex = path.indexOf(search2); + int endIndex = path.indexOf(VMDK_EXTENSION); if (endIndex == -1) { return null; @@ -3288,113 +1883,6 @@ public String getVmdkPath(String path) { return path.substring(0, endIndex).trim(); } - private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, - DiskTO[] disks, Command cmd) throws Exception { - HashMap> mapIdToMors = new HashMap<>(); - - assert (hyperHost != null) && (context != null); - - for (DiskTO vol : disks) { - if (vol.getType() != Volume.Type.ISO) { - VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); - DataStoreTO primaryStore = volumeTO.getDataStore(); - String poolUuid = primaryStore.getUuid(); - - if (mapIdToMors.get(poolUuid) == null) { - boolean isManaged = false; - Map details = vol.getDetails(); - - if (details != null) { - isManaged = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - if (isManaged) { - String iScsiName = details.get(DiskTO.IQN); // details should not be null for managed storage (it may or may not be null for non-managed storage) - String datastoreName = VmwareResource.getDatastoreName(iScsiName); - ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreName); - - // if the datastore is not present, we need to discover the iSCSI device that will support it, - // create the datastore, and create a VMDK file in the datastore - if (morDatastore == null) { - final String vmdkPath = getVmdkPath(volumeTO.getPath()); - - morDatastore = _storageProcessor.prepareManagedStorage(context, hyperHost, null, iScsiName, - details.get(DiskTO.STORAGE_HOST), Integer.parseInt(details.get(DiskTO.STORAGE_PORT)), - vmdkPath, - details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), - details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET), - Long.parseLong(details.get(DiskTO.VOLUME_SIZE)), cmd); - - DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDatastore); - - final String datastoreVolumePath; - - if (vmdkPath != null) { - datastoreVolumePath = dsMo.getDatastorePath(vmdkPath + VMDK_EXTENSION); - } else { - datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + VMDK_EXTENSION); - } - - volumeTO.setPath(datastoreVolumePath); - vol.setPath(datastoreVolumePath); - } - - mapIdToMors.put(datastoreName, new Pair<>(morDatastore, new DatastoreMO(context, morDatastore))); - } else { - ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid); - - if (morDatastore == null) { - String msg = "Failed to get the mounted datastore for the volume's pool " + poolUuid; - - s_logger.error(msg); - - throw new Exception(msg); - } - - mapIdToMors.put(poolUuid, new Pair<>(morDatastore, new DatastoreMO(context, morDatastore))); - } - } - } - } - - return mapIdToMors; - } - - private DatastoreMO getDatastoreThatRootDiskIsOn(HashMap> dataStoresDetails, DiskTO disks[]) { - Pair rootDiskDataStoreDetails = null; - - for (DiskTO vol : disks) { - if (vol.getType() == Volume.Type.ROOT) { - Map details = vol.getDetails(); - boolean managed = false; - - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - if (managed) { - String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); - - rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); - - break; - } else { - DataStoreTO primaryStore = vol.getData().getDataStore(); - - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); - - break; - } - } - } - - if (rootDiskDataStoreDetails != null) { - return rootDiskDataStoreDetails.second(); - } - - return null; - } - private String getPvlanInfo(NicTO nicTo) { if (nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) { return NetUtils.getIsolatedPvlanFromUri(nicTo.getBroadcastUri()); @@ -3435,7 +1923,7 @@ private String getVlanInfo(NicTO nicTo, String defaultVlan) { return defaultVlan; } - private Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType) + Pair prepareNetworkFromNicInfo(HostMO hostMo, NicTO nicTo, boolean configureVServiceInNexus, VirtualMachine.Type vmType) throws Exception { Ternary switchDetails = getTargetSwitch(nicTo); @@ -3536,58 +2024,9 @@ private String getNetworkNamePrefix(NicTO nicTo) throws Exception { } } - private VirtualMachineMO takeVmFromOtherHyperHost(VmwareHypervisorHost hyperHost, String vmName) throws Exception { - - VirtualMachineMO vmMo = hyperHost.findVmOnPeerHyperHost(vmName); - if (vmMo != null) { - ManagedObjectReference morTargetPhysicalHost = hyperHost.findMigrationTarget(vmMo); - if (morTargetPhysicalHost == null) { - String msg = "VM " + vmName + " is on other host and we have no resource available to migrate and start it here"; - s_logger.error(msg); - throw new Exception(msg); - } - - if (!vmMo.relocate(morTargetPhysicalHost)) { - String msg = "VM " + vmName + " is on other host and we failed to relocate it here"; - s_logger.error(msg); - throw new Exception(msg); - } - - return vmMo; - } - return null; - } - - // isoUrl sample content : - // nfs://192.168.10.231/export/home/kelven/vmware-test/secondary/template/tmpl/2/200//200-2-80f7ee58-6eff-3a2d-bcb0-59663edf6d26.iso - private Pair getIsoDatastoreInfo(VmwareHypervisorHost hyperHost, String isoUrl) throws Exception { - - assert (isoUrl != null); - int isoFileNameStartPos = isoUrl.lastIndexOf("/"); - if (isoFileNameStartPos < 0) { - throw new Exception("Invalid ISO path info"); - } - - String isoFileName = isoUrl.substring(isoFileNameStartPos); - - int templateRootPos = isoUrl.indexOf("template/tmpl"); - templateRootPos = (templateRootPos < 0 ? isoUrl.indexOf(ConfigDrive.CONFIGDRIVEDIR) : templateRootPos); - if (templateRootPos < 0) { - throw new Exception("Invalid ISO path info"); - } - - String storeUrl = isoUrl.substring(0, templateRootPos - 1); - String isoPath = isoUrl.substring(templateRootPos, isoFileNameStartPos); - - ManagedObjectReference morDs = prepareSecondaryDatastoreOnHost(storeUrl); - DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs); - - return new Pair(String.format("[%s] %s%s", dsMo.getName(), isoPath, isoFileName), morDs); - } - protected Answer execute(ReadyCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource ReadyCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource ReadyCommand: " + gson.toJson(cmd)); } try { @@ -3606,7 +2045,7 @@ protected Answer execute(ReadyCommand cmd) { protected Answer execute(GetHostStatsCommand cmd) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Executing resource GetHostStatsCommand: " + _gson.toJson(cmd)); + s_logger.trace("Executing resource GetHostStatsCommand: " + gson.toJson(cmd)); } VmwareContext context = getServiceContext(); @@ -3631,7 +2070,7 @@ protected Answer execute(GetHostStatsCommand cmd) { } if (s_logger.isTraceEnabled()) { - s_logger.trace("GetHostStats Answer: " + _gson.toJson(answer)); + s_logger.trace("GetHostStats Answer: " + gson.toJson(answer)); } return answer; @@ -3639,7 +2078,7 @@ protected Answer execute(GetHostStatsCommand cmd) { protected Answer execute(GetVmStatsCommand cmd) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Executing resource GetVmStatsCommand: " + _gson.toJson(cmd)); + s_logger.trace("Executing resource GetVmStatsCommand: " + gson.toJson(cmd)); } HashMap vmStatsMap = null; @@ -3674,7 +2113,7 @@ protected Answer execute(GetVmStatsCommand cmd) { Answer answer = new GetVmStatsAnswer(cmd, vmStatsMap); if (s_logger.isTraceEnabled()) { - s_logger.trace("Report GetVmStatsAnswer: " + _gson.toJson(answer)); + s_logger.trace("Report GetVmStatsAnswer: " + gson.toJson(answer)); } return answer; } @@ -3814,7 +2253,7 @@ protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) { for (String chainInfo : cmd.getVolumeUuids()) { if (chainInfo != null) { - VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); + VirtualMachineDiskInfo infoInChain = gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); if (infoInChain != null) { String[] disks = infoInChain.getDiskChain(); if (disks.length > 0) { @@ -3849,7 +2288,7 @@ protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) { protected Answer execute(CheckHealthCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CheckHealthCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CheckHealthCommand: " + gson.toJson(cmd)); } try { @@ -3870,7 +2309,7 @@ protected Answer execute(CheckHealthCommand cmd) { protected Answer execute(StopCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource StopCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource StopCommand: " + gson.toJson(cmd)); } // In the stop command, we're passed in the name of the VM as seen by cloudstack, @@ -3902,7 +2341,7 @@ protected Answer execute(StopCommand cmd) { if (cmd.isForceStop()) { success = vmMo.powerOff(); } else { - success = vmMo.safePowerOff(_shutdownWaitMs); + success = vmMo.safePowerOff(shutdownWaitMs); } if (!success) { msg = "Have problem in powering off VM " + cmd.getVmName() + ", let the process continue"; @@ -3936,7 +2375,7 @@ protected Answer execute(StopCommand cmd) { protected Answer execute(RebootRouterCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource RebootRouterCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource RebootRouterCommand: " + gson.toJson(cmd)); } RebootAnswer answer = (RebootAnswer) execute((RebootCommand) cmd); @@ -3955,7 +2394,7 @@ protected Answer execute(RebootRouterCommand cmd) { protected Answer execute(RebootCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource RebootCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource RebootCommand: " + gson.toJson(cmd)); } boolean toolsInstallerMounted = false; @@ -4045,7 +2484,7 @@ private boolean canSetEnableSetupConfig(VirtualMachineMO vmMo, VirtualMachineTO protected Answer execute(CheckVirtualMachineCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CheckVirtualMachineCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CheckVirtualMachineCommand: " + gson.toJson(cmd)); } final String vmName = cmd.getVmName(); @@ -4078,7 +2517,7 @@ protected Answer execute(CheckVirtualMachineCommand cmd) { protected Answer execute(PrepareForMigrationCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource PrepareForMigrationCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource PrepareForMigrationCommand: " + gson.toJson(cmd)); } VirtualMachineTO vm = cmd.getVirtualMachine(); @@ -4111,12 +2550,12 @@ protected Answer execute(PrepareForMigrationCommand cmd) { prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); } - List> secStoreUrlAndIdList = mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(_dcId)); + List> secStoreUrlAndIdList = mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(dcId)); for (Pair secStoreUrlAndId : secStoreUrlAndIdList) { String secStoreUrl = secStoreUrlAndId.first(); Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { - String msg = String.format("Secondary storage for dc %s is not ready yet?", _dcId); + String msg = String.format("Secondary storage for dc %s is not ready yet?", dcId); throw new Exception(msg); } @@ -4147,7 +2586,7 @@ protected Answer execute(MigrateVmToPoolCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info(String.format("excuting MigrateVmToPoolCommand %s -> %s", cmd.getVmName(), cmd.getDestinationPool())); if (s_logger.isDebugEnabled()) { - s_logger.debug("MigrateVmToPoolCommand: " + _gson.toJson(cmd)); + s_logger.debug("MigrateVmToPoolCommand: " + gson.toJson(cmd)); } } @@ -4228,7 +2667,7 @@ Answer createAnswerForCmd(VirtualMachineMO vmMo, String poolUuid, Command cmd, M VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, poolUuid); newVol.setId(volumeDeviceKey.get(disk.getKey())); newVol.setPath(newPath); - newVol.setChainInfo(_gson.toJson(diskInfo)); + newVol.setChainInfo(gson.toJson(diskInfo)); volumeToList.add(newVol); } return new MigrateVmToPoolAnswer((MigrateVmToPoolCommand) cmd, volumeToList); @@ -4305,7 +2744,7 @@ private VirtualMachineMO getVirtualMachineMO(String vmName, VmwareHypervisorHost protected Answer execute(MigrateCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource MigrateCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource MigrateCommand: " + gson.toJson(cmd)); } final String vmName = cmd.getVmName(); @@ -4348,7 +2787,7 @@ protected Answer execute(MigrateCommand cmd) { protected Answer execute(MigrateWithStorageCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource MigrateWithStorageCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource MigrateWithStorageCommand: " + gson.toJson(cmd)); } VirtualMachineTO vmTo = cmd.getVirtualMachine(); @@ -4496,12 +2935,12 @@ protected Answer execute(MigrateWithStorageCommand cmd) { } // Ensure all secondary storage mounted on target host - List> secStoreUrlAndIdList = mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(_dcId)); + List> secStoreUrlAndIdList = mgr.getSecondaryStorageStoresUrlAndIdList(Long.parseLong(dcId)); for (Pair secStoreUrlAndId : secStoreUrlAndIdList) { String secStoreUrl = secStoreUrlAndId.first(); Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { - String msg = String.format("Secondary storage for dc %s is not ready yet?", _dcId); + String msg = String.format("Secondary storage for dc %s is not ready yet?", dcId); throw new Exception(msg); } @@ -4565,7 +3004,7 @@ protected Answer execute(MigrateWithStorageCommand cmd) { VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(newPath, poolName); newVol.setId(volumeId); newVol.setPath(newPath); - newVol.setChainInfo(_gson.toJson(diskInfo)); + newVol.setChainInfo(gson.toJson(diskInfo)); volumeToList.add(newVol); break; } @@ -4737,7 +3176,7 @@ private Answer execute(MigrateVolumeCommand cmd) { StorageFilerTO poolTo = cmd.getPool(); if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource MigrateVolumeCommand: " + gson.toJson(cmd)); } String vmName = cmd.getAttachedVmName(); @@ -4835,7 +3274,7 @@ private Answer execute(MigrateVolumeCommand cmd) { } } VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); - String chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, poolTo.getUuid().replace("-", ""))); + String chainInfo = gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, poolTo.getUuid().replace("-", ""))); MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath); answer.setVolumeChainInfo(chainInfo); return answer; @@ -4846,7 +3285,7 @@ private Answer execute(MigrateVolumeCommand cmd) { } } - private Pair getVirtualDiskInfo(VirtualMachineMO vmMo, String srcDiskName) throws Exception { + Pair getVirtualDiskInfo(VirtualMachineMO vmMo, String srcDiskName) throws Exception { Pair deviceInfo = vmMo.getDiskDevice(srcDiskName); if (deviceInfo == null) { throw new Exception("No such disk device: " + srcDiskName); @@ -4922,7 +3361,7 @@ protected Answer execute(ModifyTargetsCommand cmd) { protected Answer execute(ModifyStoragePoolCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource ModifyStoragePoolCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource ModifyStoragePoolCommand: " + gson.toJson(cmd)); } try { @@ -4984,7 +3423,7 @@ private void handleTargets(boolean add, ModifyTargetsCommand.TargetTypeToRemove protected Answer execute(DeleteStoragePoolCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource DeleteStoragePoolCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource DeleteStoragePoolCommand: " + gson.toJson(cmd)); } try { @@ -5027,7 +3466,7 @@ public static String createDatastoreNameFromIqn(String iqn) { protected AttachIsoAnswer execute(AttachIsoCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource AttachIsoCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource AttachIsoCommand: " + gson.toJson(cmd)); } try { @@ -5146,7 +3585,7 @@ private static String getSecondaryDatastoreUUID(String storeUrl) { protected Answer execute(ValidateSnapshotCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource ValidateSnapshotCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource ValidateSnapshotCommand: " + gson.toJson(cmd)); } // the command is no longer available @@ -5159,7 +3598,7 @@ protected Answer execute(ValidateSnapshotCommand cmd) { protected Answer execute(ManageSnapshotCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource ManageSnapshotCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource ManageSnapshotCommand: " + gson.toJson(cmd)); } long snapshotId = cmd.getSnapshotId(); @@ -5191,7 +3630,7 @@ protected Answer execute(ManageSnapshotCommand cmd) { protected Answer execute(BackupSnapshotCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource BackupSnapshotCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource BackupSnapshotCommand: " + gson.toJson(cmd)); } try { @@ -5248,7 +3687,7 @@ protected Answer execute(RevertToVMSnapshotCommand cmd) { protected Answer execute(CreateVolumeFromSnapshotCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CreateVolumeFromSnapshotCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CreateVolumeFromSnapshotCommand: " + gson.toJson(cmd)); } String details = null; @@ -5274,7 +3713,7 @@ protected Answer execute(CreateVolumeFromSnapshotCommand cmd) { protected Answer execute(CreatePrivateTemplateFromVolumeCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CreatePrivateTemplateFromVolumeCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CreatePrivateTemplateFromVolumeCommand: " + gson.toJson(cmd)); } try { @@ -5301,7 +3740,7 @@ protected Answer execute(final UpgradeSnapshotCommand cmd) { protected Answer execute(CreatePrivateTemplateFromSnapshotCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CreatePrivateTemplateFromSnapshotCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CreatePrivateTemplateFromSnapshotCommand: " + gson.toJson(cmd)); } try { @@ -5322,7 +3761,7 @@ protected Answer execute(CreatePrivateTemplateFromSnapshotCommand cmd) { protected Answer execute(GetStorageStatsCommand cmd) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Executing resource GetStorageStatsCommand: " + _gson.toJson(cmd)); + s_logger.trace("Executing resource GetStorageStatsCommand: " + gson.toJson(cmd)); } try { @@ -5371,7 +3810,7 @@ protected Answer execute(GetStorageStatsCommand cmd) { protected Answer execute(GetVncPortCommand cmd) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Executing resource GetVncPortCommand: " + _gson.toJson(cmd)); + s_logger.trace("Executing resource GetVncPortCommand: " + gson.toJson(cmd)); } try { @@ -5413,7 +3852,7 @@ protected Answer execute(GetVncPortCommand cmd) { protected Answer execute(SetupCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource SetupCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource SetupCommand: " + gson.toJson(cmd)); } return new SetupAnswer(cmd, false); @@ -5421,7 +3860,7 @@ protected Answer execute(SetupCommand cmd) { protected Answer execute(MaintainCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource MaintainCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource MaintainCommand: " + gson.toJson(cmd)); } return new MaintainAnswer(cmd, "Put host in maintaince"); @@ -5429,7 +3868,7 @@ protected Answer execute(MaintainCommand cmd) { protected Answer execute(PingTestCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource PingTestCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource PingTestCommand: " + gson.toJson(cmd)); } String controlIp = cmd.getRouterIp(); @@ -5473,7 +3912,7 @@ protected Answer execute(PingTestCommand cmd) { protected Answer execute(CheckOnHostCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CheckOnHostCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CheckOnHostCommand: " + gson.toJson(cmd)); } return new CheckOnHostAnswer(cmd, null, "Not Implmeneted"); @@ -5490,7 +3929,7 @@ protected Answer execute(ModifySshKeysCommand cmd) { protected Answer execute(GetVmIpAddressCommand cmd) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Executing resource command GetVmIpAddressCommand: " + _gson.toJson(cmd)); + s_logger.trace("Executing resource command GetVmIpAddressCommand: " + gson.toJson(cmd)); } String details = "Unable to find IP Address of VM. "; @@ -5536,7 +3975,7 @@ protected Answer execute(GetVmIpAddressCommand cmd) { answer = new Answer(cmd, result, details); if (s_logger.isTraceEnabled()) { - s_logger.trace("Returning GetVmIpAddressAnswer: " + _gson.toJson(answer)); + s_logger.trace("Returning GetVmIpAddressAnswer: " + gson.toJson(answer)); } return answer; } @@ -5544,7 +3983,7 @@ protected Answer execute(GetVmIpAddressCommand cmd) { @Override public PrimaryStorageDownloadAnswer execute(PrimaryStorageDownloadCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource PrimaryStorageDownloadCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource PrimaryStorageDownloadCommand: " + gson.toJson(cmd)); } try { @@ -5573,7 +4012,7 @@ protected Answer execute(PvlanSetupCommand cmd) { protected Answer execute(UnregisterVMCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource UnregisterVMCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource UnregisterVMCommand: " + gson.toJson(cmd)); } VmwareContext context = getServiceContext(); @@ -5623,7 +4062,7 @@ protected Answer execute(UnregisterVMCommand cmd) { * @return */ protected Answer execute(UnregisterNicCommand cmd) { - s_logger.info("Executing resource UnregisterNicCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource UnregisterNicCommand: " + gson.toJson(cmd)); if (_guestTrafficInfo == null) { return new Answer(cmd, false, "No Guest Traffic Info found, unable to determine where to clean up"); @@ -5682,7 +4121,7 @@ public void cleanupNetwork(HostMO hostMo, NetworkDetails netDetails) { @Override public CopyVolumeAnswer execute(CopyVolumeCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource CopyVolumeCommand: " + _gson.toJson(cmd)); + s_logger.info("Executing resource CopyVolumeCommand: " + gson.toJson(cmd)); } try { @@ -5875,11 +4314,11 @@ private List initializeLocalStorage() { cmd.setPoolInfo(pInfo); cmd.setGuid(poolUuid); // give storage host the same UUID as the local storage pool itself cmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL); - cmd.setDataCenter(_dcId); + cmd.setDataCenter(dcId); cmd.setPod(_pod); cmd.setCluster(_cluster); - s_logger.info("Add local storage startup command: " + _gson.toJson(cmd)); + s_logger.info("Add local storage startup command: " + gson.toJson(cmd)); storageCmds.add(cmd); } @@ -5923,7 +4362,7 @@ protected void fillHostInfo(StartupRoutingCommand cmd) { cmd.setHostDetails(details); cmd.setName(_url); cmd.setGuid(_guid); - cmd.setDataCenter(_dcId); + cmd.setDataCenter(dcId); cmd.setIqn(getIqn()); cmd.setPod(_pod); cmd.setCluster(_cluster); @@ -5961,7 +4400,7 @@ private void fillHostHardwareInfo(VmwareContext serviceContext, StartupRoutingCo VmwareHypervisorHostResourceSummary summary = hyperHost.getHyperHostResourceSummary(); if (s_logger.isInfoEnabled()) { - s_logger.info("Startup report on host hardware info. " + _gson.toJson(summary)); + s_logger.info("Startup report on host hardware info. " + gson.toJson(summary)); } cmd.setCaps("hvm"); @@ -5986,7 +4425,7 @@ private void fillHostNetworkInfo(VmwareContext serviceContext, StartupRoutingCom } if (s_logger.isInfoEnabled()) { - s_logger.info("Startup report on host network info. " + _gson.toJson(summary)); + s_logger.info("Startup report on host network info. " + gson.toJson(summary)); } cmd.setPrivateIpAddress(summary.getHostIp()); @@ -6093,35 +4532,6 @@ protected OptionValue[] configureVnc(OptionValue[] optionsToMerge, VmwareHypervi } } - private VirtualMachineGuestOsIdentifier translateGuestOsIdentifier(String cpuArchitecture, String guestOs, String cloudGuestOs) { - if (cpuArchitecture == null) { - s_logger.warn("CPU arch is not set, default to i386. guest os: " + guestOs); - cpuArchitecture = "i386"; - } - - if (cloudGuestOs == null) { - s_logger.warn("Guest OS mapping name is not set for guest os: " + guestOs); - } - - VirtualMachineGuestOsIdentifier identifier = null; - try { - if (cloudGuestOs != null) { - identifier = VirtualMachineGuestOsIdentifier.fromValue(cloudGuestOs); - s_logger.debug("Using mapping name : " + identifier.toString()); - } - } catch (IllegalArgumentException e) { - s_logger.warn("Unable to find Guest OS Identifier in VMware for mapping name: " + cloudGuestOs + ". Continuing with defaults."); - } - if (identifier != null) { - return identifier; - } - - if (cpuArchitecture.equalsIgnoreCase("x86_64")) { - return VirtualMachineGuestOsIdentifier.OTHER_GUEST_64; - } - return VirtualMachineGuestOsIdentifier.OTHER_GUEST; - } - private HashMap getHostVmStateReport() throws Exception { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); @@ -6559,7 +4969,7 @@ public boolean configure(String name, Map params) throws Configu _url = (String) params.get("url"); _username = (String) params.get("username"); _password = (String) params.get("password"); - _dcId = (String) params.get("zone"); + dcId = (String) params.get("zone"); _pod = (String) params.get("pod"); _cluster = (String) params.get("cluster"); @@ -6598,7 +5008,7 @@ public boolean configure(String name, Map params) throws Configu if (_guestTrafficInfo.getVirtualSwitchType() == VirtualSwitchType.NexusDistributedVirtualSwitch || _publicTrafficInfo.getVirtualSwitchType() == VirtualSwitchType.NexusDistributedVirtualSwitch) { - _privateNetworkVSwitchName = mgr.getPrivateVSwitchName(Long.parseLong(_dcId), HypervisorType.VMware); + _privateNetworkVSwitchName = mgr.getPrivateVSwitchName(Long.parseLong(dcId), HypervisorType.VMware); _vsmCredentials = mgr.getNexusVSMCredentialsByClusterId(Long.parseLong(_cluster)); } @@ -6635,16 +5045,16 @@ else if (value != null && value.equalsIgnoreCase("ide")) boolObj = (Boolean) params.get("vm.instancename.flag"); if (boolObj != null && boolObj.booleanValue()) { - _instanceNameFlag = true; + instanceNameFlag = true; } else { - _instanceNameFlag = false; + instanceNameFlag = false; } value = (String) params.get("scripts.timeout"); int timeout = NumbersUtil.parseInt(value, 1440) * 1000; storageNfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); - _storageProcessor = new VmwareStorageProcessor((VmwareHostService) this, _fullCloneFlag, (VmwareStorageMount) mgr, timeout, this, _shutdownWaitMs, null, + _storageProcessor = new VmwareStorageProcessor((VmwareHostService) this, _fullCloneFlag, (VmwareStorageMount) mgr, timeout, this, shutdownWaitMs, null, storageNfsVersion); storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, storageNfsVersion); @@ -6801,7 +5211,7 @@ public void setRunLevel(int level) { @Override public Answer execute(DestroyCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource DestroyCommand to evict template from storage pool: " + _gson.toJson(cmd)); + s_logger.info("Executing resource DestroyCommand to evict template from storage pool: " + gson.toJson(cmd)); } try { @@ -7156,7 +5566,7 @@ private UnmanagedInstanceTO getUnmanagedInstance(VmwareHypervisorHost hyperHost, private Answer execute(GetUnmanagedInstancesCommand cmd) { if (s_logger.isInfoEnabled()) { - s_logger.info("Executing resource GetUnmanagedInstancesCommand " + _gson.toJson(cmd)); + s_logger.info("Executing resource GetUnmanagedInstancesCommand " + gson.toJson(cmd)); } VmwareContext context = getServiceContext(); diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java new file mode 100644 index 000000000000..73832d368ab0 --- /dev/null +++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java @@ -0,0 +1,37 @@ +package com.cloud.hypervisor.vmware.resource; + +import com.cloud.agent.api.to.NicTO; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Spy; + +import static org.junit.Assert.assertEquals; + +public class StartCommandExecutorTest { + + @Spy + @InjectMocks + VmwareResource resource = new VmwareResource(); + + @Spy + @InjectMocks + StartCommandExecutor starter = new StartCommandExecutor(resource); + + @Test + public void generateMacSequence() { + final NicTO nicTo1 = new NicTO(); + nicTo1.setMac("01:23:45:67:89:AB"); + nicTo1.setDeviceId(1); + + final NicTO nicTo2 = new NicTO(); + nicTo2.setMac("02:00:65:b5:00:03"); + nicTo2.setDeviceId(0); + + //final NicTO [] nicTOs = {nicTO1, nicTO2, nicTO3}; + //final NicTO[] nics = new NicTO[]{nic}; + final NicTO[] nics = new NicTO[] {nicTo1, nicTo2}; + + String macSequence = starter.generateMacSequence(nics); + assertEquals(macSequence, "02:00:65:b5:00:03|01:23:45:67:89:AB"); + } +} \ No newline at end of file diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java index 7cebaf119106..a7a84c6eb0c7 100644 --- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java +++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -55,7 +55,6 @@ import com.cloud.agent.api.ScaleVmCommand; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.NfsTO; -import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -214,24 +213,6 @@ public void testScaleVMF1() throws Exception { verify(_resource).execute(cmd); } - @Test - public void testGenerateMacSequence() { - final NicTO nicTo1 = new NicTO(); - nicTo1.setMac("01:23:45:67:89:AB"); - nicTo1.setDeviceId(1); - - final NicTO nicTo2 = new NicTO(); - nicTo2.setMac("02:00:65:b5:00:03"); - nicTo2.setDeviceId(0); - - //final NicTO [] nicTOs = {nicTO1, nicTO2, nicTO3}; - //final NicTO[] nics = new NicTO[]{nic}; - final NicTO[] nics = new NicTO[] {nicTo1, nicTo2}; - - String macSequence = _resource.generateMacSequence(nics); - assertEquals(macSequence, "02:00:65:b5:00:03|01:23:45:67:89:AB"); - } - @Test public void testReplaceNicsMacSequenceInBootArgs() { String bootArgs = "nic_macs=02:00:65:b5:00:03|7C02:00:4f:1b:00:15|7C1e:00:54:00:00:0f|7C02:00:35:fa:00:11|7C02:00:47:40:00:12"; From 680fd7d12cc11357b8e605cb63c6dc496528cfc2 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 12 Jun 2020 17:07:11 +0000 Subject: [PATCH 023/148] execute start; init of disk info factorred out --- .../vmware/resource/StartCommandExecutor.java | 131 +++++++++++------- 1 file changed, 78 insertions(+), 53 deletions(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java index 142f97f8c274..39d7bd914c6c 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java @@ -122,7 +122,6 @@ protected StartAnswer execute(StartCommand cmd) { } } VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - boolean vmAlreadyExistsInVcenter = false; String existingVmName = null; VirtualMachineFileInfo existingVmFileInfo = null; @@ -132,38 +131,14 @@ protected StartAnswer execute(StartCommand cmd) { Pair names = composeVmNames(vmSpec); String vmInternalCSName = names.first(); String vmNameOnVcenter = names.second(); - String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER); - String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); - DiskTO rootDiskTO = null; - String bootMode = null; - if (vmSpec.getDetails().containsKey(VmDetailConstants.BOOT_MODE)) { - bootMode = vmSpec.getDetails().get(VmDetailConstants.BOOT_MODE); - } - if (null == bootMode) { - bootMode = ApiConstants.BootType.BIOS.toString(); - } - - // If root disk controller is scsi, then data disk controller would also be scsi instead of using 'osdefault' - // This helps avoid mix of different scsi subtype controllers in instance. - if (DiskControllerType.osdefault == DiskControllerType.getType(dataDiskController) && DiskControllerType.lsilogic == DiskControllerType.getType(rootDiskController)) { - dataDiskController = DiskControllerType.scsi.toString(); - } - - // Validate the controller types - dataDiskController = DiskControllerType.getType(dataDiskController).toString(); - rootDiskController = DiskControllerType.getType(rootDiskController).toString(); - if (DiskControllerType.getType(rootDiskController) == DiskControllerType.none) { - throw new CloudRuntimeException("Invalid root disk controller detected : " + rootDiskController); - } - if (DiskControllerType.getType(dataDiskController) == DiskControllerType.none) { - throw new CloudRuntimeException("Invalid data disk controller detected : " + dataDiskController); - } + DiskTO rootDiskTO = null; - Pair controllerInfo = new Pair<>(rootDiskController, dataDiskController); + Pair controllerInfo = getDiskControllerInfo(vmSpec); Boolean systemVm = vmSpec.getType().isUsedBySystem(); - // Thus, vmInternalCSName always holds i-x-y, the cloudstack generated internal VM name. + + // Thus, vmInternalCSName always holds i-x-y, the cloudstack generated internal VM name. FR37 this is an out of place comment VmwareContext context = vmwareResource.getServiceContext(); DatacenterMO dcMo = null; try { @@ -172,14 +147,8 @@ protected StartAnswer execute(StartCommand cmd) { VmwareHypervisorHost hyperHost = vmwareResource.getHyperHost(context); dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter()); - // Validate VM name is unique in Datacenter - VirtualMachineMO vmInVcenter = dcMo.checkIfVmAlreadyExistsInVcenter(vmNameOnVcenter, vmInternalCSName); - if (vmInVcenter != null) { - vmAlreadyExistsInVcenter = true; - String msg = "VM with name: " + vmNameOnVcenter + " already exists in vCenter."; - LOGGER.error(msg); - throw new Exception(msg); - } + checkIfVmExistsInVcenter(vmInternalCSName, vmNameOnVcenter, dcMo); + // FR37 disks should not yet be our concern String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value(); DiskTO[] disks = validateDisks(vmSpec.getDisks()); @@ -504,7 +473,7 @@ protected StartAnswer execute(StartCommand cmd) { VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context); controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey); - String diskController = getDiskController(vmMo, matchingExistingDisk, vol, new Pair<>(rootDiskController, dataDiskController)); + String diskController = getDiskController(vmMo, matchingExistingDisk, vol, controllerInfo); if (DiskControllerType.getType(diskController) == DiskControllerType.osdefault) { diskController = vmMo.getRecommendedDiskController(null); @@ -736,7 +705,7 @@ protected StartAnswer execute(StartCommand cmd) { } } - setBootOptions(vmSpec, bootMode, vmConfigSpec); + checkBootOptions(vmSpec, vmConfigSpec); // // Configure VM @@ -803,22 +772,10 @@ protected StartAnswer execute(StartCommand cmd) { String msg = "StartCommand failed due to " + VmwareHelper.getExceptionMessage(e); LOGGER.warn(msg, e); StartAnswer startAnswer = new StartAnswer(cmd, msg); - if (vmAlreadyExistsInVcenter) { + if ( e instanceof VmAlreadyExistsInVcenter) { startAnswer.setContextParam("stopRetry", "true"); } - - // Since VM start failed, if there was an existing VM in a different cluster that was unregistered, register it back. - if (existingVmName != null && existingVmFileInfo != null) { - LOGGER.debug("Since VM start failed, registering back an existing VM: " + existingVmName + " that was unregistered"); - try { - DatastoreFile fileInDatastore = new DatastoreFile(existingVmFileInfo.getVmPathName()); - DatastoreMO existingVmDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); - registerVm(existingVmName, existingVmDsMo, vmwareResource); - } catch (Exception ex) { - String message = "Failed to register an existing VM: " + existingVmName + " due to " + VmwareHelper.getExceptionMessage(ex); - LOGGER.warn(message, ex); - } - } + reRegisterExistingVm(existingVmName, existingVmFileInfo, dcMo); return startAnswer; } finally { @@ -828,6 +785,58 @@ protected StartAnswer execute(StartCommand cmd) { } } + /** + * Since VM start failed, if there was an existing VM in a different cluster that was unregistered, register it back. + * + * @param dcMo is guaranteed to be not null since we have noticed there is an existing VM in the dc (using that mo) + */ + private void reRegisterExistingVm(String existingVmName, VirtualMachineFileInfo existingVmFileInfo, DatacenterMO dcMo) { + if (existingVmName != null && existingVmFileInfo != null) { + LOGGER.debug("Since VM start failed, registering back an existing VM: " + existingVmName + " that was unregistered"); + try { + DatastoreFile fileInDatastore = new DatastoreFile(existingVmFileInfo.getVmPathName()); + DatastoreMO existingVmDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); + registerVm(existingVmName, existingVmDsMo, vmwareResource); + } catch (Exception ex) { + String message = "Failed to register an existing VM: " + existingVmName + " due to " + VmwareHelper.getExceptionMessage(ex); + LOGGER.warn(message, ex); + } + } + } + + private void checkIfVmExistsInVcenter(String vmInternalCSName, String vmNameOnVcenter, DatacenterMO dcMo) throws VmAlreadyExistsInVcenter, Exception { + // Validate VM name is unique in Datacenter + VirtualMachineMO vmInVcenter = dcMo.checkIfVmAlreadyExistsInVcenter(vmNameOnVcenter, vmInternalCSName); + if (vmInVcenter != null) { + String msg = "VM with name: " + vmNameOnVcenter + " already exists in vCenter."; + LOGGER.error(msg); + throw new VmAlreadyExistsInVcenter(msg); + } + } + + private Pair getDiskControllerInfo(VirtualMachineTO vmSpec) { + String dataDiskController = vmSpec.getDetails().get(VmDetailConstants.DATA_DISK_CONTROLLER); + String rootDiskController = vmSpec.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); + // If root disk controller is scsi, then data disk controller would also be scsi instead of using 'osdefault' + // This helps avoid mix of different scsi subtype controllers in instance. + if (DiskControllerType.osdefault == DiskControllerType.getType(dataDiskController) && DiskControllerType.lsilogic == DiskControllerType.getType(rootDiskController)) { + dataDiskController = DiskControllerType.scsi.toString(); + } + + // Validate the controller types + dataDiskController = DiskControllerType.getType(dataDiskController).toString(); + rootDiskController = DiskControllerType.getType(rootDiskController).toString(); + + if (DiskControllerType.getType(rootDiskController) == DiskControllerType.none) { + throw new CloudRuntimeException("Invalid root disk controller detected : " + rootDiskController); + } + if (DiskControllerType.getType(dataDiskController) == DiskControllerType.none) { + throw new CloudRuntimeException("Invalid data disk controller detected : " + dataDiskController); + } + + return new Pair<>(rootDiskController, dataDiskController); + } + /** * Registers the vm to the inventory given the vmx file. * @param vmName @@ -1316,6 +1325,18 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v } } + private void checkBootOptions(VirtualMachineTO vmSpec, VirtualMachineConfigSpec vmConfigSpec) { + String bootMode = null; + if (vmSpec.getDetails().containsKey(VmDetailConstants.BOOT_MODE)) { + bootMode = vmSpec.getDetails().get(VmDetailConstants.BOOT_MODE); + } + if (null == bootMode) { + bootMode = ApiConstants.BootType.BIOS.toString(); + } + + setBootOptions(vmSpec, bootMode, vmConfigSpec); + } + private void setBootOptions(VirtualMachineTO vmSpec, String bootMode, VirtualMachineConfigSpec vmConfigSpec) { VirtualMachineBootOptions bootOptions = null; if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) { @@ -1725,4 +1746,8 @@ private static void configCustomExtraOption(List extraOptions, Virt } } + private class VmAlreadyExistsInVcenter extends Throwable { + public VmAlreadyExistsInVcenter(String msg) { + } + } } \ No newline at end of file From 5c4bcb0b2f3ada89dd5e399bdb98d474768a999e Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Fri, 5 Jun 2020 14:58:27 +0530 Subject: [PATCH 024/148] Added Storagepolicy while creating diskoffering. CreateDiskOffering API now takes storagepolicy as a parameter with UUID value --- .../admin/offering/CreateDiskOfferingCmd.java | 7 +++++++ .../ImportVsphereStoragePoliciesResponse.java | 0 .../ConfigurationManagerImpl.java | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) rename {plugins/hypervisors/vmware => api}/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java (100%) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java index f0ca5fb851a1..4f9eebeb2537 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ImportVsphereStoragePoliciesResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -151,6 +152,9 @@ public class CreateDiskOfferingCmd extends BaseCmd { since = "4.14") private String cacheMode; + @Parameter(name = ApiConstants.STORAGE_POLICY, type = CommandType.UUID, entityType = ImportVsphereStoragePoliciesResponse.class,required = false, description = "Name of the storage policy defined at vCenter, this is applicable only for VMware") + private Long storagePolicy; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -273,6 +277,9 @@ public String getCacheMode() { return cacheMode; } + public Long getStoragePolicy() { + return storagePolicy; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java similarity index 100% rename from plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java rename to api/src/main/java/org/apache/cloudstack/api/response/ImportVsphereStoragePoliciesResponse.java diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 7e9c9d39c2b1..551248352ad6 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -39,6 +39,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.dao.VsphereStoragePolicyDao; import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -386,6 +387,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati IndirectAgentLB _indirectAgentLB; @Inject private VMTemplateZoneDao templateZoneDao; + @Inject + VsphereStoragePolicyDao vsphereStoragePolicyDao; + // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject @@ -2820,7 +2824,7 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength, - final Integer hypervisorSnapshotReserve, String cacheMode) { + final Integer hypervisorSnapshotReserve, String cacheMode, final Long storagePolicyID) { long diskSize = 0;// special case for custom disk offerings if (numGibibytes != null && numGibibytes <= 0) { throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb."); @@ -2948,6 +2952,9 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List detailsVO.add(new DiskOfferingDetailVO(offering.getId(), ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); } } + if (storagePolicyID != null) { + detailsVO.add(new DiskOfferingDetailVO(offering.getId(), ApiConstants.STORAGE_POLICY, String.valueOf(storagePolicyID), false)); + } if (!detailsVO.isEmpty()) { diskOfferingDetailsDao.saveDetails(detailsVO); } @@ -2969,6 +2976,7 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { final String tags = cmd.getTags(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); + final Long storagePolicyId = cmd.getStoragePolicy(); // check if valid domain if (CollectionUtils.isNotEmpty(domainIds)) { @@ -3008,6 +3016,12 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { } } + if (storagePolicyId != null) { + if (vsphereStoragePolicyDao.findById(storagePolicyId) == null) { + throw new InvalidParameterValueException("Please specify a valid vSphere storage policy id"); + } + } + final Boolean isCustomizedIops = cmd.isCustomizedIops(); final Long minIops = cmd.getMinIops(); final Long maxIops = cmd.getMaxIops(); @@ -3038,7 +3052,7 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops, maxIops, bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength, iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength, - hypervisorSnapshotReserve, cacheMode); + hypervisorSnapshotReserve, cacheMode, storagePolicyId); } /** From d1af0d10bdb0684498058d6c67574d9728b5f02d Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Mon, 15 Jun 2020 08:44:26 +0530 Subject: [PATCH 025/148] Unit test fix --- server/src/test/resources/createNetworkOffering.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/test/resources/createNetworkOffering.xml b/server/src/test/resources/createNetworkOffering.xml index 8dee0e8a54ee..55343ef835d4 100644 --- a/server/src/test/resources/createNetworkOffering.xml +++ b/server/src/test/resources/createNetworkOffering.xml @@ -60,4 +60,5 @@ + From 78cab3409644e8c69a5b0edf9159e6ce92326013 Mon Sep 17 00:00:00 2001 From: dahn Date: Mon, 15 Jun 2020 09:43:11 +0200 Subject: [PATCH 026/148] license --- .../resource/StartCommandExecutorTest.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java index 73832d368ab0..dc2474ae7907 100644 --- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java +++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutorTest.java @@ -1,3 +1,20 @@ +// 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.vmware.resource; import com.cloud.agent.api.to.NicTO; @@ -34,4 +51,4 @@ public void generateMacSequence() { String macSequence = starter.generateMacSequence(nics); assertEquals(macSequence, "02:00:65:b5:00:03|01:23:45:67:89:AB"); } -} \ No newline at end of file +} From 96f35cfe5f3456a299fc465d79eb1f416d750e22 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 15 Jun 2020 11:34:37 +0000 Subject: [PATCH 027/148] howto pass deploy OVA as is? --- .../cloud/agent/api/to/VirtualMachineTO.java | 11 ++ .../hypervisor/guru/VmwareVmImplementer.java | 4 + .../vmware/resource/StartCommandExecutor.java | 125 +++++++++++------- 3 files changed, 89 insertions(+), 51 deletions(-) diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java index dceacf0e65bc..eaca567957cc 100644 --- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java @@ -83,6 +83,8 @@ public class VirtualMachineTO { Map extraConfig = new HashMap<>(); @LogLevel(LogLevel.Log4jLevel.Off) Pair> ovfProperties; + // FR37 todo change to URL? + String templateLocation = null; public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, String os, boolean enableHA, boolean limitCpuUse, String vncPassword) { @@ -402,4 +404,13 @@ public boolean isEnterHardwareSetup() { public void setEnterHardwareSetup(boolean enterHardwareSetup) { this.enterHardwareSetup = enterHardwareSetup; } + + public String getTemplateLocation() { + return templateLocation; + } + + public void setTemplateLocation(String templateLocation) { + this.templateLocation = templateLocation; + } + } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java index 9e98c4b33791..63e20804d39c 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java @@ -121,6 +121,10 @@ VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long c // FR37 so the url for the original OVA can be used for deployment if (deployOvaAsIs) { if (LOG.isTraceEnabled()) { + // FR37 todo MAYBE add flag for deploy as is TO + + // FR37 TODO add url for template in TO + to.setTemplateLocation(vm.getTemplate().getUrl()); // FR37 TODO add usefull stuff in message LOG.trace("deploying OVA as is."); } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java index 39d7bd914c6c..7d4b5e65d495 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java @@ -114,19 +114,17 @@ protected StartAnswer execute(StartCommand cmd) { LOGGER.info("Executing resource StartCommand: " + vmwareResource.getGson().toJson(cmd)); } - // FR37 if startcommand contains a secendary storage URL or some flag or other type of indicator, deploy OVA as is - String secStorUrl = cmd.getSecondaryStorage(); - if (StringUtils.isNotEmpty(secStorUrl)) { + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); + + boolean installAsIs = StringUtils.isNotEmpty(vmSpec.getTemplateLocation()); + // FR37 if startcommand contains a template url deploy OVA as is + if (installAsIs) { if (LOGGER.isTraceEnabled()) { - LOGGER.trace(String.format("deploying OVA as is from %s", secStorUrl)); + LOGGER.trace(String.format("deploying OVA as is from %s", vmSpec.getTemplateLocation())); } } - VirtualMachineTO vmSpec = cmd.getVirtualMachine(); - String existingVmName = null; - VirtualMachineFileInfo existingVmFileInfo = null; - VirtualMachineFileLayoutEx existingVmFileLayout = null; - List existingDatastores = new ArrayList<>(); + VirtualMachineData existingVm = null; Pair names = composeVmNames(vmSpec); String vmInternalCSName = names.first(); @@ -225,37 +223,9 @@ protected StartAnswer execute(StartCommand cmd) { ensureDiskControllers(vmMo, controllerInfo); } } else { - // If a VM with the same name is found in a different cluster in the DC, unregister the old VM and configure a new VM (cold-migration). - VirtualMachineMO existingVmInDc = dcMo.findVm(vmInternalCSName); - if (existingVmInDc != null) { - LOGGER.debug("Found VM: " + vmInternalCSName + " on a host in a different cluster. Unregistering the exisitng VM."); - existingVmName = existingVmInDc.getName(); - existingVmFileInfo = existingVmInDc.getFileInfo(); - existingVmFileLayout = existingVmInDc.getFileLayout(); - existingDatastores = existingVmInDc.getAllDatastores(); - existingVmInDc.unregisterVm(); - } - Pair rootDiskDataStoreDetails = null; - for (DiskTO vol : disks) { - if (vol.getType() == Volume.Type.ROOT) { - Map details = vol.getDetails(); - boolean managed = false; + existingVm = unregisterButHoldOnToOldVmData(vmInternalCSName, dcMo); - if (details != null) { - managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); - } - - if (managed) { - String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); - - rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); - } else { - DataStoreTO primaryStore = vol.getData().getDataStore(); - - rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); - } - } - } + Pair rootDiskDataStoreDetails = getRootDiskDataStoreDetails(disks, dataStoresDetails); assert (vmSpec.getMinSpeed() != null) && (rootDiskDataStoreDetails != null); @@ -270,8 +240,11 @@ protected StartAnswer execute(StartCommand cmd) { } } tearDownVm(vmMo); + } else if (installAsIs) { + // FR37 create blank or install as is ???? needs to be replaced with the proceudre at + // https://code.vmware.com/docs/5540/vsphere-automation-sdks-programming-guide/doc/GUID-82084C78-49FC-4B7F-BD89-F90D5AA22631.html + hyperHost.importVmFromOVF(vmSpec.getTemplateLocation(), vmNameOnVcenter, rootDiskDataStoreDetails.second(), "thin"); } else { - // FR37 create blank or install as is ???? if (!hyperHost .createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmwareResource.getReservedCpuMHZ(vmSpec), vmSpec.getLimitCpuUse(), (int)(vmSpec.getMaxRam() / Resource.ResourceType.bytesToMiB), vmwareResource.getReservedMemoryMb(vmSpec), guestOsId, rootDiskDataStoreDetails.first(), false, controllerInfo, systemVm)) { @@ -747,19 +720,19 @@ protected StartAnswer execute(StartCommand cmd) { startAnswer.setIqnToData(iqnToData); // Since VM was successfully powered-on, if there was an existing VM in a different cluster that was unregistered, delete all the files associated with it. - if (existingVmName != null && existingVmFileLayout != null) { + if (existingVm != null && existingVm.vmName != null && existingVm.vmFileLayout != null) { List vmDatastoreNames = new ArrayList<>(); for (DatastoreMO vmDatastore : vmMo.getAllDatastores()) { vmDatastoreNames.add(vmDatastore.getName()); } // Don't delete files that are in a datastore that is being used by the new VM as well (zone-wide datastore). List skipDatastores = new ArrayList<>(); - for (DatastoreMO existingDatastore : existingDatastores) { + for (DatastoreMO existingDatastore : existingVm.datastores) { if (vmDatastoreNames.contains(existingDatastore.getName())) { skipDatastores.add(existingDatastore.getName()); } } - vmwareResource.deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true, skipDatastores); + vmwareResource.deleteUnregisteredVmFiles(existingVm.vmFileLayout, dcMo, true, skipDatastores); } return startAnswer; @@ -775,7 +748,7 @@ protected StartAnswer execute(StartCommand cmd) { if ( e instanceof VmAlreadyExistsInVcenter) { startAnswer.setContextParam("stopRetry", "true"); } - reRegisterExistingVm(existingVmName, existingVmFileInfo, dcMo); + reRegisterExistingVm(existingVm, dcMo); return startAnswer; } finally { @@ -785,20 +758,63 @@ protected StartAnswer execute(StartCommand cmd) { } } + /** + * If a VM with the same name is found in a different cluster in the DC, unregister the old VM and configure a new VM (cold-migration). + */ + private VirtualMachineData unregisterButHoldOnToOldVmData(String vmInternalCSName, DatacenterMO dcMo) throws Exception { + VirtualMachineMO existingVmInDc = dcMo.findVm(vmInternalCSName); + VirtualMachineData existingVm = null; + if (existingVmInDc != null) { + existingVm = new VirtualMachineData(); + existingVm.vmName = existingVmInDc.getName(); + existingVm.vmFileInfo = existingVmInDc.getFileInfo(); + existingVm.vmFileLayout = existingVmInDc.getFileLayout(); + existingVm.datastores = existingVmInDc.getAllDatastores(); + LOGGER.info("Found VM: " + vmInternalCSName + " on a host in a different cluster. Unregistering the exisitng VM."); + existingVmInDc.unregisterVm(); + } + return existingVm; + } + + private Pair getRootDiskDataStoreDetails(DiskTO[] disks, HashMap> dataStoresDetails) { + Pair rootDiskDataStoreDetails = null; + for (DiskTO vol : disks) { + if (vol.getType() == Volume.Type.ROOT) { + Map details = vol.getDetails(); + boolean managed = false; + + if (details != null) { + managed = Boolean.parseBoolean(details.get(DiskTO.MANAGED)); + } + + if (managed) { + String datastoreName = VmwareResource.getDatastoreName(details.get(DiskTO.IQN)); + + rootDiskDataStoreDetails = dataStoresDetails.get(datastoreName); + } else { + DataStoreTO primaryStore = vol.getData().getDataStore(); + + rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid()); + } + } + } + return rootDiskDataStoreDetails; + } + /** * Since VM start failed, if there was an existing VM in a different cluster that was unregistered, register it back. * * @param dcMo is guaranteed to be not null since we have noticed there is an existing VM in the dc (using that mo) */ - private void reRegisterExistingVm(String existingVmName, VirtualMachineFileInfo existingVmFileInfo, DatacenterMO dcMo) { - if (existingVmName != null && existingVmFileInfo != null) { - LOGGER.debug("Since VM start failed, registering back an existing VM: " + existingVmName + " that was unregistered"); + private void reRegisterExistingVm(VirtualMachineData existingVm, DatacenterMO dcMo) { + if (existingVm != null && existingVm.vmName != null && existingVm.vmFileInfo != null) { + LOGGER.debug("Since VM start failed, registering back an existing VM: " + existingVm.vmName + " that was unregistered"); try { - DatastoreFile fileInDatastore = new DatastoreFile(existingVmFileInfo.getVmPathName()); + DatastoreFile fileInDatastore = new DatastoreFile(existingVm.vmFileInfo.getVmPathName()); DatastoreMO existingVmDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); - registerVm(existingVmName, existingVmDsMo, vmwareResource); + registerVm(existingVm.vmName, existingVmDsMo, vmwareResource); } catch (Exception ex) { - String message = "Failed to register an existing VM: " + existingVmName + " due to " + VmwareHelper.getExceptionMessage(ex); + String message = "Failed to register an existing VM: " + existingVm.vmName + " due to " + VmwareHelper.getExceptionMessage(ex); LOGGER.warn(message, ex); } } @@ -1746,8 +1762,15 @@ private static void configCustomExtraOption(List extraOptions, Virt } } - private class VmAlreadyExistsInVcenter extends Throwable { + private class VmAlreadyExistsInVcenter extends Exception { public VmAlreadyExistsInVcenter(String msg) { } } + + private class VirtualMachineData { + String vmName = null; + VirtualMachineFileInfo vmFileInfo = null; + VirtualMachineFileLayoutEx vmFileLayout = null; + List datastores = new ArrayList<>(); + } } \ No newline at end of file From 38b9a7627ce98f6b59dc2a58ee1851f6c9e71149 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 15 Jun 2020 13:53:29 +0000 Subject: [PATCH 028/148] logging during ingestion and guest net creation --- .../admin/vm/ImportUnmanagedInstanceCmd.java | 19 ++++++++++++++----- .../orchestration/NetworkOrchestrator.java | 4 ++-- .../ConfigurationManagerImpl.java | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java index 10321cc035d4..7127bac8d785 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java @@ -204,6 +204,9 @@ public Map getNicNetworkList() { for (Map entry : (Collection>)nicNetworkList.values()) { String nic = entry.get(VmDetailConstants.NIC); String networkUuid = entry.get(VmDetailConstants.NETWORK); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(String.format("nic, '%s', goes on net, '%s'", nic, networkUuid)); + } if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) { throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic)); } @@ -219,11 +222,14 @@ public Map getNicIpAddressList() { for (Map entry : (Collection>)nicIpAddressList.values()) { String nic = entry.get(VmDetailConstants.NIC); String ipAddress = Strings.emptyToNull(entry.get(VmDetailConstants.IP4_ADDRESS)); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(String.format("nic, '%s', gets ip, '%s'", nic, ipAddress)); + } if (Strings.isNullOrEmpty(nic)) { throw new InvalidParameterValueException(String.format("NIC ID: '%s' is invalid for IP address mapping", nic)); } if (Strings.isNullOrEmpty(ipAddress)) { - throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic)); + throw new InvalidParameterValueException(String.format("Empty IP address for NIC ID: %s is invalid", nic)); } if (!Strings.isNullOrEmpty(ipAddress) && !ipAddress.equals("auto") && !NetUtils.isValidIp4(ipAddress)) { throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic)); @@ -239,12 +245,15 @@ public Map getDataDiskToDiskOfferingList() { Map dataDiskToDiskOfferingMap = new HashMap<>(); if (MapUtils.isNotEmpty(dataDiskToDiskOfferingList)) { for (Map entry : (Collection>)dataDiskToDiskOfferingList.values()) { - String nic = entry.get(VmDetailConstants.DISK); + String disk = entry.get(VmDetailConstants.DISK); String offeringUuid = entry.get(VmDetailConstants.DISK_OFFERING); - if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(offeringUuid) || _entityMgr.findByUuid(DiskOffering.class, offeringUuid) == null) { - throw new InvalidParameterValueException(String.format("Disk offering ID: %s for disk ID: %s is invalid", offeringUuid, nic)); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(String.format("disk, '%s', gets offering, '%s'", disk, offeringUuid)); + } + if (Strings.isNullOrEmpty(disk) || Strings.isNullOrEmpty(offeringUuid) || _entityMgr.findByUuid(DiskOffering.class, offeringUuid) == null) { + throw new InvalidParameterValueException(String.format("Disk offering ID: %s for disk ID: %s is invalid", offeringUuid, disk)); } - dataDiskToDiskOfferingMap.put(nic, _entityMgr.findByUuid(DiskOffering.class, offeringUuid).getId()); + dataDiskToDiskOfferingMap.put(disk, _entityMgr.findByUuid(DiskOffering.class, offeringUuid).getId()); } } return dataDiskToDiskOfferingMap; diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index e16bde62b3ff..bf5ddba0014a 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2347,12 +2347,12 @@ private Network createGuestNetwork(final long networkOfferingId, final String na URI secondaryUri = isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null; //don't allow to specify vlan tag used by physical network for dynamic vlan allocation if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) { - throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + throw new InvalidParameterValueException("The VLAN tag to use for new guest network, " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } if (secondaryUri != null && !(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(secondaryUri)).size() > 0) { - throw new InvalidParameterValueException("The VLAN tag " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone " + throw new InvalidParameterValueException("The VLAN tag for isolated PVLAN " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } if (! UuidUtils.validateUUID(vlanId)){ diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 551248352ad6..54e6cf64a83c 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -4021,7 +4021,7 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, // Check if the vlan is being used if (!bypassVlanOverlapCheck && _zoneDao.findVnet(zoneId, physicalNetworkId, BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId))).size() > 0) { - throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + throw new InvalidParameterValueException("The VLAN tag to create; " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } From 33994b8e33e787141434cdb9e7bd5719e4ab9c44 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Mon, 15 Jun 2020 13:57:00 +0000 Subject: [PATCH 029/148] more todos in comment --- .../cloud/hypervisor/vmware/resource/StartCommandExecutor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java index 7d4b5e65d495..8137a66f656a 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java @@ -244,6 +244,9 @@ protected StartAnswer execute(StartCommand cmd) { // FR37 create blank or install as is ???? needs to be replaced with the proceudre at // https://code.vmware.com/docs/5540/vsphere-automation-sdks-programming-guide/doc/GUID-82084C78-49FC-4B7F-BD89-F90D5AA22631.html hyperHost.importVmFromOVF(vmSpec.getTemplateLocation(), vmNameOnVcenter, rootDiskDataStoreDetails.second(), "thin"); + // FR37 importUnmanaged code must be called + // FR37 this must be called before starting + // FR37 existing serviceOffering with the right (minimum) dimensions must exist } else { if (!hyperHost .createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmwareResource.getReservedCpuMHZ(vmSpec), vmSpec.getLimitCpuUse(), (int)(vmSpec.getMaxRam() / Resource.ResourceType.bytesToMiB), vmwareResource.getReservedMemoryMb(vmSpec), guestOsId, From bcad5a271fa12c59c15484395fde82e099c3984b Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 16 Jun 2020 12:07:53 +0530 Subject: [PATCH 030/148] Fix NPE in case of preparing secondarystorage on Host --- .../src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java index 65b1572598fd..dd43158fb20b 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -883,7 +883,9 @@ public ManagedObjectReference mountDatastore(boolean vmfsDatastore, String poolH } } - HypervisorHostHelper.createBaseFolderInDatastore(dsMo, this); + if (dsMo != null) { + HypervisorHostHelper.createBaseFolderInDatastore(dsMo, this); + } if (s_logger.isTraceEnabled()) s_logger.trace("vCenter API trace - mountDatastore() done(successfully)"); From 303ed33933f15d431e1b0374255b369a6c90fe37 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Tue, 16 Jun 2020 09:56:25 +0000 Subject: [PATCH 031/148] rename pbm to vmware-pbm --- deps/install-non-oss.sh | 2 +- plugins/hypervisors/vmware/pom.xml | 2 +- vmware-base/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh index f1c63c4a95f6..5d9150ba1d7c 100755 --- a/deps/install-non-oss.sh +++ b/deps/install-non-oss.sh @@ -41,4 +41,4 @@ mvn install:install-file -Dfile=vim25_65.jar -DgroupId=com.cloud.com.vmwa mvn install:install-file -Dfile=vim25_67.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=6.7 -Dpackaging=jar # From https://my.vmware.com/group/vmware/get-download?downloadGroup=VS-MGMT-SDK65 -mvn install:install-file -Dfile=pbm_65.jar -DgroupId=com.cloud.com.vmware -DartifactId=pbm -Dversion=6.5 -Dpackaging=jar +mvn install:install-file -Dfile=pbm_65.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-pbm -Dversion=6.5 -Dpackaging=jar diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index b0c1ca8cb799..c4dbb1d81b66 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -74,7 +74,7 @@ com.cloud.com.vmware - pbm + vmware-pbm ${cs.vmware.api.version} compile diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml index 925a00314007..ef03d9ada22c 100644 --- a/vmware-base/pom.xml +++ b/vmware-base/pom.xml @@ -77,7 +77,7 @@ com.cloud.com.vmware - pbm + vmware-pbm ${cs.vmware.api.version} compile From 4bee00564cfe2c094070bfd5fc4cf732fd99f4e3 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Tue, 16 Jun 2020 12:57:49 +0000 Subject: [PATCH 032/148] tested in production '{' is really needed --- ui/scripts/ui-custom/instanceWizard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index 4926ae434f9e..2004257b2c64 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -185,7 +185,7 @@ } propertyField = $('') .attr({pattern : '.{' + minLen + ',' + maxLen + '}'}) - .attr(type: fieldType}) + .attr({type: fieldType}) .addClass('name').val(_s(this[fields.value])) } } else { From f2618eff7995f18a45ec9783c5b601d5d754268d Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Tue, 16 Jun 2020 15:01:37 +0000 Subject: [PATCH 033/148] deploy ovf without stripping networks --- .../manager/VmwareStorageManagerImpl.java | 4 +- .../vmware/resource/StartCommandExecutor.java | 2 +- .../resource/VmwareStorageProcessor.java | 4 +- .../cloud/hypervisor/vmware/mo/ClusterMO.java | 4 +- .../cloud/hypervisor/vmware/mo/HostMO.java | 6 +- .../hypervisor/vmware/mo/HttpNfcLeaseMO.java | 7 ++ .../vmware/mo/HypervisorHostHelper.java | 65 ++++++++++++------- .../vmware/mo/VmwareHypervisorHost.java | 2 +- 8 files changed, 59 insertions(+), 35 deletions(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index f17d613125c8..4404bc97cb1a 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -591,7 +591,7 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, } String vmName = templateUuid; - hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin"); + hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin", true); VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName); if (vmMo == null) { @@ -912,7 +912,7 @@ private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, Datasto VirtualMachineMO clonedVm = null; try { - hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin"); + hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin", true); clonedVm = hyperHost.findVmOnHyperHost(newVolumeName); if (clonedVm == null) { throw new Exception("Unable to create container VM for volume creation"); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java index 8137a66f656a..d65ed4c7f75e 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/StartCommandExecutor.java @@ -243,7 +243,7 @@ protected StartAnswer execute(StartCommand cmd) { } else if (installAsIs) { // FR37 create blank or install as is ???? needs to be replaced with the proceudre at // https://code.vmware.com/docs/5540/vsphere-automation-sdks-programming-guide/doc/GUID-82084C78-49FC-4B7F-BD89-F90D5AA22631.html - hyperHost.importVmFromOVF(vmSpec.getTemplateLocation(), vmNameOnVcenter, rootDiskDataStoreDetails.second(), "thin"); + hyperHost.importVmFromOVF(vmSpec.getTemplateLocation(), vmNameOnVcenter, rootDiskDataStoreDetails.second(), "thin", false); // FR37 importUnmanaged code must be called // FR37 this must be called before starting // FR37 existing serviceOffering with the right (minimum) dimensions must exist diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index 0da059116f0e..c120b191f613 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -514,7 +514,7 @@ private Pair copyTemplateFromSecondaryToPrimary(VmwareHy } String vmName = templateUuid; - hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin"); + hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin", true); VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName); VmConfigInfo vAppConfig; @@ -3430,7 +3430,7 @@ private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, Datasto VirtualMachineMO clonedVm = null; try { - hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin"); + hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin", true); clonedVm = hyperHost.findVmOnHyperHost(newVolumeName); if (clonedVm == null) { throw new Exception("Unable to create container VM for volume creation"); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java index b8afdc84cfde..1048abb3460c 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java @@ -385,7 +385,7 @@ public boolean createVm(VirtualMachineConfigSpec vmSpec) throws Exception { } @Override - public void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption) throws Exception { + public void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, boolean stripNeworks) throws Exception { if (s_logger.isTraceEnabled()) s_logger.trace("vCenter API trace - importVmFromOVF(). target MOR: " + _mor.getValue() + ", ovfFilePath: " + ovfFilePath + ", vmName: " + vmName + ", datastore: " + dsMo.getMor().getValue() + ", diskOption: " + diskOption); @@ -396,7 +396,7 @@ public void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, if (s_logger.isTraceEnabled()) s_logger.trace("vCenter API trace - importVmFromOVF(). resource pool: " + morRp.getValue()); - HypervisorHostHelper.importVmFromOVF(this, ovfFilePath, vmName, dsMo, diskOption, morRp, null); + HypervisorHostHelper.importVmFromOVF(this, ovfFilePath, vmName, dsMo, diskOption, morRp, null, stripNeworks); if (s_logger.isTraceEnabled()) s_logger.trace("vCenter API trace - importVmFromOVF() done"); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java index dd43158fb20b..4c2eeb3f6f48 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -766,19 +766,19 @@ public void importVmFromOVF(String ovfFilePath, String vmName, String datastoreN if (dsMo == null) throw new Exception("Invalid datastore name: " + datastoreName); - importVmFromOVF(ovfFilePath, vmName, dsMo, diskOption); + importVmFromOVF(ovfFilePath, vmName, dsMo, diskOption, true); if (s_logger.isTraceEnabled()) s_logger.trace("vCenter API trace - importVmFromOVF() done"); } @Override - public void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption) throws Exception { + public void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, boolean stripNeworks) throws Exception { ManagedObjectReference morRp = getHyperHostOwnerResourcePool(); assert (morRp != null); - HypervisorHostHelper.importVmFromOVF(this, ovfFilePath, vmName, dsMo, diskOption, morRp, _mor); + HypervisorHostHelper.importVmFromOVF(this, ovfFilePath, vmName, dsMo, diskOption, morRp, _mor, stripNeworks); } @Override diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java index 6e4980c1e91c..a8ebf6b2729b 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java @@ -119,6 +119,13 @@ public static long calcTotalBytes(OvfCreateImportSpecResult ovfImportResult) { return totalBytes; } + /** + * should be called {code}String readFileContents(String filePath){code}, does nothing special, like checking if this is indeed adhering to ovf format. + * + * @param ovfFilePath + * @return + * @throws IOException + */ public static String readOvfContent(String ovfFilePath) throws IOException { StringBuffer strContent = new StringBuffer(); BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(ovfFilePath),"UTF-8")); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index b109efde6adb..3e0ab1292fd3 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -470,21 +470,6 @@ public static void updatePortProfile(VmwareContext context, String ethPortProfil } } - /** - * @param ethPortProfileName - * @param namePrefix - * @param hostMo - * @param vlanId - * @param networkRateMbps - * @param networkRateMulticastMbps - * @param timeOutMs - * @param vSwitchType - * @param numPorts - * @param details - * @return - * @throws Exception - */ - public static Pair prepareNetwork(String physicalNetwork, String namePrefix, HostMO hostMo, String vlanId, String secondaryvlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs, VirtualSwitchType vSwitchType, int numPorts, String gateway, boolean configureVServiceInNexus, BroadcastDomainType broadcastDomainType, Map vsmCredentials, Map details) throws Exception { @@ -1706,6 +1691,11 @@ public static String resolveHostNameInUrl(DatacenterMO dcMo, String url) { return url; } + /** + * removes the NetworkSection element from the {ovfString} if it is an ovf xml file + * @param ovfString input string + * @return like the input string but if xml elements by name {NetworkSection} removed + */ public static String removeOVFNetwork(final String ovfString) { if (ovfString == null || ovfString.isEmpty()) { return ovfString; @@ -1735,24 +1725,33 @@ public static String removeOVFNetwork(final String ovfString) { transformer.transform(domSource, result); return writer.toString(); } catch (SAXException | IOException | ParserConfigurationException | TransformerException e) { +// FR37 TODO this warn() should really be an error and the exception should be thrown??? s_logger.warn("Unexpected exception caught while removing network elements from OVF:", e); } return ovfString; } - public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, ManagedObjectReference morRp, - ManagedObjectReference morHost) throws Exception { + /** + * deploys a new VM from a ovf spec. It ignores network, defaults locale to 'US' + * @param host + * @param ovfFilePath + * @param vmName + * @param dsMo + * @param diskOption + * @param morRp + * @param morHost + * @param stripNetworks + * @throws Exception + */ + public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, ManagedObjectReference morRp, + ManagedObjectReference morHost, boolean stripNetworks) throws Exception { assert (morRp != null); - OvfCreateImportSpecParams importSpecParams = new OvfCreateImportSpecParams(); - importSpecParams.setHostSystem(morHost); - importSpecParams.setLocale("US"); - importSpecParams.setEntityName(vmName); - importSpecParams.setDeploymentOption(""); - importSpecParams.setDiskProvisioning(diskOption); // diskOption: thin, thick, etc + OvfCreateImportSpecParams importSpecParams = createOvfCreateImportSpecParamsObject(vmName, diskOption, morHost); + + String ovfDescriptor = readTheOvfDescriptorAsString(ovfFilePath, stripNetworks); - String ovfDescriptor = removeOVFNetwork(HttpNfcLeaseMO.readOvfContent(ovfFilePath)); VmwareContext context = host.getContext(); OvfCreateImportSpecResult ovfImportResult = context.getService().createImportSpec(context.getServiceContent().getOvfManager(), ovfDescriptor, morRp, dsMo.getMor(), importSpecParams); @@ -1849,6 +1848,24 @@ public void action(Long param) { } } + private static OvfCreateImportSpecParams createOvfCreateImportSpecParamsObject(String vmName, String diskOption, ManagedObjectReference morHost) { + OvfCreateImportSpecParams importSpecParams = new OvfCreateImportSpecParams(); + importSpecParams.setHostSystem(morHost); + importSpecParams.setLocale("US"); + importSpecParams.setEntityName(vmName); + importSpecParams.setDeploymentOption(""); + importSpecParams.setDiskProvisioning(diskOption); // diskOption: thin, thick, etc + return importSpecParams; + } + + private static String readTheOvfDescriptorAsString(String ovfFilePath, boolean stripNetworks) throws IOException { + String ovfDescriptor = HttpNfcLeaseMO.readOvfContent(ovfFilePath); + if (stripNetworks) { + ovfDescriptor = removeOVFNetwork(ovfDescriptor); + } + return ovfDescriptor; + } + public static List> readOVF(VmwareHypervisorHost host, String ovfFilePath, DatastoreMO dsMo) throws Exception { List> ovfVolumeInfos = new ArrayList>(); List files = new ArrayList(); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java index a9ceb5d806ec..406157836535 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java @@ -65,7 +65,7 @@ boolean createBlankVm(String vmName, String vmInternalCSName, int cpuCount, int int memoryReserveMB, String guestOsIdentifier, ManagedObjectReference morDs, boolean snapshotDirToParent, Pair controllerInfo, Boolean systemVm) throws Exception; - void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption) throws Exception; + void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, boolean stripNeworks) throws Exception; ObjectContent[] getVmPropertiesOnHyperHost(String[] propertyPaths) throws Exception; From 7162e3435944053be6355ac0197517d4754847d7 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 18 Jun 2020 08:13:17 +0000 Subject: [PATCH 034/148] deploy as is parameter to DB --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../template/RegisterTemplateCmdByAdmin.java | 24 +++- .../api/response/TemplateResponse.java | 8 ++ .../java/com/cloud/storage/VMTemplateVO.java | 17 ++- .../META-INF/db/schema-41400to41500.sql | 111 ++++++++++++++++++ .../storage/image/TemplateServiceImpl.java | 2 +- .../com/cloud/hypervisor/guru/VMwareGuru.java | 2 +- .../api/query/dao/TemplateJoinDaoImpl.java | 1 + .../cloud/api/query/vo/TemplateJoinVO.java | 7 ++ .../com/cloud/storage/TemplateProfile.java | 43 ++----- .../storage/upload/params/UploadParams.java | 1 + .../upload/params/UploadParamsBase.java | 5 + .../template/HypervisorTemplateAdapter.java | 3 + .../com/cloud/template/TemplateAdapter.java | 15 ++- .../cloud/template/TemplateAdapterBase.java | 31 +++-- .../cloud/template/TemplateManagerImpl.java | 3 +- 16 files changed, 213 insertions(+), 61 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 073c94049106..75d64e1e3ae2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -813,6 +813,7 @@ public class ApiConstants { public static final String BOOT_TYPE = "boottype"; public static final String BOOT_MODE = "bootmode"; public static final String BOOT_INTO_SETUP = "bootintosetup"; + public static final String DEPLOY_AS_IS = "deployasis"; public enum BootType { UEFI, BIOS; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java index 28593755c115..a5575eb514a0 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/template/RegisterTemplateCmdByAdmin.java @@ -17,10 +17,32 @@ package org.apache.cloudstack.api.command.admin.template; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.response.TemplateResponse; @APICommand(name = "registerTemplate", description = "Registers an existing template into the CloudStack cloud.", responseObject = TemplateResponse.class, responseView = ResponseView.Full, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class RegisterTemplateCmdByAdmin extends RegisterTemplateCmd {} +public class RegisterTemplateCmdByAdmin extends RegisterTemplateCmd { + + ///////////////////////////////////////////////////// + //////////////// +API parameter ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name= ApiConstants.DEPLOY_AS_IS, + type = CommandType.BOOLEAN, + description = "true if template should not strip and define disks and networks but leave those to the template definition", + since = "4.15" + ) + private Boolean deployAsIs; + + ///////////////////////////////////////////////////// + /////////////////// +Accessor /////////////////////// + ///////////////////////////////////////////////////// + + public Boolean isDeployAsIs() { + return (deployAsIs == null) ? false : deployAsIs; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/TemplateResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/TemplateResponse.java index 81fc2f37b0d6..e8c3b7eda2b6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/TemplateResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/TemplateResponse.java @@ -189,6 +189,10 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements @Param(description = "KVM Only: true if template is directly downloaded to Primary Storage bypassing Secondary Storage") private Boolean directDownload; + @SerializedName(ApiConstants.DEPLOY_AS_IS) + @Param(description = "Vmware Only: true if template is deployed without orchestrating disks and networks but \"as-is\" defined in the template.") + private Boolean deployAsIs; + @SerializedName("parenttemplateid") @Param(description = "if Datadisk template, then id of the root disk template this template belongs to") private String parentTemplateId; @@ -387,6 +391,10 @@ public Boolean getDirectDownload() { return directDownload; } + public void setDeployAsIs(Boolean deployAsIs) { + this.deployAsIs = deployAsIs; + } + public void setParentTemplateId(String parentTemplateId) { this.parentTemplateId = parentTemplateId; } diff --git a/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java b/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java index af04099f9a2a..d109f5a76081 100644 --- a/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java @@ -152,6 +152,9 @@ public class VMTemplateVO implements VirtualMachineTemplate { @Column(name = "parent_template_id") private Long parentTemplateId; + @Column(name = "deploy_as_is") + private boolean deployAsIs; + @Override public String getUniqueName() { return uniqueName; @@ -192,9 +195,9 @@ private VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, uuid = UUID.randomUUID().toString(); } - public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, - boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, - HypervisorType hyperType, String templateTag, Map details, boolean sshKeyEnabled, boolean isDynamicallyScalable, boolean directDownload) { + public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, + HypervisorType hyperType, String templateTag, Map details, boolean sshKeyEnabled, boolean isDynamicallyScalable, boolean directDownload, + boolean deployAsIs) { this(id, name, format, @@ -219,6 +222,7 @@ public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, dynamicallyScalable = isDynamicallyScalable; state = State.Active; this.directDownload = directDownload; + this.deployAsIs = deployAsIs; } public static VMTemplateVO createPreHostIso(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type, @@ -637,4 +641,11 @@ public void setParentTemplateId(Long parentTemplateId) { this.parentTemplateId = parentTemplateId; } + public boolean isDeployAsIs() { + return deployAsIs; + } + + public void setDeployAsIs(boolean deployAsIs) { + this.deployAsIs = deployAsIs; + } } diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index 80cf7e43eb9f..2061ed8c6705 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -47,3 +47,114 @@ CREATE TABLE IF NOT EXISTS `cloud`.`vsphere_storage_policy` ( UNIQUE KEY (`zone_id`, `policy_id`), CONSTRAINT `fk_vsphere_storage_policy__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Add passthrough instruction for appliance deployments +ALTER TABLE `cloud`.`vm_template` ADD COLUMN `deploy_as_is` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'True if the template should be deployed with disks and networks as defined'; + +-- Changes to template_view for both deploying multidisk OVA/vApp as is +DROP VIEW IF EXISTS `cloud`.`template_view`; +CREATE VIEW `cloud`.`template_view` AS + SELECT + `vm_template`.`id` AS `id`, + `vm_template`.`uuid` AS `uuid`, + `vm_template`.`unique_name` AS `unique_name`, + `vm_template`.`name` AS `name`, + `vm_template`.`public` AS `public`, + `vm_template`.`featured` AS `featured`, + `vm_template`.`type` AS `type`, + `vm_template`.`hvm` AS `hvm`, + `vm_template`.`bits` AS `bits`, + `vm_template`.`url` AS `url`, + `vm_template`.`format` AS `format`, + `vm_template`.`created` AS `created`, + `vm_template`.`checksum` AS `checksum`, + `vm_template`.`display_text` AS `display_text`, + `vm_template`.`enable_password` AS `enable_password`, + `vm_template`.`dynamically_scalable` AS `dynamically_scalable`, + `vm_template`.`state` AS `template_state`, + `vm_template`.`guest_os_id` AS `guest_os_id`, + `guest_os`.`uuid` AS `guest_os_uuid`, + `guest_os`.`display_name` AS `guest_os_name`, + `vm_template`.`bootable` AS `bootable`, + `vm_template`.`prepopulate` AS `prepopulate`, + `vm_template`.`cross_zones` AS `cross_zones`, + `vm_template`.`hypervisor_type` AS `hypervisor_type`, + `vm_template`.`extractable` AS `extractable`, + `vm_template`.`template_tag` AS `template_tag`, + `vm_template`.`sort_key` AS `sort_key`, + `vm_template`.`removed` AS `removed`, + `vm_template`.`enable_sshkey` AS `enable_sshkey`, + `parent_template`.`id` AS `parent_template_id`, + `parent_template`.`uuid` AS `parent_template_uuid`, + `source_template`.`id` AS `source_template_id`, + `source_template`.`uuid` AS `source_template_uuid`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `launch_permission`.`account_id` AS `lp_account_id`, + `template_store_ref`.`store_id` AS `store_id`, + `image_store`.`scope` AS `store_scope`, + `template_store_ref`.`state` AS `state`, + `template_store_ref`.`download_state` AS `download_state`, + `template_store_ref`.`download_pct` AS `download_pct`, + `template_store_ref`.`error_str` AS `error_str`, + `template_store_ref`.`size` AS `size`, + `template_store_ref`.physical_size AS `physical_size`, + `template_store_ref`.`destroyed` AS `destroyed`, + `template_store_ref`.`created` AS `created_on_store`, + `vm_template_details`.`name` AS `detail_name`, + `vm_template_details`.`value` AS `detail_value`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + CONCAT(`vm_template`.`id`, + '_', + IFNULL(`data_center`.`id`, 0)) AS `temp_zone_pair`, + `vm_template`.`direct_download` AS `direct_download`, + `vm_template`.`deploy_as_is` AS `deploy_as_is` + FROM + (((((((((((((`vm_template` + JOIN `guest_os` ON ((`guest_os`.`id` = `vm_template`.`guest_os_id`))) + JOIN `account` ON ((`account`.`id` = `vm_template`.`account_id`))) + JOIN `domain` ON ((`domain`.`id` = `account`.`domain_id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `vm_template_details` ON ((`vm_template_details`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `source_template` ON ((`source_template`.`id` = `vm_template`.`source_template_id`))) + LEFT JOIN `template_store_ref` ON (((`template_store_ref`.`template_id` = `vm_template`.`id`) + AND (`template_store_ref`.`store_role` = 'Image') + AND (`template_store_ref`.`destroyed` = 0)))) + LEFT JOIN `vm_template` `parent_template` ON ((`parent_template`.`id` = `vm_template`.`parent_template_id`))) + LEFT JOIN `image_store` ON ((ISNULL(`image_store`.`removed`) + AND (`template_store_ref`.`store_id` IS NOT NULL) + AND (`image_store`.`id` = `template_store_ref`.`store_id`)))) + LEFT JOIN `template_zone_ref` ON (((`template_zone_ref`.`template_id` = `vm_template`.`id`) + AND ISNULL(`template_store_ref`.`store_id`) + AND ISNULL(`template_zone_ref`.`removed`)))) + LEFT JOIN `data_center` ON (((`image_store`.`data_center_id` = `data_center`.`id`) + OR (`template_zone_ref`.`zone_id` = `data_center`.`id`)))) + LEFT JOIN `launch_permission` ON ((`launch_permission`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_template`.`id`) + AND ((`resource_tags`.`resource_type` = 'Template') + OR (`resource_tags`.`resource_type` = 'ISO'))))); + diff --git a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index edf824403e17..5375ede56d91 100644 --- a/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/main/java/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -789,7 +789,7 @@ private boolean createChildDataDiskTemplate(DatadiskTO dataDiskTemplate, VMTempl String templateName = dataDiskTemplate.isIso() ? dataDiskTemplate.getPath().substring(dataDiskTemplate.getPath().lastIndexOf(File.separator) + 1) : template.getName() + suffix + diskCount; VMTemplateVO templateVO = new VMTemplateVO(templateId, templateName, format, false, false, false, ttype, template.getUrl(), template.requiresHvm(), template.getBits(), template.getAccountId(), null, templateName, false, guestOsId, false, template.getHypervisorType(), null, - null, false, false, false); + null, false, false, false, false); if (dataDiskTemplate.isIso()){ templateVO.setUniqueName(templateName); } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java index d45320ee055e..1e59a8657754 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java @@ -599,7 +599,7 @@ private Long getTemplateSize(VirtualMachineMO template, String vmInternalName, M private VMTemplateVO createVMTemplateRecord(String vmInternalName, long guestOsId, long accountId) { Long nextTemplateId = vmTemplateDao.getNextInSequence(Long.class, "id"); VMTemplateVO templateVO = new VMTemplateVO(nextTemplateId, "Imported-from-" + vmInternalName, Storage.ImageFormat.OVA, false, false, false, Storage.TemplateType.USER, null, - false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false); + false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false, false); return vmTemplateDao.persist(templateVO); } diff --git a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 27380ffaa936..272237212a6a 100644 --- a/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -222,6 +222,7 @@ public TemplateResponse newTemplateResponse(ResponseView view, TemplateJoinVO te } templateResponse.setDirectDownload(template.isDirectDownload()); + templateResponse.setDeployAsIs(template.isDeployAsIs()); templateResponse.setRequiresHvm(template.isRequiresHvm()); //set template children disks diff --git a/server/src/main/java/com/cloud/api/query/vo/TemplateJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/TemplateJoinVO.java index 25e3b0b5ff50..91bb76336ccc 100644 --- a/server/src/main/java/com/cloud/api/query/vo/TemplateJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/TemplateJoinVO.java @@ -231,6 +231,9 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont @Column(name = "direct_download") private boolean directDownload; + @Column(name = "deploy_as_is") + private boolean deployAsIs; + public TemplateJoinVO() { } @@ -490,6 +493,10 @@ public boolean isDirectDownload() { return directDownload; } + public boolean isDeployAsIs() { + return deployAsIs; + } + public Object getParentTemplateId() { return parentTemplateId; } diff --git a/server/src/main/java/com/cloud/storage/TemplateProfile.java b/server/src/main/java/com/cloud/storage/TemplateProfile.java index 304b652a589f..9eaafd1a9a68 100644 --- a/server/src/main/java/com/cloud/storage/TemplateProfile.java +++ b/server/src/main/java/com/cloud/storage/TemplateProfile.java @@ -52,6 +52,7 @@ public class TemplateProfile { Boolean isDynamicallyScalable; TemplateType templateType; Boolean directDownload; + Boolean deployAsIs; Long size; public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, @@ -91,11 +92,10 @@ public TemplateProfile(Long userId, VMTemplateVO template, Long zoneId) { else this.zoneIdList = null; } - public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, - Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List zoneId, - - HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details, - Boolean sshKeyEnabled, Long imageStoreId, Boolean isDynamicallyScalable, TemplateType templateType, Boolean directDownload) { + public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, Boolean isPublic, + Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List zoneId, HypervisorType hypervisorType, String accountName, Long domainId, + Long accountId, String chksum, Boolean bootable, String templateTag, Map details, Boolean sshKeyEnabled, Boolean isDynamicallyScalable, TemplateType templateType, + Boolean directDownload, Boolean deployAsIs) { this(templateId, userId, name, @@ -122,6 +122,7 @@ public TemplateProfile(Long templateId, Long userId, String name, String display this.isDynamicallyScalable = isDynamicallyScalable; this.templateType = templateType; this.directDownload = directDownload; + this.deployAsIs = deployAsIs; } public Long getTemplateId() { @@ -168,18 +169,10 @@ public Boolean isPasswordEnabled() { return passwordEnabled; } - public void setPasswordEnabled(Boolean enabled) { - this.passwordEnabled = enabled; - } - public Boolean isRequiresHVM() { return requiresHvm; } - public void setRequiresHVM(Boolean hvm) { - this.requiresHvm = hvm; - } - public String getUrl() { return url; } @@ -224,10 +217,6 @@ public Long getGuestOsId() { return guestOsId; } - public void setGuestOsId(Long id) { - this.guestOsId = id; - } - public List getZoneIdList() { return zoneIdList; } @@ -260,10 +249,6 @@ public String getCheckSum() { return chksum; } - public void setCheckSum(String chksum) { - this.chksum = chksum; - } - public Boolean isBootable() { return this.bootable; } @@ -284,10 +269,6 @@ public String getTemplateTag() { return templateTag; } - public void setTemplateTag(String templateTag) { - this.templateTag = templateTag; - } - public Map getDetails() { return this.details; } @@ -296,10 +277,6 @@ public void setDetails(Map details) { this.details = details; } - public void setSshKeyEnabled(Boolean enabled) { - this.sshKeyEnbaled = enabled; - } - public Boolean isSshKeyEnabled() { return this.sshKeyEnbaled; } @@ -308,10 +285,6 @@ public Boolean IsDynamicallyScalable() { return this.isDynamicallyScalable; } - public void setScalabe(Boolean isDynamicallyScalabe) { - this.isDynamicallyScalable = isDynamicallyScalabe; - } - public TemplateType getTemplateType() { return templateType; } @@ -331,4 +304,8 @@ public Long getSize() { public void setSize(Long size) { this.size = size; } + + public boolean isDeployAsIs() { + return deployAsIs == null ? false : deployAsIs; + } } diff --git a/server/src/main/java/com/cloud/storage/upload/params/UploadParams.java b/server/src/main/java/com/cloud/storage/upload/params/UploadParams.java index 0d42b760b6d9..be8319c9e570 100644 --- a/server/src/main/java/com/cloud/storage/upload/params/UploadParams.java +++ b/server/src/main/java/com/cloud/storage/upload/params/UploadParams.java @@ -46,4 +46,5 @@ public interface UploadParams { boolean isDynamicallyScalable(); boolean isRoutingType(); boolean isDirectDownload(); + boolean isDeployAsIs(); } diff --git a/server/src/main/java/com/cloud/storage/upload/params/UploadParamsBase.java b/server/src/main/java/com/cloud/storage/upload/params/UploadParamsBase.java index 67b04f7b4800..e5bc1a3c906d 100644 --- a/server/src/main/java/com/cloud/storage/upload/params/UploadParamsBase.java +++ b/server/src/main/java/com/cloud/storage/upload/params/UploadParamsBase.java @@ -214,6 +214,11 @@ public boolean isDirectDownload() { return false; } + @Override + public boolean isDeployAsIs() { + return false; + } + void setIso(boolean iso) { isIso = iso; } diff --git a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java index 85c4a77774e8..c42a6b507cc7 100644 --- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java @@ -178,6 +178,9 @@ public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllo @Override public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { + if(s_logger.isTraceEnabled()) { + s_logger.trace(String.format("registering template for %s",cmd.getUrl())); + } TemplateProfile profile = super.prepare(cmd); String url = profile.getUrl(); UriUtils.validateUrl(cmd.getFormat(), url); diff --git a/server/src/main/java/com/cloud/template/TemplateAdapter.java b/server/src/main/java/com/cloud/template/TemplateAdapter.java index c048ceaf1fc2..f4b33c8dddd0 100644 --- a/server/src/main/java/com/cloud/template/TemplateAdapter.java +++ b/server/src/main/java/com/cloud/template/TemplateAdapter.java @@ -72,13 +72,12 @@ public String getName() { boolean delete(TemplateProfile profile); - TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, - Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneId, HypervisorType hypervisorType, String accountName, - Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload) throws ResourceAllocationException; - - TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, - Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneId, HypervisorType hypervisorType, String chksum, - Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable, - TemplateType templateType, boolean directDownload) throws ResourceAllocationException; + TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, + Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload, + boolean deployAsIs) throws ResourceAllocationException; + + TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, + Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneId, HypervisorType hypervisorType, String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable, + TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException; } diff --git a/server/src/main/java/com/cloud/template/TemplateAdapterBase.java b/server/src/main/java/com/cloud/template/TemplateAdapterBase.java index 0e88c147f512..201b628edd29 100644 --- a/server/src/main/java/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/main/java/com/cloud/template/TemplateAdapterBase.java @@ -26,6 +26,7 @@ import com.cloud.storage.upload.params.IsoUploadParams; import com.cloud.storage.upload.params.TemplateUploadParams; import com.cloud.storage.upload.params.UploadParams; +import org.apache.cloudstack.api.command.admin.template.RegisterTemplateCmdByAdmin; import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd; import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd; import org.apache.commons.collections.CollectionUtils; @@ -128,17 +129,17 @@ public boolean stop() { @Override public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, - Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneId, HypervisorType hypervisorType, String accountName, - Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload) throws ResourceAllocationException { - return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId, - hypervisorType, chksum, bootable, null, null, details, false, null, false, TemplateType.USER, directDownload); + Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneId, HypervisorType hypervisorType, String accountName, + Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException { + return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId, hypervisorType, + chksum, bootable, null, null, details, false, null, false, TemplateType.USER, directDownload, deployAsIs); } @Override public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, - Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneIdList, HypervisorType hypervisorType, String chksum, - Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable, - TemplateType templateType, boolean directDownload) throws ResourceAllocationException { + Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List zoneIdList, HypervisorType hypervisorType, String chksum, + Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable, + TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException { //Long accountId = null; // parameters verification @@ -257,7 +258,7 @@ public TemplateProfile prepare(boolean isIso, long userId, String name, String d CallContext.current().setEventDetails("Id: " + id + " name: " + name); return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, imgfmt, guestOSId, zoneIdList, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, - sshkeyEnabled, null, isDynamicallyScalable, templateType, directDownload); + sshkeyEnabled, isDynamicallyScalable, templateType, directDownload, deployAsIs); } @@ -282,10 +283,14 @@ public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocatio throw new InvalidParameterValueException("Hypervisor Type: " + cmd.getHypervisor() + " is invalid. Supported Hypervisor types are " + EnumUtils.listValues(HypervisorType.values()).replace("None, ", "")); } - + boolean deployAsIs = false; + if (cmd instanceof RegisterTemplateCmdByAdmin) { + deployAsIs = ((RegisterTemplateCmdByAdmin)cmd).isDeployAsIs(); + } return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(), cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneId, hypervisorType, cmd.getChecksum(), true, - cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), isRouting ? TemplateType.ROUTING : TemplateType.USER, cmd.isDirectDownload()); + cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), isRouting ? TemplateType.ROUTING : TemplateType.USER, + cmd.isDirectDownload(), deployAsIs); } @@ -316,7 +321,7 @@ private TemplateProfile prepareUploadParamsInternal(UploadParams params) throws params.isExtractable(), params.getFormat(), params.getGuestOSId(), zoneList, params.getHypervisorType(), params.getChecksum(), params.isBootable(), params.getTemplateTag(), owner, params.getDetails(), params.isSshKeyEnabled(), params.getImageStoreUuid(), - params.isDynamicallyScalable(), params.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER, params.isDirectDownload()); + params.isDynamicallyScalable(), params.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER, params.isDirectDownload(), false ); } @Override @@ -358,7 +363,7 @@ public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationExce return prepare(true, CallContext.current().getCallingUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, cmd.isPasswordEnabled(), true, cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), zoneList, HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, - owner, null, false, cmd.getImageStoreUuid(), cmd.isDynamicallyScalable(), TemplateType.USER, cmd.isDirectDownload()); + owner, null, false, cmd.getImageStoreUuid(), cmd.isDynamicallyScalable(), TemplateType.USER, cmd.isDirectDownload(), false); } protected VMTemplateVO persistTemplate(TemplateProfile profile, VirtualMachineTemplate.State initialState) { @@ -367,7 +372,7 @@ protected VMTemplateVO persistTemplate(TemplateProfile profile, VirtualMachineTe new VMTemplateVO(profile.getTemplateId(), profile.getName(), profile.getFormat(), profile.isPublic(), profile.isFeatured(), profile.isExtractable(), profile.getTemplateType(), profile.getUrl(), profile.isRequiresHVM(), profile.getBits(), profile.getAccountId(), profile.getCheckSum(), profile.getDisplayText(), profile.isPasswordEnabled(), profile.getGuestOsId(), profile.isBootable(), profile.getHypervisorType(), - profile.getTemplateTag(), profile.getDetails(), profile.isSshKeyEnabled(), profile.IsDynamicallyScalable(), profile.isDirectDownload()); + profile.getTemplateTag(), profile.getDetails(), profile.isSshKeyEnabled(), profile.IsDynamicallyScalable(), profile.isDirectDownload(), profile.isDeployAsIs() ); template.setState(initialState); if (profile.isDirectDownload()) { diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 48c186eabdc9..b58d892a5946 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -334,6 +334,7 @@ public VirtualMachineTemplate registerTemplate(RegisterTemplateCmd cmd) throws U } if (cmd.isRoutingType() != null) { if (!_accountService.isRootAdmin(account.getId())) { + // FR37 than why is it not in RegisterTemplateCmdByAdmin at least? throw new PermissionDeniedException("Parameter isrouting can only be specified by a Root Admin, permission denied"); } } @@ -1888,7 +1889,7 @@ public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account t } privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable, TemplateType.USER, null, requiresHvmValue, bitsValue, templateOwner.getId(), null, description, - passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails(), sshKeyEnabledValue, isDynamicScalingEnabled, false); + passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails(), sshKeyEnabledValue, isDynamicScalingEnabled, false, false); if (sourceTemplateId != null) { if (s_logger.isDebugEnabled()) { From af42e1cda4138d425a880bc2994e8b5de85b5cf3 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 18 Jun 2020 09:11:08 +0000 Subject: [PATCH 035/148] show deploy as is hack --- ui/scripts/templates.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index 1516286f01a9..49f2c284a871 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -248,6 +248,7 @@ $form.find('.form-item[rel=rootDiskControllerType]').css('display', 'inline-block'); $form.find('.form-item[rel=nicAdapterType]').css('display', 'inline-block'); $form.find('.form-item[rel=keyboardType]').css('display', 'inline-block'); + $form.find('.form-item[rel=deployAsIs]').css('display', 'inline-block'); $form.find('.form-item[rel=xenserverToolsVersion61plus]').hide(); $form.find('.form-item[rel=rootDiskControllerTypeKVM]').hide(); $form.find('.form-item[rel=directdownload]').hide(); @@ -258,6 +259,7 @@ $form.find('.form-item[rel=keyboardType]').hide(); $form.find('.form-item[rel=rootDiskControllerTypeKVM]').hide(); $form.find('.form-item[rel=directdownload]').hide(); + $form.find('.form-item[rel=deployAsIs]').hide(); $form.find('.form-item[rel=requireshvm]').css('display', 'inline-block'); if (isAdmin()) { @@ -268,6 +270,7 @@ $form.find('.form-item[rel=nicAdapterType]').hide(); $form.find('.form-item[rel=keyboardType]').hide(); $form.find('.form-item[rel=xenserverToolsVersion61plus]').hide(); + $form.find('.form-item[rel=deployAsIs]').hide(); $form.find('.form-item[rel=rootDiskControllerTypeKVM]').css('display', 'inline-block'); $('#label_root_disk_controller').prop('selectedIndex', 2); $form.find('.form-item[rel=requireshvm]').css('display', 'inline-block'); @@ -281,6 +284,7 @@ $form.find('.form-item[rel=xenserverToolsVersion61plus]').hide(); $form.find('.form-item[rel=rootDiskControllerTypeKVM]').hide(); $form.find('.form-item[rel=directdownload]').hide(); + $form.find('.form-item[rel=deployAsIs]').hide(); $form.find('.form-item[rel=requireshvm]').css('display', 'inline-block'); } }); @@ -463,6 +467,13 @@ }); } }, + deployAsIs : { + label: 'label.deploy.as.is', + docID: 'helpRegisterTemplateDeployAsIs', + isBoolean: true, + dependsOn: 'hypervisor', + isHidden: true + }, // fields for hypervisor == "VMware" (ends here) format: { @@ -683,6 +694,11 @@ 'details[0].keyboard': args.data.keyboardType }); } + if (args.$form.find('.form-item[rel=deployAsIs]').css("display") != "none" && args.data.deployAsIs != "") { + $.extend(data, { + 'details[0].deployAsIs': args.data.DeployAsIs + }); + } // for hypervisor == VMware (ends here) $.ajax({ @@ -1919,6 +1935,11 @@ isBoolean: true, converter: cloudStack.converters.toBooleanText }, + deployasis: { + label: 'label.deploy.as.is', + isBoolean: true, + converter: cloudStack.converters.toBooleanText + }, isextractable: { label: 'label.extractable.lower', isBoolean: true, @@ -2851,6 +2872,11 @@ docID: 'helpRegisterISOFeatured', isBoolean: true, isHidden: true + }, + deployAsIs : { + label: 'label.deploy.as.is', + docID: 'helpRegisterTemplateDeployAsIs', + isBoolean: true } } }, @@ -2864,7 +2890,8 @@ zoneid: args.data.zone, isextractable: (args.data.isExtractable == "on"), bootable: (args.data.isBootable == "on"), - directdownload: (args.data.directdownload == "on") + directdownload: (args.data.directdownload == "on"), + deployasis: (args.data.deployAsIs == "on") }; if (args.$form.find('.form-item[rel=osTypeId]').css("display") != "none") { @@ -3701,6 +3728,11 @@ isBoolean: true, converter: cloudStack.converters.toBooleanText }, + deployasis: { + label: 'label.deploy.as.is', + isBoolean: true, + converter: cloudStack.converters.toBooleanText + }, size: { label: 'label.size', converter: function(args) { From 0405f0e51c8fa5b44fe28574ba65eb91d655e502 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 19 Jun 2020 13:26:01 +0000 Subject: [PATCH 036/148] extract extension --- core/src/main/java/com/cloud/resource/ServerResource.java | 2 ++ .../storage/resource/NfsSecondaryStorageResource.java | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/cloud/resource/ServerResource.java b/core/src/main/java/com/cloud/resource/ServerResource.java index 9030db72f00b..6aa04ea8d7bc 100644 --- a/core/src/main/java/com/cloud/resource/ServerResource.java +++ b/core/src/main/java/com/cloud/resource/ServerResource.java @@ -31,6 +31,8 @@ * ServerResource is a generic container to execute commands sent */ public interface ServerResource extends Manager { + String ORIGINAL_FILE_EXTENSION = ".orig"; + /** * @return Host.Type type of the computing server we have. */ diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index ab98a812580f..31d8d31b3424 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -53,6 +53,7 @@ import javax.naming.ConfigurationException; +import com.cloud.resource.ServerResource; import org.apache.cloudstack.framework.security.keystore.KeystoreManager; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; @@ -192,6 +193,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S private static final String POST_UPLOAD_KEY_LOCATION = "/etc/cloudstack/agent/ms-psk"; private static final Map updatableConfigData = Maps.newHashMap(); + static { updatableConfigData.put(PUBLIC_KEYS_FILE, METATDATA_DIR); @@ -445,7 +447,7 @@ public Answer execute(GetDatadisksCommand cmd) { Script command = new Script("cp", _timeout, s_logger); command.add(ovfFilePath); - command.add(ovfFilePath + ".orig"); + command.add(ovfFilePath + ServerResource.ORIGINAL_FILE_EXTENSION); String result = command.execute(); if (result != null) { String msg = "Unable to rename original OVF, error msg: " + result; @@ -513,7 +515,7 @@ public Answer execute(CreateDatadiskTemplateCommand cmd) { throw new Exception(msg); } command = new Script("cp", _timeout, s_logger); - command.add(ovfFilePath + ".orig"); + command.add(ovfFilePath + ServerResource.ORIGINAL_FILE_EXTENSION); command.add(newTmplDirAbsolute); result = command.execute(); if (result != null) { @@ -527,7 +529,7 @@ public Answer execute(CreateDatadiskTemplateCommand cmd) { // Create OVF for the disk String newOvfFilePath = newTmplDirAbsolute + File.separator + ovfFilePath.substring(ovfFilePath.lastIndexOf(File.separator) + 1); OVFHelper ovfHelper = new OVFHelper(); - ovfHelper.rewriteOVFFile(ovfFilePath + ".orig", newOvfFilePath, diskName); + ovfHelper.rewriteOVFFile(ovfFilePath + ServerResource.ORIGINAL_FILE_EXTENSION, newOvfFilePath, diskName); postCreatePrivateTemplate(newTmplDirAbsolute, templateId, templateUniqueName, physicalSize, virtualSize); writeMetaOvaForTemplate(newTmplDirAbsolute, ovfFilePath.substring(ovfFilePath.lastIndexOf(File.separator) + 1), diskName, templateUniqueName, physicalSize); From 21f59644965e27edc4756b01ba2ff3365da2b749 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Fri, 19 Jun 2020 13:29:27 +0000 Subject: [PATCH 037/148] path correction --- .../com/cloud/hypervisor/guru/VMwareGuru.java | 2 +- .../hypervisor/guru/VmwareVmImplementer.java | 39 +++++++++++++------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java index 1e59a8657754..410932a42e0c 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java @@ -198,7 +198,7 @@ protected VMwareGuru() { "When set to true this will enable nested virtualization per vm", true, ConfigKey.Scope.Global, null); public static final ConfigKey VmwareImplementAsIsAndReconsiliate = new ConfigKey(Boolean.class, "vmware.dont.orchestrate.but.reconsiliate", "Advanced", "false", - "When set to true OVAs will be deployed as is to then discover disk.]/net/etc", true, ConfigKey.Scope.Global, null); + "When set to true OVAs will be deployed as is to then discover disk/net/etc", true, ConfigKey.Scope.Global, null); @Override public HypervisorType getHypervisorType() { return HypervisorType.VMware; diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java index 63e20804d39c..bb4b760d5f94 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VmwareVmImplementer.java @@ -61,6 +61,7 @@ import org.apache.log4j.Logger; import javax.inject.Inject; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -70,7 +71,7 @@ import java.util.stream.Collectors; class VmwareVmImplementer { - private static final Logger LOG = Logger.getLogger(VmwareVmImplementer.class); + private static final Logger LOGGER = Logger.getLogger(VmwareVmImplementer.class); @Inject DomainRouterDao domainRouterDao; @@ -120,13 +121,27 @@ VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long c // FR37 if VmwareImplementAsIsAndReconsiliate add secondary storage or some other encoding of the OVA file to the start command, // FR37 so the url for the original OVA can be used for deployment if (deployOvaAsIs) { - if (LOG.isTraceEnabled()) { + if (LOGGER.isTraceEnabled()) { // FR37 todo MAYBE add flag for deploy as is TO - // FR37 TODO add url for template in TO - to.setTemplateLocation(vm.getTemplate().getUrl()); + // FR37 TODO add url for template in TO ??? + // FR37 or the OVF file + // FR37 actually pass the location the ovf will found once we get to it ???? + // FR37 secStor/template/tmpl//