Merge branch '4.20'

This commit is contained in:
Daan Hoogland 2025-02-12 16:54:05 +01:00
commit 0dcb8da03a
112 changed files with 2960 additions and 1586 deletions

View File

@ -26,7 +26,7 @@ import com.cloud.utils.SerialVersionUID;
public class StorageAccessException extends RuntimeException { public class StorageAccessException extends RuntimeException {
private static final long serialVersionUID = SerialVersionUID.StorageAccessException; private static final long serialVersionUID = SerialVersionUID.StorageAccessException;
public StorageAccessException(String message) { public StorageAccessException(String message, Exception causer) {
super(message); super(message, causer);
} }
} }

View File

@ -16,14 +16,10 @@
// under the License. // under the License.
package com.cloud.storage; package com.cloud.storage;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class Storage { public class Storage {
public static enum ImageFormat { public static enum ImageFormat {
@ -139,6 +135,21 @@ public class Storage {
ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */ ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */
} }
public enum EncryptionSupport {
/**
* Encryption not supported.
*/
Unsupported,
/**
* Will use hypervisor encryption driver (qemu -> luks)
*/
Hypervisor,
/**
* Storage pool handles encryption and just provides an encrypted volume
*/
Storage
}
/** /**
* StoragePoolTypes carry some details about the format and capabilities of a storage pool. While not necessarily a * StoragePoolTypes carry some details about the format and capabilities of a storage pool. While not necessarily a
* 1:1 with PrimaryDataStoreDriver (and for KVM agent, KVMStoragePool and StorageAdaptor) implementations, it is * 1:1 with PrimaryDataStoreDriver (and for KVM agent, KVMStoragePool and StorageAdaptor) implementations, it is
@ -150,61 +161,37 @@ public class Storage {
* ensure this is available on the agent side as well. This is best done by defining the StoragePoolType in a common * ensure this is available on the agent side as well. This is best done by defining the StoragePoolType in a common
* package available on both management server and agent plugin jars. * package available on both management server and agent plugin jars.
*/ */
public static class StoragePoolType { public static enum StoragePoolType {
private static final Map<String, StoragePoolType> map = new LinkedHashMap<>(); Filesystem(false, true, EncryptionSupport.Hypervisor), // local directory
NetworkFilesystem(true, true, EncryptionSupport.Hypervisor), // NFS
IscsiLUN(true, false, EncryptionSupport.Unsupported), // shared LUN, with a clusterfs overlay
Iscsi(true, false, EncryptionSupport.Unsupported), // for e.g., ZFS Comstar
ISO(false, false, EncryptionSupport.Unsupported), // for iso image
LVM(false, false, EncryptionSupport.Unsupported), // XenServer local LVM SR
CLVM(true, false, EncryptionSupport.Unsupported),
RBD(true, true, EncryptionSupport.Unsupported), // http://libvirt.org/storage.html#StorageBackendRBD
SharedMountPoint(true, true, EncryptionSupport.Hypervisor),
VMFS(true, true, EncryptionSupport.Unsupported), // VMware VMFS storage
PreSetup(true, true, EncryptionSupport.Unsupported), // for XenServer, Storage Pool is set up by customers.
EXT(false, true, EncryptionSupport.Unsupported), // XenServer local EXT SR
OCFS2(true, false, EncryptionSupport.Unsupported),
SMB(true, false, EncryptionSupport.Unsupported),
Gluster(true, false, EncryptionSupport.Unsupported),
PowerFlex(true, true, EncryptionSupport.Hypervisor), // Dell EMC PowerFlex/ScaleIO (formerly VxFlexOS)
ManagedNFS(true, false, EncryptionSupport.Unsupported),
Linstor(true, true, EncryptionSupport.Storage),
DatastoreCluster(true, true, EncryptionSupport.Unsupported), // for VMware, to abstract pool of clusters
StorPool(true, true, EncryptionSupport.Hypervisor),
FiberChannel(true, true, EncryptionSupport.Unsupported); // Fiber Channel Pool for KVM hypervisors is used to find the volume by WWN value (/dev/disk/by-id/wwn-<wwnvalue>)
public static final StoragePoolType Filesystem = new StoragePoolType("Filesystem", false, true, true);
public static final StoragePoolType NetworkFilesystem = new StoragePoolType("NetworkFilesystem", true, true, true);
public static final StoragePoolType IscsiLUN = new StoragePoolType("IscsiLUN", true, false, false);
public static final StoragePoolType Iscsi = new StoragePoolType("Iscsi", true, false, false);
public static final StoragePoolType ISO = new StoragePoolType("ISO", false, false, false);
public static final StoragePoolType LVM = new StoragePoolType("LVM", false, false, false);
public static final StoragePoolType CLVM = new StoragePoolType("CLVM", true, false, false);
public static final StoragePoolType RBD = new StoragePoolType("RBD", true, true, false);
public static final StoragePoolType SharedMountPoint = new StoragePoolType("SharedMountPoint", true, true, true);
public static final StoragePoolType VMFS = new StoragePoolType("VMFS", true, true, false);
public static final StoragePoolType PreSetup = new StoragePoolType("PreSetup", true, true, false);
public static final StoragePoolType EXT = new StoragePoolType("EXT", false, true, false);
public static final StoragePoolType OCFS2 = new StoragePoolType("OCFS2", true, false, false);
public static final StoragePoolType SMB = new StoragePoolType("SMB", true, false, false);
public static final StoragePoolType Gluster = new StoragePoolType("Gluster", true, false, false);
public static final StoragePoolType PowerFlex = new StoragePoolType("PowerFlex", true, true, true);
public static final StoragePoolType ManagedNFS = new StoragePoolType("ManagedNFS", true, false, false);
public static final StoragePoolType Linstor = new StoragePoolType("Linstor", true, true, false);
public static final StoragePoolType DatastoreCluster = new StoragePoolType("DatastoreCluster", true, true, false);
public static final StoragePoolType StorPool = new StoragePoolType("StorPool", true,true,true);
public static final StoragePoolType FiberChannel = new StoragePoolType("FiberChannel", true,true,false);
private final String name;
private final boolean shared; private final boolean shared;
private final boolean overProvisioning; private final boolean overProvisioning;
private final boolean encryption; private final EncryptionSupport encryption;
/** StoragePoolType(boolean shared, boolean overProvisioning, EncryptionSupport encryption) {
* New StoragePoolType, set the name to check with it in Dao (Note: Do not register it into the map of pool types).
* @param name name of the StoragePoolType.
*/
public StoragePoolType(String name) {
this.name = name;
this.shared = false;
this.overProvisioning = false;
this.encryption = false;
}
/**
* Define a new StoragePoolType, and register it into the map of pool types known to the management server.
* @param name Simple unique name of the StoragePoolType.
* @param shared Storage pool is shared/accessible to multiple hypervisors
* @param overProvisioning Storage pool supports overProvisioning
* @param encryption Storage pool supports encrypted volumes
*/
public StoragePoolType(String name, boolean shared, boolean overProvisioning, boolean encryption) {
this.name = name;
this.shared = shared; this.shared = shared;
this.overProvisioning = overProvisioning; this.overProvisioning = overProvisioning;
this.encryption = encryption; this.encryption = encryption;
addStoragePoolType(this);
} }
public boolean isShared() { public boolean isShared() {
@ -216,50 +203,12 @@ public class Storage {
} }
public boolean supportsEncryption() { public boolean supportsEncryption() {
return encryption == EncryptionSupport.Hypervisor || encryption == EncryptionSupport.Storage;
}
public EncryptionSupport encryptionSupportMode() {
return encryption; return encryption;
} }
private static void addStoragePoolType(StoragePoolType storagePoolType) {
map.putIfAbsent(storagePoolType.name, storagePoolType);
}
public static StoragePoolType[] values() {
return map.values().toArray(StoragePoolType[]::new).clone();
}
public static StoragePoolType valueOf(String name) {
if (StringUtils.isBlank(name)) {
return null;
}
StoragePoolType storage = map.get(name);
if (storage == null) {
throw new IllegalArgumentException("StoragePoolType '" + name + "' not found");
}
return storage;
}
@Override
public String toString() {
return name;
}
public String name() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoragePoolType that = (StoragePoolType) o;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
} }
public static List<StoragePoolType> getNonSharedStoragePoolTypes() { public static List<StoragePoolType> getNonSharedStoragePoolTypes() {

View File

@ -63,6 +63,7 @@ public class ApiConstants {
public static final String BASE64_IMAGE = "base64image"; public static final String BASE64_IMAGE = "base64image";
public static final String BGP_PEERS = "bgppeers"; public static final String BGP_PEERS = "bgppeers";
public static final String BGP_PEER_IDS = "bgppeerids"; public static final String BGP_PEER_IDS = "bgppeerids";
public static final String BATCH_SIZE = "batchsize";
public static final String BITS = "bits"; public static final String BITS = "bits";
public static final String BOOTABLE = "bootable"; public static final String BOOTABLE = "bootable";
public static final String BIND_DN = "binddn"; public static final String BIND_DN = "binddn";
@ -455,7 +456,6 @@ public class ApiConstants {
public static final String SENT = "sent"; public static final String SENT = "sent";
public static final String SENT_BYTES = "sentbytes"; public static final String SENT_BYTES = "sentbytes";
public static final String SERIAL = "serial"; public static final String SERIAL = "serial";
public static final String SERVICE_IP = "serviceip";
public static final String SERVICE_OFFERING_ID = "serviceofferingid"; public static final String SERVICE_OFFERING_ID = "serviceofferingid";
public static final String SESSIONKEY = "sessionkey"; public static final String SESSIONKEY = "sessionkey";
public static final String SHOW_CAPACITIES = "showcapacities"; public static final String SHOW_CAPACITIES = "showcapacities";
@ -485,11 +485,12 @@ public class ApiConstants {
public static final String STATE = "state"; public static final String STATE = "state";
public static final String STATS = "stats"; public static final String STATS = "stats";
public static final String STATUS = "status"; public static final String STATUS = "status";
public static final String STORAGE_TYPE = "storagetype";
public static final String STORAGE_POLICY = "storagepolicy";
public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled";
public static final String STORAGE_CAPABILITIES = "storagecapabilities"; public static final String STORAGE_CAPABILITIES = "storagecapabilities";
public static final String STORAGE_CUSTOM_STATS = "storagecustomstats"; public static final String STORAGE_CUSTOM_STATS = "storagecustomstats";
public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled";
public static final String STORAGE_POLICY = "storagepolicy";
public static final String STORAGE_POOL = "storagepool";
public static final String STORAGE_TYPE = "storagetype";
public static final String SUBNET = "subnet"; public static final String SUBNET = "subnet";
public static final String OWNER = "owner"; public static final String OWNER = "owner";
public static final String SWAP_OWNER = "swapowner"; public static final String SWAP_OWNER = "swapowner";
@ -962,7 +963,6 @@ public class ApiConstants {
public static final String AUTOSCALE_VMGROUP_NAME = "autoscalevmgroupname"; public static final String AUTOSCALE_VMGROUP_NAME = "autoscalevmgroupname";
public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername"; public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
public static final String BAREMETAL_RCT_URL = "baremetalrcturl"; public static final String BAREMETAL_RCT_URL = "baremetalrcturl";
public static final String BATCH_SIZE = "batchsize";
public static final String UCS_DN = "ucsdn"; public static final String UCS_DN = "ucsdn";
public static final String GSLB_PROVIDER = "gslbprovider"; public static final String GSLB_PROVIDER = "gslbprovider";
public static final String EXCLUSIVE_GSLB_PROVIDER = "isexclusivegslbprovider"; public static final String EXCLUSIVE_GSLB_PROVIDER = "isexclusivegslbprovider";
@ -1210,6 +1210,7 @@ public class ApiConstants {
"a boolean or a numeric value: if it results in a boolean value, the tariff value will be applied according to the result; if it results in a numeric value, the " + "a boolean or a numeric value: if it results in a boolean value, the tariff value will be applied according to the result; if it results in a numeric value, the " +
"numeric value will be applied; if the result is neither a boolean nor a numeric value, the tariff will not be applied. If the rule is not informed, the tariff " + "numeric value will be applied; if the result is neither a boolean nor a numeric value, the tariff will not be applied. If the rule is not informed, the tariff " +
"value will be applied."; "value will be applied.";
public static final String PARAMETER_DESCRIPTION_START_DATE_POSSIBLE_FORMATS = "The recommended format is \"yyyy-MM-dd'T'HH:mm:ssZ\" (e.g.: \"2023-01-01T12:00:00+0100\"); " + public static final String PARAMETER_DESCRIPTION_START_DATE_POSSIBLE_FORMATS = "The recommended format is \"yyyy-MM-dd'T'HH:mm:ssZ\" (e.g.: \"2023-01-01T12:00:00+0100\"); " +
"however, the following formats are also accepted: \"yyyy-MM-dd HH:mm:ss\" (e.g.: \"2023-01-01 12:00:00\") and \"yyyy-MM-dd\" (e.g.: \"2023-01-01\" - if the time is not " + "however, the following formats are also accepted: \"yyyy-MM-dd HH:mm:ss\" (e.g.: \"2023-01-01 12:00:00\") and \"yyyy-MM-dd\" (e.g.: \"2023-01-01\" - if the time is not " +
"added, it will be interpreted as \"00:00:00\"). If the recommended format is not used, the date will be considered in the server timezone."; "added, it will be interpreted as \"00:00:00\"). If the recommended format is not used, the date will be considered in the server timezone.";
@ -1218,6 +1219,8 @@ public class ApiConstants {
"however, the following formats are also accepted: \"yyyy-MM-dd HH:mm:ss\" (e.g.: \"2023-01-01 12:00:00\") and \"yyyy-MM-dd\" (e.g.: \"2023-01-01\" - if the time is not " + "however, the following formats are also accepted: \"yyyy-MM-dd HH:mm:ss\" (e.g.: \"2023-01-01 12:00:00\") and \"yyyy-MM-dd\" (e.g.: \"2023-01-01\" - if the time is not " +
"added, it will be interpreted as \"23:59:59\"). If the recommended format is not used, the date will be considered in the server timezone."; "added, it will be interpreted as \"23:59:59\"). If the recommended format is not used, the date will be considered in the server timezone.";
public static final String VMWARE_DC = "vmwaredc";
/** /**
* This enum specifies IO Drivers, each option controls specific policies on I/O. * This enum specifies IO Drivers, each option controls specific policies on I/O.
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).

View File

@ -152,7 +152,7 @@ public class HostResponse extends BaseResponseWithAnnotations {
@Deprecated @Deprecated
@SerializedName("memoryallocated") @SerializedName("memoryallocated")
@Param(description = "the amount of the host's memory currently allocated") @Param(description = "the amount of the host's memory currently allocated")
private long memoryAllocated; private Long memoryAllocated;
@SerializedName("memoryallocatedpercentage") @SerializedName("memoryallocatedpercentage")
@Param(description = "the amount of the host's memory currently allocated in percentage") @Param(description = "the amount of the host's memory currently allocated in percentage")
@ -415,7 +415,7 @@ public class HostResponse extends BaseResponseWithAnnotations {
this.memWithOverprovisioning=memWithOverprovisioning; this.memWithOverprovisioning=memWithOverprovisioning;
} }
public void setMemoryAllocated(long memoryAllocated) { public void setMemoryAllocated(Long memoryAllocated) {
this.memoryAllocated = memoryAllocated; this.memoryAllocated = memoryAllocated;
} }
@ -703,8 +703,8 @@ public class HostResponse extends BaseResponseWithAnnotations {
return memoryTotal; return memoryTotal;
} }
public long getMemoryAllocated() { public Long getMemoryAllocated() {
return memoryAllocated; return memoryAllocated == null ? 0 : memoryAllocated;
} }
public void setMemoryAllocatedPercentage(String memoryAllocatedPercentage) { public void setMemoryAllocatedPercentage(String memoryAllocatedPercentage) {

View File

@ -74,9 +74,9 @@ public class ManagementServerResponse extends BaseResponse {
@Param(description = "the running OS kernel version for this Management Server") @Param(description = "the running OS kernel version for this Management Server")
private String kernelVersion; private String kernelVersion;
@SerializedName(ApiConstants.SERVICE_IP) @SerializedName(ApiConstants.IP_ADDRESS)
@Param(description = "the IP Address for this Management Server") @Param(description = "the IP Address for this Management Server")
private String serviceIp; private String ipAddress;
@SerializedName(ApiConstants.PEERS) @SerializedName(ApiConstants.PEERS)
@Param(description = "the Management Server Peers") @Param(description = "the Management Server Peers")
@ -130,8 +130,8 @@ public class ManagementServerResponse extends BaseResponse {
return lastBoot; return lastBoot;
} }
public String getServiceIp() { public String getIpAddress() {
return serviceIp; return ipAddress;
} }
public Long getAgentsCount() { public Long getAgentsCount() {
@ -186,8 +186,8 @@ public class ManagementServerResponse extends BaseResponse {
this.kernelVersion = kernelVersion; this.kernelVersion = kernelVersion;
} }
public void setServiceIp(String serviceIp) { public void setIpAddress(String ipAddress) {
this.serviceIp = serviceIp; this.ipAddress = ipAddress;
} }
public void setAgentsCount(Long agentsCount) { public void setAgentsCount(Long agentsCount) {

View File

@ -0,0 +1,46 @@
//
// 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.agent.api;
/**
* This command will destroy a leftover VM during the expunge process if it wasn't destroyed before.
*
*/
public class CleanupVMCommand extends Command {
String vmName;
boolean executeInSequence;
public CleanupVMCommand(String vmName) {
this(vmName, false);
}
public CleanupVMCommand(String vmName, boolean executeInSequence) {
this.vmName = vmName;
this.executeInSequence = executeInSequence;
}
@Override
public boolean executeInSequence() {
return executeInSequence;
}
public String getVmName() {
return vmName;
}
}

View File

@ -1807,7 +1807,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
try { try {
volService.grantAccess(volFactory.getVolume(newVol.getId()), host, destPool); volService.grantAccess(volFactory.getVolume(newVol.getId()), host, destPool);
} catch (Exception e) { } catch (Exception e) {
throw new StorageAccessException(String.format("Unable to grant access to the volume [%s] on host [%s].", newVolToString, host)); throw new StorageAccessException(String.format("Unable to grant access to the volume [%s] on host [%s].", newVolToString, host), e);
} }
} }
@ -1847,7 +1847,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
try { try {
volService.grantAccess(volFactory.getVolume(volumeId), host, volumeStore); volService.grantAccess(volFactory.getVolume(volumeId), host, volumeStore);
} catch (Exception e) { } catch (Exception e) {
throw new StorageAccessException(String.format("Unable to grant access to volume [%s] on host [%s].", volToString, host)); throw new StorageAccessException(String.format("Unable to grant access to volume [%s] on host [%s].", volToString, host), e);
} }
} }
@ -1928,7 +1928,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
try { try {
volService.grantAccess(volFactory.getVolume(vol.getId()), host, store); volService.grantAccess(volFactory.getVolume(vol.getId()), host, store);
} catch (Exception e) { } catch (Exception e) {
throw new StorageAccessException(String.format("Unable to grant access to volume [%s] on host [%s].", volToString, host)); throw new StorageAccessException(String.format("Unable to grant access to volume [%s] on host [%s].", volToString, host), e);
} }
} else { } else {
grantVolumeAccessToHostIfNeeded(store, vol.getId(), host, volToString); grantVolumeAccessToHostIfNeeded(store, vol.getId(), host, volToString);

View File

@ -20,8 +20,9 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
public interface ClusterDetailsDao extends GenericDao<ClusterDetailsVO, Long> { public interface ClusterDetailsDao extends GenericDao<ClusterDetailsVO, Long>, ResourceDetailsDao<ClusterDetailsVO> {
Map<String, String> findDetails(long clusterId); Map<String, String> findDetails(long clusterId);
void persist(long clusterId, Map<String, String> details); void persist(long clusterId, Map<String, String> details);

View File

@ -28,12 +28,13 @@ import org.apache.cloudstack.framework.config.ScopedConfigStorage;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionLegacy;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
public class ClusterDetailsDaoImpl extends ResourceDetailsDaoBase<ClusterDetailsVO> implements ClusterDetailsDao, ScopedConfigStorage {
public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long> implements ClusterDetailsDao, ScopedConfigStorage {
protected final SearchBuilder<ClusterDetailsVO> ClusterSearch; protected final SearchBuilder<ClusterDetailsVO> ClusterSearch;
protected final SearchBuilder<ClusterDetailsVO> DetailSearch; protected final SearchBuilder<ClusterDetailsVO> DetailSearch;
@ -44,11 +45,11 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long
protected ClusterDetailsDaoImpl() { protected ClusterDetailsDaoImpl() {
ClusterSearch = createSearchBuilder(); ClusterSearch = createSearchBuilder();
ClusterSearch.and("clusterId", ClusterSearch.entity().getClusterId(), SearchCriteria.Op.EQ); ClusterSearch.and("clusterId", ClusterSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
ClusterSearch.done(); ClusterSearch.done();
DetailSearch = createSearchBuilder(); DetailSearch = createSearchBuilder();
DetailSearch.and("clusterId", DetailSearch.entity().getClusterId(), SearchCriteria.Op.EQ); DetailSearch.and("clusterId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ);
DetailSearch.done(); DetailSearch.done();
} }
@ -68,6 +69,11 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long
return detail; return detail;
} }
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new ClusterDetailsVO(resourceId, key, value));
}
@Override @Override
public Map<String, String> findDetails(long clusterId) { public Map<String, String> findDetails(long clusterId) {
SearchCriteria<ClusterDetailsVO> sc = ClusterSearch.create(); SearchCriteria<ClusterDetailsVO> sc = ClusterSearch.create();
@ -91,7 +97,7 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long
return new HashMap<>(); return new HashMap<>();
} }
SearchBuilder<ClusterDetailsVO> sb = createSearchBuilder(); SearchBuilder<ClusterDetailsVO> sb = createSearchBuilder();
sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ); sb.and("clusterId", sb.entity().getResourceId(), SearchCriteria.Op.EQ);
sb.and("name", sb.entity().getName(), SearchCriteria.Op.IN); sb.and("name", sb.entity().getName(), SearchCriteria.Op.IN);
sb.done(); sb.done();
SearchCriteria<ClusterDetailsVO> sc = sb.create(); SearchCriteria<ClusterDetailsVO> sc = sb.create();

View File

@ -23,11 +23,11 @@ import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.ResourceDetail;
@Entity @Entity
@Table(name = "cluster_details") @Table(name = "cluster_details")
public class ClusterDetailsVO implements InternalIdentity { public class ClusterDetailsVO implements ResourceDetail {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@ -35,7 +35,7 @@ public class ClusterDetailsVO implements InternalIdentity {
private long id; private long id;
@Column(name = "cluster_id") @Column(name = "cluster_id")
private long clusterId; private long resourceId;
@Column(name = "name") @Column(name = "name")
private String name; private String name;
@ -47,13 +47,14 @@ public class ClusterDetailsVO implements InternalIdentity {
} }
public ClusterDetailsVO(long clusterId, String name, String value) { public ClusterDetailsVO(long clusterId, String name, String value) {
this.clusterId = clusterId; this.resourceId = clusterId;
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
public long getClusterId() { @Override
return clusterId; public long getResourceId() {
return resourceId;
} }
public String getName() { public String getName() {
@ -64,6 +65,11 @@ public class ClusterDetailsVO implements InternalIdentity {
return value; return value;
} }
@Override
public boolean isDisplay() {
return true;
}
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }

View File

@ -23,18 +23,18 @@ import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.ResourceDetail;
@Entity @Entity
@Table(name = "domain_details") @Table(name = "domain_details")
public class DomainDetailVO implements InternalIdentity { public class DomainDetailVO implements ResourceDetail {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id") @Column(name = "id")
private long id; private long id;
@Column(name = "domain_id") @Column(name = "domain_id")
private long domainId; private long resourceId;
@Column(name = "name") @Column(name = "name")
private String name; private String name;
@ -46,13 +46,14 @@ public class DomainDetailVO implements InternalIdentity {
} }
public DomainDetailVO(long domainId, String name, String value) { public DomainDetailVO(long domainId, String name, String value) {
this.domainId = domainId; this.resourceId = domainId;
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
public long getDomainId() { @Override
return domainId; public long getResourceId() {
return resourceId;
} }
public String getName() { public String getName() {
@ -63,6 +64,11 @@ public class DomainDetailVO implements InternalIdentity {
return value; return value;
} }
@Override
public boolean isDisplay() {
return true;
}
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }

View File

@ -20,8 +20,9 @@ import java.util.Map;
import com.cloud.domain.DomainDetailVO; import com.cloud.domain.DomainDetailVO;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
public interface DomainDetailsDao extends GenericDao<DomainDetailVO, Long> { public interface DomainDetailsDao extends GenericDao<DomainDetailVO, Long>, ResourceDetailsDao<DomainDetailVO> {
Map<String, String> findDetails(long domainId); Map<String, String> findDetails(long domainId);
void persist(long domainId, Map<String, String> details); void persist(long domainId, Map<String, String> details);
@ -31,6 +32,4 @@ public interface DomainDetailsDao extends GenericDao<DomainDetailVO, Long> {
void deleteDetails(long domainId); void deleteDetails(long domainId);
void update(long domainId, Map<String, String> details); void update(long domainId, Map<String, String> details);
String getActualValue(DomainDetailVO domainDetailVO);
} }

View File

@ -25,19 +25,17 @@ import javax.inject.Inject;
import org.apache.cloudstack.framework.config.ConfigKey.Scope; import org.apache.cloudstack.framework.config.ConfigKey.Scope;
import org.apache.cloudstack.framework.config.ScopedConfigStorage; import org.apache.cloudstack.framework.config.ScopedConfigStorage;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
import com.cloud.domain.DomainDetailVO; import com.cloud.domain.DomainDetailVO;
import com.cloud.domain.DomainVO; import com.cloud.domain.DomainVO;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionLegacy;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> implements DomainDetailsDao, ScopedConfigStorage { public class DomainDetailsDaoImpl extends ResourceDetailsDaoBase<DomainDetailVO> implements DomainDetailsDao, ScopedConfigStorage {
protected final SearchBuilder<DomainDetailVO> domainSearch; protected final SearchBuilder<DomainDetailVO> domainSearch;
@Inject @Inject
@ -47,14 +45,14 @@ public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> i
protected DomainDetailsDaoImpl() { protected DomainDetailsDaoImpl() {
domainSearch = createSearchBuilder(); domainSearch = createSearchBuilder();
domainSearch.and("domainId", domainSearch.entity().getDomainId(), Op.EQ); domainSearch.and("domainId", domainSearch.entity().getResourceId(), Op.EQ);
domainSearch.done(); domainSearch.done();
} }
@Override @Override
public Map<String, String> findDetails(long domainId) { public Map<String, String> findDetails(long domainId) {
QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class); QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class);
sc.and(sc.entity().getDomainId(), Op.EQ, domainId); sc.and(sc.entity().getResourceId(), Op.EQ, domainId);
List<DomainDetailVO> results = sc.list(); List<DomainDetailVO> results = sc.list();
Map<String, String> details = new HashMap<String, String>(results.size()); Map<String, String> details = new HashMap<String, String>(results.size());
for (DomainDetailVO r : results) { for (DomainDetailVO r : results) {
@ -80,11 +78,16 @@ public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> i
@Override @Override
public DomainDetailVO findDetail(long domainId, String name) { public DomainDetailVO findDetail(long domainId, String name) {
QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class); QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class);
sc.and(sc.entity().getDomainId(), Op.EQ, domainId); sc.and(sc.entity().getResourceId(), Op.EQ, domainId);
sc.and(sc.entity().getName(), Op.EQ, name); sc.and(sc.entity().getName(), Op.EQ, name);
return sc.find(); return sc.find();
} }
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new DomainDetailVO(resourceId, key, value));
}
@Override @Override
public void deleteDetails(long domainId) { public void deleteDetails(long domainId) {
SearchCriteria<DomainDetailVO> sc = domainSearch.create(); SearchCriteria<DomainDetailVO> sc = domainSearch.create();
@ -129,13 +132,4 @@ public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> i
} }
return vo == null ? null : getActualValue(vo); return vo == null ? null : getActualValue(vo);
} }
@Override
public String getActualValue(DomainDetailVO domainDetailVO) {
ConfigurationVO configurationVO = _configDao.findByName(domainDetailVO.getName());
if (configurationVO != null && configurationVO.isEncrypted()) {
return DBEncryptionUtil.decrypt(domainDetailVO.getValue());
}
return domainDetailVO.getValue();
}
} }

View File

@ -46,7 +46,7 @@ public class StoragePoolDetailsDaoImpl extends ResourceDetailsDaoBase<StoragePoo
@Override @Override
public String getConfigValue(long id, String key) { public String getConfigValue(long id, String key) {
StoragePoolDetailVO vo = findDetail(id, key); StoragePoolDetailVO vo = findDetail(id, key);
return vo == null ? null : vo.getValue(); return vo == null ? null : getActualValue(vo);
} }
@Override @Override

View File

@ -334,7 +334,7 @@ public class SystemVmTemplateRegistration {
} }
}; };
public static boolean validateIfSeeded(String url, String path, String nfsVersion) { public boolean validateIfSeeded(TemplateDataStoreVO templDataStoreVO, String url, String path, String nfsVersion) {
String filePath = null; String filePath = null;
try { try {
filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString(); filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString();
@ -347,6 +347,9 @@ public class SystemVmTemplateRegistration {
String templatePath = filePath + File.separator + partialDirPath; String templatePath = filePath + File.separator + partialDirPath;
File templateProps = new File(templatePath + "/template.properties"); File templateProps = new File(templatePath + "/template.properties");
if (templateProps.exists()) { if (templateProps.exists()) {
Pair<Long, Long> templateSizes = readTemplatePropertiesSizes(templatePath + "/template.properties");
updateSeededTemplateDetails(templDataStoreVO.getTemplateId(), templDataStoreVO.getDataStoreId(),
templateSizes.first(), templateSizes.second());
LOGGER.info("SystemVM template already seeded, skipping registration"); LOGGER.info("SystemVM template already seeded, skipping registration");
return true; return true;
} }
@ -542,6 +545,21 @@ public class SystemVmTemplateRegistration {
} }
} }
public void updateSeededTemplateDetails(long templateId, long storeId, long size, long physicalSize) {
VMTemplateVO template = vmTemplateDao.findById(templateId);
template.setSize(size);
vmTemplateDao.update(template.getId(), template);
TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(storeId, template.getId());
templateDataStoreVO.setSize(size);
templateDataStoreVO.setPhysicalSize(physicalSize);
templateDataStoreVO.setLastUpdated(new Date(DateUtil.currentGMTTime().getTime()));
boolean updated = templateDataStoreDao.update(templateDataStoreVO.getId(), templateDataStoreVO);
if (!updated) {
throw new CloudRuntimeException("Failed to update template_store_ref entry for seeded systemVM template");
}
}
public void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) { public void updateSystemVMEntries(Long templateId, Hypervisor.HypervisorType hypervisorType) {
vmInstanceDao.updateSystemVmTemplateId(templateId, hypervisorType); vmInstanceDao.updateSystemVmTemplateId(templateId, hypervisorType);
} }
@ -555,7 +573,7 @@ public class SystemVmTemplateRegistration {
} }
} }
private static void readTemplateProperties(String path, SystemVMTemplateDetails details) { private static Pair<Long, Long> readTemplatePropertiesSizes(String path) {
File tmpFile = new File(path); File tmpFile = new File(path);
Long size = null; Long size = null;
Long physicalSize = 0L; Long physicalSize = 0L;
@ -574,8 +592,13 @@ public class SystemVmTemplateRegistration {
} catch (IOException ex) { } catch (IOException ex) {
LOGGER.warn("Failed to read from template.properties", ex); LOGGER.warn("Failed to read from template.properties", ex);
} }
details.setSize(size); return new Pair<>(size, physicalSize);
details.setPhysicalSize(physicalSize); }
public static void readTemplateProperties(String path, SystemVMTemplateDetails details) {
Pair<Long, Long> templateSizes = readTemplatePropertiesSizes(path);
details.setSize(templateSizes.first());
details.setPhysicalSize(templateSizes.second());
} }
private void updateTemplateTablesOnFailure(long templateId) { private void updateTemplateTablesOnFailure(long templateId) {
@ -799,7 +822,7 @@ public class SystemVmTemplateRegistration {
TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(storeUrlAndId.second(), templateId); TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(storeUrlAndId.second(), templateId);
if (templateDataStoreVO != null) { if (templateDataStoreVO != null) {
String installPath = templateDataStoreVO.getInstallPath(); String installPath = templateDataStoreVO.getInstallPath();
if (validateIfSeeded(storeUrlAndId.first(), installPath, nfsVersion)) { if (validateIfSeeded(templateDataStoreVO, storeUrlAndId.first(), installPath, nfsVersion)) {
continue; continue;
} }
} }

View File

@ -23,18 +23,18 @@ import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.ResourceDetail;
@Entity @Entity
@Table(name = "account_details") @Table(name = "account_details")
public class AccountDetailVO implements InternalIdentity { public class AccountDetailVO implements ResourceDetail {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id") @Column(name = "id")
private long id; private long id;
@Column(name = "account_id") @Column(name = "account_id")
private long accountId; private long resourceId;
@Column(name = "name") @Column(name = "name")
private String name; private String name;
@ -46,13 +46,14 @@ public class AccountDetailVO implements InternalIdentity {
} }
public AccountDetailVO(long accountId, String name, String value) { public AccountDetailVO(long accountId, String name, String value) {
this.accountId = accountId; this.resourceId = accountId;
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
public long getAccountId() { @Override
return accountId; public long getResourceId() {
return resourceId;
} }
public String getName() { public String getName() {
@ -63,6 +64,11 @@ public class AccountDetailVO implements InternalIdentity {
return value; return value;
} }
@Override
public boolean isDisplay() {
return true;
}
public void setValue(String value) { public void setValue(String value) {
this.value = value; this.value = value;
} }

View File

@ -19,8 +19,9 @@ package com.cloud.user;
import java.util.Map; import java.util.Map;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
public interface AccountDetailsDao extends GenericDao<AccountDetailVO, Long> { public interface AccountDetailsDao extends GenericDao<AccountDetailVO, Long>, ResourceDetailsDao<AccountDetailVO> {
Map<String, String> findDetails(long accountId); Map<String, String> findDetails(long accountId);
void persist(long accountId, Map<String, String> details); void persist(long accountId, Map<String, String> details);
@ -34,6 +35,4 @@ public interface AccountDetailsDao extends GenericDao<AccountDetailVO, Long> {
* they will get created * they will get created
*/ */
void update(long accountId, Map<String, String> details); void update(long accountId, Map<String, String> details);
String getActualValue(AccountDetailVO accountDetailVO);
} }

View File

@ -27,22 +27,20 @@ import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.ConfigKey.Scope; import org.apache.cloudstack.framework.config.ConfigKey.Scope;
import org.apache.cloudstack.framework.config.ScopedConfigStorage; import org.apache.cloudstack.framework.config.ScopedConfigStorage;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
import com.cloud.domain.DomainDetailVO; import com.cloud.domain.DomainDetailVO;
import com.cloud.domain.DomainVO; import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao; import com.cloud.domain.dao.DomainDao;
import com.cloud.domain.dao.DomainDetailsDao; import com.cloud.domain.dao.DomainDetailsDao;
import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.AccountDao;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionLegacy;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long> implements AccountDetailsDao, ScopedConfigStorage { public class AccountDetailsDaoImpl extends ResourceDetailsDaoBase<AccountDetailVO> implements AccountDetailsDao, ScopedConfigStorage {
protected final SearchBuilder<AccountDetailVO> accountSearch; protected final SearchBuilder<AccountDetailVO> accountSearch;
@Inject @Inject
@ -56,16 +54,16 @@ public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long>
protected AccountDetailsDaoImpl() { protected AccountDetailsDaoImpl() {
accountSearch = createSearchBuilder(); accountSearch = createSearchBuilder();
accountSearch.and("accountId", accountSearch.entity().getAccountId(), Op.EQ); accountSearch.and("accountId", accountSearch.entity().getResourceId(), Op.EQ);
accountSearch.done(); accountSearch.done();
} }
@Override @Override
public Map<String, String> findDetails(long accountId) { public Map<String, String> findDetails(long accountId) {
QueryBuilder<AccountDetailVO> sc = QueryBuilder.create(AccountDetailVO.class); QueryBuilder<AccountDetailVO> sc = QueryBuilder.create(AccountDetailVO.class);
sc.and(sc.entity().getAccountId(), Op.EQ, accountId); sc.and(sc.entity().getResourceId(), Op.EQ, accountId);
List<AccountDetailVO> results = sc.list(); List<AccountDetailVO> results = sc.list();
Map<String, String> details = new HashMap<String, String>(results.size()); Map<String, String> details = new HashMap<>(results.size());
for (AccountDetailVO r : results) { for (AccountDetailVO r : results) {
details.put(r.getName(), r.getValue()); details.put(r.getName(), r.getValue());
} }
@ -89,11 +87,16 @@ public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long>
@Override @Override
public AccountDetailVO findDetail(long accountId, String name) { public AccountDetailVO findDetail(long accountId, String name) {
QueryBuilder<AccountDetailVO> sc = QueryBuilder.create(AccountDetailVO.class); QueryBuilder<AccountDetailVO> sc = QueryBuilder.create(AccountDetailVO.class);
sc.and(sc.entity().getAccountId(), Op.EQ, accountId); sc.and(sc.entity().getResourceId(), Op.EQ, accountId);
sc.and(sc.entity().getName(), Op.EQ, name); sc.and(sc.entity().getName(), Op.EQ, name);
return sc.find(); return sc.find();
} }
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new AccountDetailVO(resourceId, key, value));
}
@Override @Override
public void deleteDetails(long accountId) { public void deleteDetails(long accountId) {
SearchCriteria<AccountDetailVO> sc = accountSearch.create(); SearchCriteria<AccountDetailVO> sc = accountSearch.create();
@ -153,13 +156,4 @@ public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long>
} }
return value; return value;
} }
@Override
public String getActualValue(AccountDetailVO accountDetailVO) {
ConfigurationVO configurationVO = _configDao.findByName(accountDetailVO.getName());
if (configurationVO != null && configurationVO.isEncrypted()) {
return DBEncryptionUtil.decrypt(accountDetailVO.getValue());
}
return accountDetailVO.getValue();
}
} }

View File

@ -53,7 +53,7 @@ public interface ResourceDetailsDao<R extends ResourceDetail> extends GenericDao
* Removes all details for the resource specified * Removes all details for the resource specified
* @param resourceId * @param resourceId
*/ */
public void removeDetails(long resourceId); void removeDetails(long resourceId);
/** /**
@ -76,7 +76,7 @@ public interface ResourceDetailsDao<R extends ResourceDetail> extends GenericDao
* @param resourceId * @param resourceId
* @return list of details each implementing ResourceDetail interface * @return list of details each implementing ResourceDetail interface
*/ */
public List<R> listDetails(long resourceId); List<R> listDetails(long resourceId);
/** /**
* List details for resourceId having display field = forDisplay value passed in * List details for resourceId having display field = forDisplay value passed in
@ -84,21 +84,23 @@ public interface ResourceDetailsDao<R extends ResourceDetail> extends GenericDao
* @param forDisplay * @param forDisplay
* @return * @return
*/ */
public List<R> listDetails(long resourceId, boolean forDisplay); List<R> listDetails(long resourceId, boolean forDisplay);
public Map<String, String> listDetailsKeyPairs(long resourceId); Map<String, String> listDetailsKeyPairs(long resourceId);
Map<String, String> listDetailsKeyPairs(long resourceId, List<String> keys); Map<String, String> listDetailsKeyPairs(long resourceId, List<String> keys);
public Map<String, String> listDetailsKeyPairs(long resourceId, boolean forDisplay); Map<String, String> listDetailsKeyPairs(long resourceId, boolean forDisplay);
Map<String, Boolean> listDetailsVisibility(long resourceId); Map<String, Boolean> listDetailsVisibility(long resourceId);
public void saveDetails(List<R> details); void saveDetails(List<R> details);
public void addDetail(long resourceId, String key, String value, boolean display); void addDetail(long resourceId, String key, String value, boolean display);
public List<Long> findResourceIdsByNameAndValueIn(String name, Object[] values); List<Long> findResourceIdsByNameAndValueIn(String name, Object[] values);
public long batchExpungeForResources(List<Long> ids, Long batchSize); long batchExpungeForResources(List<Long> ids, Long batchSize);
String getActualValue(ResourceDetail resourceDetail);
} }

View File

@ -21,9 +21,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.cloudstack.api.ResourceDetail;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
@ -31,7 +31,17 @@ import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionLegacy;
import org.apache.cloudstack.api.ResourceDetail;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
import javax.inject.Inject;
public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends GenericDaoBase<R, Long> implements ResourceDetailsDao<R> { public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends GenericDaoBase<R, Long> implements ResourceDetailsDao<R> {
@Inject
private ConfigurationDao configDao;
private SearchBuilder<R> AllFieldsSearch; private SearchBuilder<R> AllFieldsSearch;
public ResourceDetailsDaoBase() { public ResourceDetailsDaoBase() {
@ -76,8 +86,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("value", value); sc.setParameters("value", value);
} }
List<R> results = search(sc, null); return search(sc, null);
return results;
} }
public Map<String, String> listDetailsKeyPairs(long resourceId) { public Map<String, String> listDetailsKeyPairs(long resourceId) {
@ -85,7 +94,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("resourceId", resourceId); sc.setParameters("resourceId", resourceId);
List<R> results = search(sc, null); List<R> results = search(sc, null);
Map<String, String> details = new HashMap<String, String>(results.size()); Map<String, String> details = new HashMap<>(results.size());
for (R result : results) { for (R result : results) {
details.put(result.getName(), result.getValue()); details.put(result.getName(), result.getValue());
} }
@ -122,8 +131,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
SearchCriteria<R> sc = AllFieldsSearch.create(); SearchCriteria<R> sc = AllFieldsSearch.create();
sc.setParameters("resourceId", resourceId); sc.setParameters("resourceId", resourceId);
List<R> results = search(sc, null); return search(sc, null);
return results;
} }
public void removeDetails(long resourceId) { public void removeDetails(long resourceId) {
@ -185,7 +193,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("display", forDisplay); sc.setParameters("display", forDisplay);
List<R> results = search(sc, null); List<R> results = search(sc, null);
Map<String, String> details = new HashMap<String, String>(results.size()); Map<String, String> details = new HashMap<>(results.size());
for (R result : results) { for (R result : results) {
details.put(result.getName(), result.getValue()); details.put(result.getName(), result.getValue());
} }
@ -197,8 +205,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("resourceId", resourceId); sc.setParameters("resourceId", resourceId);
sc.setParameters("display", forDisplay); sc.setParameters("display", forDisplay);
List<R> results = search(sc, null); return search(sc, null);
return results;
} }
@Override @Override
@ -230,4 +237,13 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("ids", ids.toArray()); sc.setParameters("ids", ids.toArray());
return batchExpunge(sc, batchSize); return batchExpunge(sc, batchSize);
} }
@Override
public String getActualValue(ResourceDetail resourceDetail) {
ConfigurationVO configurationVO = configDao.findByName(resourceDetail.getName());
if (configurationVO != null && configurationVO.isEncrypted()) {
return DBEncryptionUtil.decrypt(resourceDetail.getValue());
}
return resourceDetail.getValue();
}
} }

View File

@ -36,7 +36,6 @@ import com.cloud.utils.db.TransactionLegacy;
@Component @Component
public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreDetailVO> implements ImageStoreDetailsDao, ScopedConfigStorage { public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreDetailVO> implements ImageStoreDetailsDao, ScopedConfigStorage {
protected final SearchBuilder<ImageStoreDetailVO> storeSearch; protected final SearchBuilder<ImageStoreDetailVO> storeSearch;
public ImageStoreDetailsDaoImpl() { public ImageStoreDetailsDaoImpl() {
@ -67,7 +66,7 @@ public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreD
sc.setParameters("store", storeId); sc.setParameters("store", storeId);
List<ImageStoreDetailVO> details = listBy(sc); List<ImageStoreDetailVO> details = listBy(sc);
Map<String, String> detailsMap = new HashMap<String, String>(); Map<String, String> detailsMap = new HashMap<>();
for (ImageStoreDetailVO detail : details) { for (ImageStoreDetailVO detail : details) {
String name = detail.getName(); String name = detail.getName();
String value = detail.getValue(); String value = detail.getValue();
@ -110,9 +109,14 @@ public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreD
return vo == null ? null : vo.getValue(); return vo == null ? null : vo.getValue();
} }
@Override
public String getConfigValue(long id, ConfigKey<?> key) {
ImageStoreDetailVO vo = findDetail(id, key.key());
return vo == null ? null : getActualValue(vo);
}
@Override @Override
public void addDetail(long resourceId, String key, String value, boolean display) { public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new ImageStoreDetailVO(resourceId, key, value, display)); super.addDetail(new ImageStoreDetailVO(resourceId, key, value, display));
} }
} }

View File

@ -755,7 +755,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
if (keyword != null) { if (keyword != null) {
SearchCriteria<StoragePoolVO> ssc = createSearchCriteria(); SearchCriteria<StoragePoolVO> ssc = createSearchCriteria();
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("poolType", SearchCriteria.Op.LIKE, new Storage.StoragePoolType("%" + keyword + "%")); ssc.addOr("poolType", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc); sc.addAnd("name", SearchCriteria.Op.SC, ssc);
} }

View File

@ -24,6 +24,14 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.user', 'api_key_access', 'boolean DE
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.account', 'api_key_access', 'boolean DEFAULT NULL COMMENT "is api key access allowed for the account" '); CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.account', 'api_key_access', 'boolean DEFAULT NULL COMMENT "is api key access allowed for the account" ');
CALL `cloud_usage`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.account', 'api_key_access', 'boolean DEFAULT NULL COMMENT "is api key access allowed for the account" '); CALL `cloud_usage`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.account', 'api_key_access', 'boolean DEFAULT NULL COMMENT "is api key access allowed for the account" ');
-- Create a new group for Usage Server related configurations
INSERT INTO `cloud`.`configuration_group` (`name`, `description`, `precedence`) VALUES ('Usage Server', 'Usage Server related configuration', 9);
UPDATE `cloud`.`configuration_subgroup` set `group_id` = (SELECT `id` FROM `cloud`.`configuration_group` WHERE `name` = 'Usage Server'), `precedence` = 1 WHERE `name`='Usage';
UPDATE `cloud`.`configuration` SET `group_id` = (SELECT `id` FROM `cloud`.`configuration_group` WHERE `name` = 'Usage Server') where `subgroup_id` = (SELECT `id` FROM `cloud`.`configuration_subgroup` WHERE `name` = 'Usage');
-- Update the description to indicate this setting applies only to volume snapshots on running instances
UPDATE `cloud`.`configuration` SET `description`='whether volume snapshot is enabled on running instances on KVM hosts' WHERE `name`='kvm.snapshot.enabled';
-- Modify index for mshost_peer -- Modify index for mshost_peer
DELETE FROM `cloud`.`mshost_peer`; DELETE FROM `cloud`.`mshost_peer`;
CALL `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.mshost_peer','fk_mshost_peer__owner_mshost'); CALL `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.mshost_peer','fk_mshost_peer__owner_mshost');

View File

@ -40,6 +40,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
@ -1534,6 +1535,16 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
verifyFormat(templateInfo.getFormat()); verifyFormat(templateInfo.getFormat());
} }
// this blurb handles the case where the storage system can clone a volume from a template
String canCloneVolumeFromTemplate = templateInfo.getDataStore().getDriver().getCapabilities().get("CAN_CLONE_VOLUME_FROM_TEMPLATE");
if (canCloneVolumeFromTemplate != null && canCloneVolumeFromTemplate.toLowerCase().equals("true")) {
DataStoreDriver driver = templateInfo.getDataStore().getDriver();
driver.createAsync(volumeInfo.getDataStore(), volumeInfo, null);
volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore());
driver.copyAsync(templateInfo, volumeInfo, null);
return;
}
HostVO hostVO = null; HostVO hostVO = null;
final boolean computeClusterSupportsVolumeClone; final boolean computeClusterSupportsVolumeClone;
@ -1641,7 +1652,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
errMsg = "Create volume from template failed: " + ex.getMessage(); errMsg = "Create volume from template failed: " + ex.getMessage();
} }
throw new CloudRuntimeException(errMsg); throw new CloudRuntimeException(errMsg, ex);
} }
finally { finally {
if (copyCmdAnswer == null) { if (copyCmdAnswer == null) {
@ -2634,7 +2645,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
catch (Exception ex) { catch (Exception ex) {
errMsg = ex.getMessage(); errMsg = ex.getMessage();
throw new CloudRuntimeException(errMsg); throw new CloudRuntimeException(errMsg, ex);
} }
finally { finally {
if (copyCmdAnswer == null) { if (copyCmdAnswer == null) {

View File

@ -622,7 +622,7 @@ public class VolumeServiceImpl implements VolumeService {
try { try {
Thread.sleep(sleepTime * 1000); Thread.sleep(sleepTime * 1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.debug("waiting for template download been interrupted: " + e.toString()); logger.debug("waiting for template download been interrupted: " + e);
} }
tries--; tries--;
} }
@ -691,7 +691,6 @@ public class VolumeServiceImpl implements VolumeService {
} }
_tmpltPoolDao.releaseFromLockTable(templatePoolRefId); _tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
} }
return;
} }
protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, ManagedCreateBaseImageContext<VolumeApiResult> context) { protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, ManagedCreateBaseImageContext<VolumeApiResult> context) {
@ -1039,7 +1038,7 @@ public class VolumeServiceImpl implements VolumeService {
try { try {
grantAccess(templateOnPrimary, destHost, destPrimaryDataStore); grantAccess(templateOnPrimary, destHost, destPrimaryDataStore);
} catch (Exception e) { } catch (Exception e) {
throw new StorageAccessException(String.format("Unable to grant access to template: %s on host: %s", templateOnPrimary.getImage(), destHost)); throw new StorageAccessException(String.format("Unable to grant access to template: %s on host: %s", templateOnPrimary.getImage(), destHost), e);
} }
templateOnPrimary.processEvent(Event.CopyingRequested); templateOnPrimary.processEvent(Event.CopyingRequested);
@ -1161,7 +1160,7 @@ public class VolumeServiceImpl implements VolumeService {
try { try {
grantAccess(srcTemplateOnPrimary, destHost, destPrimaryDataStore); grantAccess(srcTemplateOnPrimary, destHost, destPrimaryDataStore);
} catch (Exception e) { } catch (Exception e) {
throw new StorageAccessException(String.format("Unable to grant access to src template: %s on host: %s", srcTemplateOnPrimary, destHost)); throw new StorageAccessException(String.format("Unable to grant access to src template: %s on host: %s", srcTemplateOnPrimary, destHost), e);
} }
_volumeDetailsDao.addDetail(volumeInfo.getId(), volumeDetailKey, String.valueOf(templatePoolRef.getId()), false); _volumeDetailsDao.addDetail(volumeInfo.getId(), volumeDetailKey, String.valueOf(templatePoolRef.getId()), false);
@ -1408,7 +1407,7 @@ public class VolumeServiceImpl implements VolumeService {
try { try {
grantAccess(templateOnPrimary, destHost, destPrimaryDataStore); grantAccess(templateOnPrimary, destHost, destPrimaryDataStore);
} catch (Exception e) { } catch (Exception e) {
throw new StorageAccessException(String.format("Unable to grant access to template: %s on host: %s", templateOnPrimary, destHost)); throw new StorageAccessException(String.format("Unable to grant access to template: %s on host: %s", templateOnPrimary, destHost), e);
} }
templateOnPrimary.processEvent(Event.CopyingRequested); templateOnPrimary.processEvent(Event.CopyingRequested);

View File

@ -39,7 +39,7 @@ import com.cloud.utils.mgmt.ManagementBean;
public class CloudStackExtendedLifeCycle extends AbstractBeanCollector { public class CloudStackExtendedLifeCycle extends AbstractBeanCollector {
Map<Integer, Set<ComponentLifecycle>> sorted = new TreeMap<Integer, Set<ComponentLifecycle>>(); Map<Integer, Set<ComponentLifecycle>> sorted = new TreeMap<>();
public CloudStackExtendedLifeCycle() { public CloudStackExtendedLifeCycle() {
super(); super();
@ -80,13 +80,8 @@ public class CloudStackExtendedLifeCycle extends AbstractBeanCollector {
ManagementBean mbean = (ManagementBean)lifecycle; ManagementBean mbean = (ManagementBean)lifecycle;
try { try {
JmxUtil.registerMBean(mbean); JmxUtil.registerMBean(mbean);
} catch (MalformedObjectNameException e) { } catch (MalformedObjectNameException | InstanceAlreadyExistsException |
logger.warn("Unable to register MBean: " + mbean.getName(), e); MBeanRegistrationException | NotCompliantMBeanException e) {
} catch (InstanceAlreadyExistsException e) {
logger.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (MBeanRegistrationException e) {
logger.warn("Unable to register MBean: " + mbean.getName(), e);
} catch (NotCompliantMBeanException e) {
logger.warn("Unable to register MBean: " + mbean.getName(), e); logger.warn("Unable to register MBean: " + mbean.getName(), e);
} }
logger.info("Registered MBean: " + mbean.getName()); logger.info("Registered MBean: " + mbean.getName());
@ -129,6 +124,7 @@ public class CloudStackExtendedLifeCycle extends AbstractBeanCollector {
throw new CloudRuntimeException(e); throw new CloudRuntimeException(e);
} catch (Exception e) { } catch (Exception e) {
logger.error("Error on configuring bean {} - {}", lifecycle.getName(), e.getMessage(), e); logger.error("Error on configuring bean {} - {}", lifecycle.getName(), e.getMessage(), e);
throw new CloudRuntimeException(e);
} }
} }
}); });
@ -141,7 +137,7 @@ public class CloudStackExtendedLifeCycle extends AbstractBeanCollector {
Set<ComponentLifecycle> set = sorted.get(lifecycle.getRunLevel()); Set<ComponentLifecycle> set = sorted.get(lifecycle.getRunLevel());
if (set == null) { if (set == null) {
set = new HashSet<ComponentLifecycle>(); set = new HashSet<>();
sorted.put(lifecycle.getRunLevel(), set); sorted.put(lifecycle.getRunLevel(), set);
} }
@ -169,12 +165,7 @@ public class CloudStackExtendedLifeCycle extends AbstractBeanCollector {
} }
} }
@Override private interface WithComponentLifeCycle {
public int getPhase() {
return 2000;
}
private static interface WithComponentLifeCycle {
public void with(ComponentLifecycle lifecycle); public void with(ComponentLifecycle lifecycle);
} }
} }

View File

@ -48,7 +48,7 @@ public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, App
* can use this. * can use this.
*/ */
String registryBeanName; String registryBeanName;
Set<Object> beans = new HashSet<Object>(); Set<Object> beans = new HashSet<>();
Class<?> typeClass; Class<?> typeClass;
ApplicationContext applicationContext; ApplicationContext applicationContext;
Set<String> excludes = null; Set<String> excludes = null;
@ -79,7 +79,7 @@ public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, App
protected synchronized void loadExcluded() { protected synchronized void loadExcluded() {
Properties props = applicationContext.getBean("DefaultConfigProperties", Properties.class); Properties props = applicationContext.getBean("DefaultConfigProperties", Properties.class);
excludes = new HashSet<String>(); excludes = new HashSet<>();
for (String exclude : props.getProperty(EXTENSION_EXCLUDE, "").trim().split("\\s*,\\s*")) { for (String exclude : props.getProperty(EXTENSION_EXCLUDE, "").trim().split("\\s*,\\s*")) {
if (StringUtils.hasText(exclude)) { if (StringUtils.hasText(exclude)) {
excludes.add(exclude); excludes.add(exclude);
@ -109,11 +109,16 @@ public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, App
while (iter.hasNext()) { while (iter.hasNext()) {
Object next = iter.next(); Object next = iter.next();
try {
if (registry.register(next)) { if (registry.register(next)) {
logger.debug("Registered " + next); logger.debug("Registered " + next);
} else { } else {
logger.warn("Bean registration failed for " + next.toString());
iter.remove(); iter.remove();
} }
} catch (Throwable e) {
logger.warn("Bean registration attempt resulted in an exception for " + next.toString(), e);
}
} }
} }

View File

@ -47,7 +47,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
private RoleService roleService; private RoleService roleService;
private List<PluggableService> services; private List<PluggableService> services;
private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<RoleType, Set<String>>(); private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<>();
private LazyCache<Long, Account> accountCache; private LazyCache<Long, Account> accountCache;
private LazyCache<Long, Pair<Role, List<RolePermission>>> rolePermissionsCache; private LazyCache<Long, Pair<Role, List<RolePermission>>> rolePermissionsCache;
@ -56,7 +56,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
protected DynamicRoleBasedAPIAccessChecker() { protected DynamicRoleBasedAPIAccessChecker() {
super(); super();
for (RoleType roleType : RoleType.values()) { for (RoleType roleType : RoleType.values()) {
annotationRoleBasedApisMap.put(roleType, new HashSet<String>()); annotationRoleBasedApisMap.put(roleType, new HashSet<>());
} }
} }

View File

@ -3155,7 +3155,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
disk.setLogicalBlockIOSize(pool.getSupportedLogicalBlockSize()); disk.setLogicalBlockIOSize(pool.getSupportedLogicalBlockSize());
disk.setPhysicalBlockIOSize(pool.getSupportedPhysicalBlockSize()); disk.setPhysicalBlockIOSize(pool.getSupportedPhysicalBlockSize());
if (diskBusType == DiskDef.DiskBus.SCSI ) { if (diskBusType == DiskDef.DiskBus.SCSI || diskBusType == DiskDef.DiskBus.VIRTIOBLK) {
disk.setQemuDriver(true); disk.setQemuDriver(true);
disk.setDiscard(DiscardType.UNMAP); disk.setDiscard(DiscardType.UNMAP);
} }
@ -3226,7 +3226,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
disk.setCacheMode(DiskDef.DiskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString().toUpperCase())); disk.setCacheMode(DiskDef.DiskCacheMode.valueOf(volumeObjectTO.getCacheMode().toString().toUpperCase()));
} }
if (volumeObjectTO.requiresEncryption()) { if (volumeObjectTO.requiresEncryption() &&
pool.getType().encryptionSupportMode() == Storage.EncryptionSupport.Hypervisor ) {
String secretUuid = createLibvirtVolumeSecret(conn, volumeObjectTO.getPath(), volumeObjectTO.getPassphrase()); String secretUuid = createLibvirtVolumeSecret(conn, volumeObjectTO.getPath(), volumeObjectTO.getPassphrase());
DiskDef.LibvirtDiskEncryptDetails encryptDetails = new DiskDef.LibvirtDiskEncryptDetails(secretUuid, QemuObject.EncryptFormat.enumValue(volumeObjectTO.getEncryptFormat())); DiskDef.LibvirtDiskEncryptDetails encryptDetails = new DiskDef.LibvirtDiskEncryptDetails(secretUuid, QemuObject.EncryptFormat.enumValue(volumeObjectTO.getEncryptFormat()));
disk.setLibvirtDiskEncryptDetails(encryptDetails); disk.setLibvirtDiskEncryptDetails(encryptDetails);

View File

@ -248,7 +248,7 @@ public class LibvirtVMDef {
guestDef.append("<boot dev='" + bo + "'/>\n"); guestDef.append("<boot dev='" + bo + "'/>\n");
} }
} }
if (!(_arch != null && _arch.equals("s390x"))) { if (_arch == null || ! (_arch.equals("aarch64") || _arch.equals("s390x"))) { // simplification of (as ref.) (!(_arch != null && _arch.equals("s390x")) || (_arch == null || !_arch.equals("aarch64")))
guestDef.append("<smbios mode='sysinfo'/>\n"); guestDef.append("<smbios mode='sysinfo'/>\n");
} }
guestDef.append("</os>\n"); guestDef.append("</os>\n");
@ -680,7 +680,7 @@ public class LibvirtVMDef {
} }
public enum DiskBus { public enum DiskBus {
IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML("uml"), FDC("fdc"), SATA("sata"); IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML("uml"), FDC("fdc"), SATA("sata"), VIRTIOBLK("virtio-blk");
String _bus; String _bus;
DiskBus(String bus) { DiskBus(String bus) {

View File

@ -122,7 +122,10 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
instance.setName(domain.getName()); instance.setName(domain.getName());
instance.setCpuCores((int) LibvirtComputingResource.countDomainRunningVcpus(domain)); instance.setCpuCores((int) LibvirtComputingResource.countDomainRunningVcpus(domain));
if (parser.getCpuTuneDef() != null && instance.getCpuCores() != null) {
instance.setCpuSpeed(parser.getCpuTuneDef().getShares()/instance.getCpuCores()); instance.setCpuSpeed(parser.getCpuTuneDef().getShares()/instance.getCpuCores());
}
if (parser.getCpuModeDef() != null) { if (parser.getCpuModeDef() != null) {
instance.setCpuCoresPerSocket(parser.getCpuModeDef().getCoresPerSocket()); instance.setCpuCoresPerSocket(parser.getCpuModeDef().getCoresPerSocket());

View File

@ -125,6 +125,7 @@ import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper;
import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.JavaStorageLayer;
import com.cloud.storage.MigrationOptions; import com.cloud.storage.MigrationOptions;
import com.cloud.storage.ScopeType; import com.cloud.storage.ScopeType;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageLayer; import com.cloud.storage.StorageLayer;
@ -161,7 +162,7 @@ public class KVMStorageProcessor implements StorageProcessor {
/** /**
* Time interval before rechecking virsh commands * Time interval before rechecking virsh commands
*/ */
private long waitDelayForVirshCommands = 1000l; private final long waitDelayForVirshCommands = 1000L;
public KVMStorageProcessor(final KVMStoragePoolManager storagePoolMgr, final LibvirtComputingResource resource) { public KVMStorageProcessor(final KVMStoragePoolManager storagePoolMgr, final LibvirtComputingResource resource) {
this.storagePoolMgr = storagePoolMgr; this.storagePoolMgr = storagePoolMgr;
@ -258,7 +259,7 @@ public class KVMStorageProcessor implements StorageProcessor {
logger.debug("Copying template to primary storage, template format is " + tmplVol.getFormat() ); logger.debug("Copying template to primary storage, template format is " + tmplVol.getFormat() );
final KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid()); final KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
KVMPhysicalDisk primaryVol = null; KVMPhysicalDisk primaryVol;
if (destData instanceof VolumeObjectTO) { if (destData instanceof VolumeObjectTO) {
final VolumeObjectTO volume = (VolumeObjectTO)destData; final VolumeObjectTO volume = (VolumeObjectTO)destData;
// pass along volume's target size if it's bigger than template's size, for storage types that copy template rather than cloning on deploy // pass along volume's target size if it's bigger than template's size, for storage types that copy template rather than cloning on deploy
@ -277,8 +278,13 @@ public class KVMStorageProcessor implements StorageProcessor {
String path = derivePath(primaryStore, destData, details); String path = derivePath(primaryStore, destData, details);
if (!storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details)) { if (path == null) {
path = destTempl.getUuid();
}
if (path != null && !storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details)) {
logger.warn("Failed to connect physical disk at path: {}, in storage pool [id: {}, name: {}]", path, primaryStore.getUuid(), primaryStore.getName()); logger.warn("Failed to connect physical disk at path: {}, in storage pool [id: {}, name: {}]", path, primaryStore.getUuid(), primaryStore.getName());
return new PrimaryStorageDownloadAnswer("Failed to spool template disk at path: " + path + ", in storage pool id: " + primaryStore.getUuid());
} }
primaryVol = storagePoolMgr.copyPhysicalDisk(tmplVol, path != null ? path : destTempl.getUuid(), primaryPool, cmd.getWaitInMillSeconds()); primaryVol = storagePoolMgr.copyPhysicalDisk(tmplVol, path != null ? path : destTempl.getUuid(), primaryPool, cmd.getWaitInMillSeconds());
@ -336,12 +342,13 @@ public class KVMStorageProcessor implements StorageProcessor {
} }
private String derivePath(PrimaryDataStoreTO primaryStore, DataTO destData, Map<String, String> details) { private String derivePath(PrimaryDataStoreTO primaryStore, DataTO destData, Map<String, String> details) {
String path = null; String path;
if (primaryStore.getPoolType() == StoragePoolType.FiberChannel) { if (primaryStore.getPoolType() == StoragePoolType.FiberChannel) {
path = destData.getPath(); path = destData.getPath();
} else { } else {
path = details != null ? details.get("managedStoreTarget") : null; path = details != null ? details.get("managedStoreTarget") : null;
} }
return path; return path;
} }
@ -390,8 +397,7 @@ public class KVMStorageProcessor implements StorageProcessor {
logger.debug("Using templates disk size of " + toHumanReadableSize(templateVol.getVirtualSize()) + "since size passed was " + toHumanReadableSize(size)); logger.debug("Using templates disk size of " + toHumanReadableSize(templateVol.getVirtualSize()) + "since size passed was " + toHumanReadableSize(size));
} }
final KVMPhysicalDisk primaryVol = storagePoolMgr.copyPhysicalDisk(templateVol, volUuid, primaryPool, timeout); return storagePoolMgr.copyPhysicalDisk(templateVol, volUuid, primaryPool, timeout);
return primaryVol;
} catch (final CloudRuntimeException e) { } catch (final CloudRuntimeException e) {
logger.error("Failed to download template to primary storage", e); logger.error("Failed to download template to primary storage", e);
return null; return null;
@ -410,9 +416,9 @@ public class KVMStorageProcessor implements StorageProcessor {
final DataStoreTO imageStore = template.getDataStore(); final DataStoreTO imageStore = template.getDataStore();
final VolumeObjectTO volume = (VolumeObjectTO)destData; final VolumeObjectTO volume = (VolumeObjectTO)destData;
final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore(); final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
KVMPhysicalDisk BaseVol = null; KVMPhysicalDisk BaseVol;
KVMStoragePool primaryPool = null; KVMStoragePool primaryPool;
KVMPhysicalDisk vol = null; KVMPhysicalDisk vol;
try { try {
primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid()); primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
@ -420,7 +426,7 @@ public class KVMStorageProcessor implements StorageProcessor {
String templatePath = template.getPath(); String templatePath = template.getPath();
if (primaryPool.getType() == StoragePoolType.CLVM) { if (primaryPool.getType() == StoragePoolType.CLVM) {
templatePath = ((NfsTO)imageStore).getUrl() + File.separator + templatePath; templatePath = imageStore.getUrl() + File.separator + templatePath;
vol = templateToPrimaryDownload(templatePath, primaryPool, volume.getUuid(), volume.getSize(), cmd.getWaitInMillSeconds()); vol = templateToPrimaryDownload(templatePath, primaryPool, volume.getUuid(), volume.getSize(), cmd.getWaitInMillSeconds());
} if (storagePoolMgr.supportsPhysicalDiskCopy(primaryPool.getType())) { } if (storagePoolMgr.supportsPhysicalDiskCopy(primaryPool.getType())) {
Map<String, String> details = primaryStore.getDetails(); Map<String, String> details = primaryStore.getDetails();
@ -778,17 +784,21 @@ public class KVMStorageProcessor implements StorageProcessor {
KVMStoragePool secondaryStorage = null; KVMStoragePool secondaryStorage = null;
String path = null;
try { try {
// look for options indicating an overridden path or IQN. Used when snapshots have to be // look for options indicating an overridden path or IQN. Used when snapshots have to be
// temporarily copied on the manaaged storage device before the actual copy to target object // temporarily copied on the manaaged storage device before the actual copy to target object
Map<String, String> details = cmd.getOptions(); Map<String, String> details = cmd.getOptions();
String path = details != null ? details.get(DiskTO.PATH) : null; path = details != null ? details.get(DiskTO.PATH) : null;
if (path == null) { if (path == null) {
path = details != null ? details.get(DiskTO.IQN) : null; path = details != null ? details.get(DiskTO.IQN) : null;
if (path == null) {
path = srcData.getPath();
if (path == null) { if (path == null) {
new CloudRuntimeException("The 'path' or 'iqn' field must be specified."); new CloudRuntimeException("The 'path' or 'iqn' field must be specified.");
} }
} }
}
storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details); storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details);
@ -849,8 +859,6 @@ public class KVMStorageProcessor implements StorageProcessor {
loc.addFormat(info); loc.addFormat(info);
loc.save(); loc.save();
storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path);
TemplateObjectTO newTemplate = new TemplateObjectTO(); TemplateObjectTO newTemplate = new TemplateObjectTO();
newTemplate.setPath(templateFolder + File.separator + templateName + ".qcow2"); newTemplate.setPath(templateFolder + File.separator + templateName + ".qcow2");
@ -870,6 +878,10 @@ public class KVMStorageProcessor implements StorageProcessor {
return new CopyCmdAnswer(ex.toString()); return new CopyCmdAnswer(ex.toString());
} finally { } finally {
if (path != null) {
storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path);
}
if (secondaryStorage != null) { if (secondaryStorage != null) {
secondaryStorage.delete(); secondaryStorage.delete();
} }
@ -1045,7 +1057,9 @@ public class KVMStorageProcessor implements StorageProcessor {
command.add(NAME_OPTION, snapshotName); command.add(NAME_OPTION, snapshotName);
command.add("-p", snapshotDestPath); command.add("-p", snapshotDestPath);
if (isCreatedFromVmSnapshot) {
descName = UUID.randomUUID().toString(); descName = UUID.randomUUID().toString();
}
command.add("-t", descName); command.add("-t", descName);
final String result = command.execute(); final String result = command.execute();
@ -1415,12 +1429,14 @@ public class KVMStorageProcessor implements StorageProcessor {
if (disk.getDeviceType() == DeviceType.DISK) { if (disk.getDeviceType() == DeviceType.DISK) {
if (disk.getBusType() == DiskDef.DiskBus.SCSI) { if (disk.getBusType() == DiskDef.DiskBus.SCSI) {
busT = DiskDef.DiskBus.SCSI; busT = DiskDef.DiskBus.SCSI;
} else if (disk.getBusType() == DiskDef.DiskBus.VIRTIOBLK) {
busT = DiskDef.DiskBus.VIRTIOBLK;
} }
break; break;
} }
} }
diskdef = new DiskDef(); diskdef = new DiskDef();
if (busT == DiskDef.DiskBus.SCSI) { if (busT == DiskDef.DiskBus.SCSI || busT == DiskDef.DiskBus.VIRTIOBLK) {
diskdef.setQemuDriver(true); diskdef.setQemuDriver(true);
diskdef.setDiscard(DiscardType.UNMAP); diskdef.setDiscard(DiscardType.UNMAP);
} }
@ -1459,7 +1475,8 @@ public class KVMStorageProcessor implements StorageProcessor {
} }
} }
if (encryptDetails != null) { if (encryptDetails != null &&
attachingPool.getType().encryptionSupportMode() == Storage.EncryptionSupport.Hypervisor) {
diskdef.setLibvirtDiskEncryptDetails(encryptDetails); diskdef.setLibvirtDiskEncryptDetails(encryptDetails);
} }

View File

@ -162,6 +162,13 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor {
KVMPhysicalDisk disk = new KVMPhysicalDisk(address.getPath(), address.toString(), pool); KVMPhysicalDisk disk = new KVMPhysicalDisk(address.getPath(), address.toString(), pool);
disk.setFormat(QemuImg.PhysicalDiskFormat.RAW); disk.setFormat(QemuImg.PhysicalDiskFormat.RAW);
// validate we have a connection, if not we need to connect first.
if (!isConnected(address.getPath())) {
if (!connectPhysicalDisk(address, pool, null)) {
throw new CloudRuntimeException("Unable to connect to volume " + address.getPath());
}
}
long diskSize = getPhysicalDiskSize(address.getPath()); long diskSize = getPhysicalDiskSize(address.getPath());
disk.setSize(diskSize); disk.setSize(diskSize);
disk.setVirtualSize(diskSize); disk.setVirtualSize(diskSize);
@ -199,6 +206,10 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor {
// we expect WWN values in the volumePath so need to convert it to an actual physical path // we expect WWN values in the volumePath so need to convert it to an actual physical path
AddressInfo address = this.parseAndValidatePath(volumePath); AddressInfo address = this.parseAndValidatePath(volumePath);
return connectPhysicalDisk(address, pool, details);
}
private boolean connectPhysicalDisk(AddressInfo address, KVMStoragePool pool, Map<String, String> details) {
// validate we have a connection id - we can't proceed without that // validate we have a connection id - we can't proceed without that
if (address.getConnectionId() == null) { if (address.getConnectionId() == null) {
LOGGER.error("Unable to connect volume with address [" + address.getPath() + "] of the storage pool: " + pool.getUuid() + " - connection id is not set in provided path"); LOGGER.error("Unable to connect volume with address [" + address.getPath() + "] of the storage pool: " + pool.getUuid() + " - connection id is not set in provided path");
@ -510,6 +521,18 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor {
return false; return false;
} }
boolean isConnected(String path) {
// run a command to test if this is a binary device at this path
Script blockTest = new Script("/bin/test", LOGGER);
blockTest.add("-b", path);
blockTest.execute();
int rc = blockTest.getExitValue();
if (rc == 0) {
return true;
}
return false;
}
long getPhysicalDiskSize(String diskPath) { long getPhysicalDiskSize(String diskPath) {
if (StringUtils.isEmpty(diskPath)) { if (StringUtils.isEmpty(diskPath)) {
return 0; return 0;

View File

@ -6531,4 +6531,14 @@ public class LibvirtComputingResourceTest {
assertEquals(DiskDef.DiscardType.UNMAP, rootDisk.getDiscard()); assertEquals(DiskDef.DiscardType.UNMAP, rootDisk.getDiscard());
} }
} }
@Test
public void testGetDiskModelFromVMDetailVirtioBlk() {
VirtualMachineTO virtualMachineTO = Mockito.mock(VirtualMachineTO.class);
Map<String, String> details = new HashMap<>();
details.put(VmDetailConstants.ROOT_DISK_CONTROLLER, "virtio-blk");
Mockito.when(virtualMachineTO.getDetails()).thenReturn(details);
DiskDef.DiskBus diskBus = libvirtComputingResourceSpy.getDiskModelFromVMDetail(virtualMachineTO);
assertEquals(DiskDef.DiskBus.VIRTIOBLK, diskBus);
}
} }

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import com.cloud.agent.api.CleanupVMCommand;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.NfsTO;
@ -370,6 +371,13 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
return tokens[0] + "@" + vCenterIp; return tokens[0] + "@" + vCenterIp;
} }
@Override public List<Command> finalizeExpunge(VirtualMachine vm) {
List<Command> commands = new ArrayList<Command>();
final CleanupVMCommand cleanupVMCommand = new CleanupVMCommand(vm.getInstanceName(), true);
commands.add(cleanupVMCommand);
return commands;
}
@Override public List<Command> finalizeExpungeNics(VirtualMachine vm, List<NicProfile> nics) { @Override public List<Command> finalizeExpungeNics(VirtualMachine vm, List<NicProfile> nics) {
List<Command> commands = new ArrayList<Command>(); List<Command> commands = new ArrayList<Command>();
List<NicVO> nicVOs = nicDao.listByVmId(vm.getId()); List<NicVO> nicVOs = nicDao.listByVmId(vm.getId());

View File

@ -22,12 +22,15 @@ import com.cloud.dc.VmwareDatacenterVO;
import com.cloud.dc.VsphereStoragePolicy; import com.cloud.dc.VsphereStoragePolicy;
import com.cloud.exception.DiscoveryException; import com.cloud.exception.DiscoveryException;
import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceInUseException;
import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.utils.Pair;
import com.cloud.utils.component.PluggableService; import com.cloud.utils.component.PluggableService;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; 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.ImportVsphereStoragePoliciesCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcHostsCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd;
@ -53,5 +56,7 @@ public interface VmwareDatacenterService extends PluggableService {
List<StoragePool> listVsphereStoragePolicyCompatibleStoragePools(ListVsphereStoragePolicyCompatiblePoolsCmd cmd); List<StoragePool> listVsphereStoragePolicyCompatibleStoragePools(ListVsphereStoragePolicyCompatiblePoolsCmd cmd);
List<UnmanagedInstanceTO> listVMsInDatacenter(ListVmwareDcVmsCmd cmd); List<HostMO> listHostsInDatacenter(ListVmwareDcHostsCmd cmd);
Pair<String, List<UnmanagedInstanceTO>> listVMsInDatacenter(ListVmwareDcVmsCmd cmd);
} }

View File

@ -19,10 +19,12 @@ package com.cloud.hypervisor.vmware.manager;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.rmi.RemoteException; import java.rmi.RemoteException;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
@ -43,10 +45,11 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.persistence.EntityExistsException; import javax.persistence.EntityExistsException;
import com.cloud.hypervisor.vmware.util.VmwareClient;
import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; 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.ImportVsphereStoragePoliciesCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcHostsCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcItems;
import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd;
@ -86,6 +89,7 @@ import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVO;
import com.cloud.dc.ClusterVSMMapVO; import com.cloud.dc.ClusterVSMMapVO;
import com.cloud.dc.DataCenterVO; import com.cloud.dc.DataCenterVO;
import com.cloud.dc.VmwareDatacenter;
import com.cloud.dc.VsphereStoragePolicy; import com.cloud.dc.VsphereStoragePolicy;
import com.cloud.dc.VsphereStoragePolicyVO; import com.cloud.dc.VsphereStoragePolicyVO;
import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.ClusterDao;
@ -111,7 +115,8 @@ import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
import com.cloud.hypervisor.vmware.LegacyZoneVO; import com.cloud.hypervisor.vmware.LegacyZoneVO;
import com.cloud.hypervisor.vmware.VmwareCleanupMaid; import com.cloud.hypervisor.vmware.VmwareCleanupMaid;
import com.cloud.dc.VmwareDatacenter; import com.cloud.hypervisor.vmware.util.VmwareClient;
import com.cloud.hypervisor.vmware.util.VmwareClientException;
import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.dc.VmwareDatacenterVO; import com.cloud.dc.VmwareDatacenterVO;
import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap; import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
@ -168,9 +173,16 @@ import com.cloud.utils.ssh.SshHelper;
import com.cloud.vm.DomainRouterVO; import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.dao.UserVmCloneSettingDao; import com.cloud.vm.dao.UserVmCloneSettingDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
// TODO move these items upstream?
import com.vmware.pbm.PbmProfile; import com.vmware.pbm.PbmProfile;
import com.vmware.vim25.AboutInfo; import com.vmware.vim25.AboutInfo;
import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.InvalidLocaleFaultMsg;
import com.vmware.vim25.InvalidLoginFaultMsg;
import com.vmware.vim25.RuntimeFaultFaultMsg;
import com.vmware.vim25.InvalidPropertyFaultMsg;
import org.jetbrains.annotations.NotNull;
public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable { public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable {
@ -245,11 +257,11 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private StorageLayer _storage; private StorageLayer _storage;
private final String _privateNetworkVSwitchName = "vSwitch0"; private final String _privateNetworkVSwitchName = "vSwitch0";
private int _portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP; private final int _portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP;
private boolean _fullCloneFlag; private boolean _fullCloneFlag;
private boolean _instanceNameFlag; private boolean _instanceNameFlag;
private String _serviceConsoleName; private String _serviceConsoleName;
private String _managemetPortGroupName; private String _managementPortGroupName;
private String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString(); private String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString();
private String _recycleHungWorker = "false"; private String _recycleHungWorker = "false";
private int _additionalPortRangeStart; private int _additionalPortRangeStart;
@ -263,7 +275,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private final Random _rand = new Random(System.currentTimeMillis()); private final Random _rand = new Random(System.currentTimeMillis());
private static ScheduledExecutorService templateCleanupScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-FullyClonedTemplateCheck"));; private static final ScheduledExecutorService templateCleanupScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-FullyClonedTemplateCheck"));
private final VmwareStorageManager _storageMgr; private final VmwareStorageManager _storageMgr;
private final GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op"); private final GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op");
@ -347,9 +359,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
_serviceConsoleName = "Service Console"; _serviceConsoleName = "Service Console";
} }
_managemetPortGroupName = _configDao.getValue(Config.VmwareManagementPortGroup.key()); _managementPortGroupName = _configDao.getValue(Config.VmwareManagementPortGroup.key());
if (_managemetPortGroupName == null) { if (_managementPortGroupName == null) {
_managemetPortGroupName = "Management Network"; _managementPortGroupName = "Management Network";
} }
_defaultSystemVmNicAdapterType = _configDao.getValue(Config.VmwareSystemVmNicDeviceType.key()); _defaultSystemVmNicAdapterType = _configDao.getValue(Config.VmwareSystemVmNicDeviceType.key());
@ -448,7 +460,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
logger.info("Preparing network on host " + hostMo.getContext().toString() + " for " + privateTrafficLabel); logger.info("Preparing network on host " + hostMo.getContext().toString() + " for " + privateTrafficLabel);
VirtualSwitchType vsType = VirtualSwitchType.getType(vSwitchType); VirtualSwitchType vsType = VirtualSwitchType.getType(vSwitchType);
//The management network is probably always going to be a physical network with islation type of vlans, so assume BroadcastDomainType VLAN //The management network is probably always going to be a physical network with isolation type of vlans, so assume BroadcastDomainType VLAN
if (VirtualSwitchType.StandardVirtualSwitch == vsType) { if (VirtualSwitchType.StandardVirtualSwitch == vsType) {
HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false, BroadcastDomainType.Vlan, null, null); HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false, BroadcastDomainType.Vlan, null, null);
} }
@ -457,7 +469,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
AboutInfo about = hostMo.getHostAboutInfo(); AboutInfo about = hostMo.getHostAboutInfo();
if (about != null) { if (about != null) {
String version = about.getApiVersion(); String version = about.getApiVersion();
if (version != null && (version.equals("4.0") || version.equals("4.1")) && _portsPerDvPortGroup < DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x) { if (version != null && (version.equals("4.0") || version.equals("4.1")) ) { // && _portsPerDvPortGroup < DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x)
portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x; portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x;
} }
} }
@ -480,7 +492,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} }
URI uriForHost = new URI(UriUtils.encodeURIComponent(clusterDetails.get("url") + "/" + host.getName())); URI uriForHost = new URI(UriUtils.encodeURIComponent(clusterDetails.get("url") + "/" + host.getName()));
morSrcHost = serviceContext.getHostMorByPath(URLDecoder.decode(uriForHost.getPath(), "UTF-8")); morSrcHost = serviceContext.getHostMorByPath(URLDecoder.decode(uriForHost.getPath(), StandardCharsets.UTF_8));
if (morSrcHost == null) { if (morSrcHost == null) {
return null; return null;
} }
@ -496,19 +508,18 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
throw new CloudRuntimeException("Invalid serviceContext"); throw new CloudRuntimeException("Invalid serviceContext");
} }
ManagedObjectReference mor = serviceContext.getHostMorByPath(hostInventoryPath); ManagedObjectReference mor = serviceContext.getHostMorByPath(hostInventoryPath);
String privateTrafficLabel = null; String privateTrafficLabel;
privateTrafficLabel = serviceContext.getStockObject("privateTrafficLabel"); privateTrafficLabel = serviceContext.getStockObject("privateTrafficLabel");
if (privateTrafficLabel == null) { if (privateTrafficLabel == null) {
privateTrafficLabel = _privateNetworkVSwitchName; privateTrafficLabel = _privateNetworkVSwitchName;
} }
if (mor != null) { if (mor != null) {
List<ManagedObjectReference> returnedHostList = new ArrayList<ManagedObjectReference>(); List<ManagedObjectReference> returnedHostList = new ArrayList<>();
if (mor.getType().equals("ComputeResource")) { if (mor.getType().equals("ComputeResource")) {
List<ManagedObjectReference> hosts = serviceContext.getVimClient().getDynamicProperty(mor, "host"); List<ManagedObjectReference> hosts = serviceContext.getVimClient().getDynamicProperty(mor, "host");
assert (hosts != null && hosts.size() > 0); assert (CollectionUtils.isNullOrEmpty(hosts));
// For ESX host, we need to enable host firewall to allow VNC access // For ESX host, we need to enable host firewall to allow VNC access
HostMO hostMo = new HostMO(serviceContext, hosts.get(0)); HostMO hostMo = new HostMO(serviceContext, hosts.get(0));
@ -519,8 +530,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
List<ManagedObjectReference> hosts = serviceContext.getVimClient().getDynamicProperty(mor, "host"); List<ManagedObjectReference> hosts = serviceContext.getVimClient().getDynamicProperty(mor, "host");
assert (hosts != null); assert (hosts != null);
if (hosts.size() > 0) { if (!hosts.isEmpty()) {
AboutInfo about = (AboutInfo)(serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product")); AboutInfo about = serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product");
String version = about.getApiVersion(); String version = about.getApiVersion();
int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster(HypervisorType.VMware, version); int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster(HypervisorType.VMware, version);
if (hosts.size() > maxHostsPerCluster) { if (hosts.size() > maxHostsPerCluster) {
@ -549,7 +560,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
returnedHostList.add(mor); returnedHostList.add(mor);
return returnedHostList; return returnedHostList;
} else { } else {
logger.error("Unsupport host type " + mor.getType() + ":" + mor.getValue() + " from inventory path: " + hostInventoryPath); logger.error("Unsupport host type {}:{} from inventory path: {}", mor.getType(), mor.getValue(), hostInventoryPath);
return null; return null;
} }
} }
@ -614,13 +625,13 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
public String getManagementPortGroupName() { public String getManagementPortGroupName() {
return _managemetPortGroupName; return _managementPortGroupName;
} }
@Override @Override
public String getManagementPortGroupByHost(HostMO hostMo) throws Exception { public String getManagementPortGroupByHost(HostMO hostMo) throws Exception {
if (hostMo.getHostType() == VmwareHostType.ESXi) { if (hostMo.getHostType() == VmwareHostType.ESXi) {
return _managemetPortGroupName; return _managementPortGroupName;
} }
return _serviceConsoleName; return _serviceConsoleName;
} }
@ -630,7 +641,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
params.put("vmware.create.full.clone", _fullCloneFlag); params.put("vmware.create.full.clone", _fullCloneFlag);
params.put("vm.instancename.flag", _instanceNameFlag); params.put("vm.instancename.flag", _instanceNameFlag);
params.put("service.console.name", _serviceConsoleName); params.put("service.console.name", _serviceConsoleName);
params.put("management.portgroup.name", _managemetPortGroupName); params.put("management.portgroup.name", _managementPortGroupName);
params.put("vmware.root.disk.controller", _rootDiskController); params.put("vmware.root.disk.controller", _rootDiskController);
params.put("vmware.data.disk.controller", _dataDiskController); params.put("vmware.data.disk.controller", _dataDiskController);
params.put("vmware.recycle.hung.wokervm", _recycleHungWorker); params.put("vmware.recycle.hung.wokervm", _recycleHungWorker);
@ -657,23 +668,23 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return false; return false;
} }
String tokens[] = workerTag.split("-"); String[] tokens = workerTag.split("-");
if (tokens.length != 3) { if (tokens.length != 3) {
logger.error("Invalid worker VM tag " + workerTag); logger.error("Invalid worker VM tag " + workerTag);
return false; return false;
} }
long startTick = Long.parseLong(tokens[0]); long startTick = Long.parseLong(tokens[0]);
long msid = Long.parseLong(tokens[1]); long msId = Long.parseLong(tokens[1]);
long runid = Long.parseLong(tokens[2]); long runId = Long.parseLong(tokens[2]);
if (msHostPeerDao.countStateSeenInPeers(msid, runid, ManagementServerHost.State.Down) > 0) { if (msHostPeerDao.countStateSeenInPeers(msId, runId, ManagementServerHost.State.Down) > 0) {
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it"); logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it");
return true; return true;
} }
if (runid != clusterManager.getManagementRunId(msid)) { if (runId != clusterManager.getManagementRunId(msId)) {
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
logger.info("Worker VM's owner management server has changed runid, recycle it"); logger.info("Worker VM's owner management server has changed runid, recycle it");
return true; return true;
@ -710,7 +721,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
File patchFolder = new File(mountPoint + "/systemvm"); File patchFolder = new File(mountPoint + "/systemvm");
if (!patchFolder.exists()) { if (!patchFolder.exists()) {
if (!patchFolder.mkdirs()) { if (!patchFolder.mkdirs()) {
String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString(); String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder;
logger.error(msg); logger.error(msg);
throw new CloudRuntimeException(msg); throw new CloudRuntimeException(msg);
} }
@ -729,7 +740,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} catch (IOException e) { } catch (IOException e) {
logger.error("Unexpected exception ", e); logger.error("Unexpected exception ", e);
String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso; String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso + ", dest location: " + destIso;
logger.error(msg); logger.error(msg);
throw new CloudRuntimeException(msg); throw new CloudRuntimeException(msg);
} }
@ -771,9 +782,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso"); isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso");
} }
assert (isoFile != null);
if (!isoFile.exists()) { if (!isoFile.exists()) {
logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString()); logger.error("Unable to locate systemvm.iso in your setup at " + isoFile);
} }
return isoFile; return isoFile;
} }
@ -788,16 +798,16 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if (keyFile == null || !keyFile.exists()) { if (keyFile == null || !keyFile.exists()) {
keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud"); keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud");
} }
assert (keyFile != null);
if (!keyFile.exists()) { if (!keyFile.exists()) {
logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile.toString()); logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile);
} }
return keyFile; return keyFile;
} }
@Override @Override
public String getMountPoint(String storageUrl, String nfsVersion) { public String getMountPoint(String storageUrl, String nfsVersion) {
String mountPoint = null; String mountPoint;
synchronized (_storageMounts) { synchronized (_storageMounts) {
mountPoint = _storageMounts.get(storageUrl); mountPoint = _storageMounts.get(storageUrl);
if (mountPoint != null) { if (mountPoint != null) {
@ -827,7 +837,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String mountPoint = null; String mountPoint = null;
long mshostId = ManagementServerNode.getManagementServerId(); long mshostId = ManagementServerNode.getManagementServerId();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE)); String mntPt = parent + File.separator + mshostId + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE));
File file = new File(mntPt); File file = new File(mntPt);
if (!file.exists()) { if (!file.exists()) {
if (_storage.mkdir(mntPt)) { if (_storage.mkdir(mntPt)) {
@ -852,10 +862,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
for (String mountPoint : mounts) { for (String mountPoint : mounts) {
logger.info("umount NFS mount from previous session: " + mountPoint); logger.info("umount NFS mount from previous session: " + mountPoint);
String result = null;
Script command = new Script(true, "umount", _timeout, logger); Script command = new Script(true, "umount", _timeout, logger);
command.add(mountPoint); command.add(mountPoint);
result = command.execute(); String result = command.execute();
if (result != null) { if (result != null) {
logger.warn("Unable to umount " + mountPoint + " due to " + result); logger.warn("Unable to umount " + mountPoint + " due to " + result);
} }
@ -873,10 +882,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
for (String mountPoint : _storageMounts.values()) { for (String mountPoint : _storageMounts.values()) {
logger.info("umount NFS mount: " + mountPoint); logger.info("umount NFS mount: " + mountPoint);
String result = null;
Script command = new Script(true, "umount", _timeout, logger); Script command = new Script(true, "umount", _timeout, logger);
command.add(mountPoint); command.add(mountPoint);
result = command.execute(); String result = command.execute();
if (result != null) { if (result != null) {
logger.warn("Unable to umount " + mountPoint + " due to " + result); logger.warn("Unable to umount " + mountPoint + " due to " + result);
} }
@ -894,8 +902,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return null; return null;
} }
Script script = null; Script script;
String result = null; String result;
Script command = new Script(true, "mount", _timeout, logger); Script command = new Script(true, "mount", _timeout, logger);
command.add("-t", "nfs"); command.add("-t", "nfs");
if (nfsVersion != null){ if (nfsVersion != null){
@ -982,11 +990,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
if (cmd instanceof StartupCommand) { if (cmd != null) {
if (host.getHypervisorType() == HypervisorType.VMware) { if (host.getHypervisorType() == HypervisorType.VMware) {
updateClusterNativeHAState(host, cmd); updateClusterNativeHAState(host, cmd);
} else {
return;
} }
} }
} }
@ -1056,16 +1062,16 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
public Pair<Integer, Integer> getAddiionalVncPortRange() { public Pair<Integer, Integer> getAddiionalVncPortRange() {
return new Pair<Integer, Integer>(_additionalPortRangeStart, _additionalPortRangeSize); return new Pair<>(_additionalPortRangeStart, _additionalPortRangeSize);
} }
@Override @Override
public Map<String, String> getNexusVSMCredentialsByClusterId(Long clusterId) { public Map<String, String> getNexusVSMCredentialsByClusterId(Long clusterId) {
CiscoNexusVSMDeviceVO nexusVSM = null; CiscoNexusVSMDeviceVO nexusVSM;
ClusterVSMMapVO vsmMapVO = null; ClusterVSMMapVO vsmMapVO;
vsmMapVO = _vsmMapDao.findByClusterId(clusterId); vsmMapVO = _vsmMapDao.findByClusterId(clusterId);
long vsmId = 0; long vsmId;
if (vsmMapVO != null) { if (vsmMapVO != null) {
vsmId = vsmMapVO.getVsmId(); vsmId = vsmMapVO.getVsmId();
logger.info("vsmId is " + vsmId); logger.info("vsmId is " + vsmId);
@ -1076,7 +1082,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return null; return null;
} }
Map<String, String> nexusVSMCredentials = new HashMap<String, String>(); Map<String, String> nexusVSMCredentials = new HashMap<>();
if (nexusVSM != null) { if (nexusVSM != null) {
nexusVSMCredentials.put("vsmip", nexusVSM.getipaddr()); nexusVSMCredentials.put("vsmip", nexusVSM.getipaddr());
nexusVSMCredentials.put("vsmusername", nexusVSM.getUserName()); nexusVSMCredentials.put("vsmusername", nexusVSM.getUserName());
@ -1103,7 +1109,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
public List<Class<?>> getCommands() { public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<Class<?>>(); List<Class<?>> cmdList = new ArrayList<>();
cmdList.add(AddVmwareDcCmd.class); cmdList.add(AddVmwareDcCmd.class);
cmdList.add(UpdateVmwareDcCmd.class); cmdList.add(UpdateVmwareDcCmd.class);
cmdList.add(RemoveVmwareDcCmd.class); cmdList.add(RemoveVmwareDcCmd.class);
@ -1112,13 +1118,14 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
cmdList.add(ListVsphereStoragePoliciesCmd.class); cmdList.add(ListVsphereStoragePoliciesCmd.class);
cmdList.add(ListVsphereStoragePolicyCompatiblePoolsCmd.class); cmdList.add(ListVsphereStoragePolicyCompatiblePoolsCmd.class);
cmdList.add(ListVmwareDcVmsCmd.class); cmdList.add(ListVmwareDcVmsCmd.class);
cmdList.add(ListVmwareDcHostsCmd.class);
return cmdList; return cmdList;
} }
@Override @Override
@DB @DB
public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws ResourceInUseException { public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws ResourceInUseException {
VmwareDatacenterVO vmwareDc = null; VmwareDatacenterVO vmwareDc;
Long zoneId = cmd.getZoneId(); Long zoneId = cmd.getZoneId();
String userName = cmd.getUsername(); String userName = cmd.getUsername();
String password = cmd.getPassword(); String password = cmd.getPassword();
@ -1174,10 +1181,10 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
checkIfDcIsUsed(vCenterHost, vmwareDcName, zoneId); checkIfDcIsUsed(vCenterHost, vmwareDcName, zoneId);
VmwareContext context = null; VmwareContext context = null;
DatacenterMO dcMo = null; DatacenterMO dcMo;
String dcCustomFieldValue; String dcCustomFieldValue;
boolean addDcCustomFieldDef = false; boolean addDcCustomFieldDef = false;
boolean dcInUse = false; boolean dcInUse;
String guid; String guid;
ManagedObjectReference dcMor; ManagedObjectReference dcMor;
try { try {
@ -1210,7 +1217,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
// Map zone with vmware datacenter // Map zone with vmware datacenter
vmwareDcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDc.getId()); vmwareDcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDc.getId());
vmwareDcZoneMap = vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap); vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap);
// Set custom field for this DC // Set custom field for this DC
if (addDcCustomFieldDef) { if (addDcCustomFieldDef) {
@ -1230,7 +1237,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if (context != null) { if (context != null) {
context.close(); context.close();
} }
context = null;
} }
importVsphereStoragePoliciesInternal(zoneId, vmwareDc.getId()); importVsphereStoragePoliciesInternal(zoneId, vmwareDc.getId());
return vmwareDc; return vmwareDc;
@ -1255,9 +1261,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
* Check if DC is already part of zone * Check if DC is already part of zone
* In that case vmware_data_center table should have the DC and a dc zone mapping should exist * In that case vmware_data_center table should have the DC and a dc zone mapping should exist
* *
* @param vCenterHost * @param vCenterHost the vcenter appliance hostname
* @param vmwareDcName * @param vmwareDcName the name of the vmware DC
* @param zoneId * @param zoneId zone that the DC should be connected to
* @throws ResourceInUseException if the DC can not be used. * @throws ResourceInUseException if the DC can not be used.
*/ */
private void checkIfDcIsUsed(String vCenterHost, String vmwareDcName, Long zoneId) throws ResourceInUseException { private void checkIfDcIsUsed(String vCenterHost, String vmwareDcName, Long zoneId) throws ResourceInUseException {
@ -1265,7 +1271,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
vmwareDc = vmwareDcDao.getVmwareDatacenterByGuid(vmwareDcName + "@" + vCenterHost); vmwareDc = vmwareDcDao.getVmwareDatacenterByGuid(vmwareDcName + "@" + vCenterHost);
if (vmwareDc != null) { if (vmwareDc != null) {
VmwareDatacenterZoneMapVO mapping = vmwareDatacenterZoneMapDao.findByVmwareDcId(vmwareDc.getId()); VmwareDatacenterZoneMapVO mapping = vmwareDatacenterZoneMapDao.findByVmwareDcId(vmwareDc.getId());
if (mapping != null && Long.compare(zoneId, mapping.getZoneId()) == 0) { if (mapping != null && zoneId == mapping.getZoneId()) {
throw new ResourceInUseException(String.format("This DC (%s) is already part of other CloudStack zone (%d). Cannot add this DC to more zones.", vmwareDc.getUuid(), zoneId)); throw new ResourceInUseException(String.format("This DC (%s) is already part of other CloudStack zone (%d). Cannot add this DC to more zones.", vmwareDc.getUuid(), zoneId));
} }
} }
@ -1274,7 +1280,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "updating VMware datacenter") @ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "updating VMware datacenter")
public VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd cmd) { public VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd cmd) {
final Long zoneId = cmd.getZoneId(); final long zoneId = cmd.getZoneId();
final String userName = cmd.getUsername(); final String userName = cmd.getUsername();
final String password = cmd.getPassword(); final String password = cmd.getPassword();
final String vCenterHost = cmd.getVcenter(); final String vCenterHost = cmd.getVcenter();
@ -1302,7 +1308,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} }
vmwareDc.setGuid(String.format("%s@%s", vmwareDc.getVmwareDatacenterName(), vmwareDc.getVcenterHost())); vmwareDc.setGuid(String.format("%s@%s", vmwareDc.getVmwareDatacenterName(), vmwareDc.getVcenterHost()));
return Transaction.execute(new TransactionCallback<VmwareDatacenter>() { return Transaction.execute(new TransactionCallback<>() {
@Override @Override
public VmwareDatacenter doInTransaction(TransactionStatus status) { public VmwareDatacenter doInTransaction(TransactionStatus status) {
if (vmwareDcDao.update(vmwareDc.getId(), vmwareDc)) { if (vmwareDcDao.update(vmwareDc.getId(), vmwareDc)) {
@ -1351,7 +1357,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String vCenterHost; String vCenterHost;
String userName; String userName;
String password; String password;
DatacenterMO dcMo = null; DatacenterMO dcMo;
final VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId); final VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId);
// Check if zone is associated with VMware DC // Check if zone is associated with VMware DC
if (vmwareDcZoneMap == null) { if (vmwareDcZoneMap == null) {
@ -1388,11 +1394,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
throw new DiscoveryException(msg); throw new DiscoveryException(msg);
} }
assert (dcMo != null);
// Reset custom field property cloud.zone over this DC // Reset custom field property cloud.zone over this DC
dcMo.setCustomFieldValue(CustomFieldConstants.CLOUD_ZONE, "false"); dcMo.setCustomFieldValue(CustomFieldConstants.CLOUD_ZONE, "false");
logger.info("Sucessfully reset custom field property cloud.zone over DC " + vmwareDcName); logger.info("Sucessfully reset custom field property cloud.zone over DC {}", vmwareDcName);
} catch (Exception e) { } catch (Exception e) {
String msg = "Unable to reset custom field property cloud.zone over DC " + vmwareDcName + " due to : " + VmwareHelper.getExceptionMessage(e); String msg = "Unable to reset custom field property cloud.zone over DC " + vmwareDcName + " due to : " + VmwareHelper.getExceptionMessage(e);
logger.error(msg); logger.error(msg);
@ -1401,7 +1405,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if (context != null) { if (context != null) {
context.close(); context.close();
} }
context = null;
} }
return true; return true;
} }
@ -1422,7 +1425,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private void validateZoneWithResources(Long zoneId, String errStr) throws ResourceInUseException { private void validateZoneWithResources(Long zoneId, String errStr) throws ResourceInUseException {
// Check if zone has resources? - For now look for clusters // Check if zone has resources? - For now look for clusters
List<ClusterVO> clusters = clusterDao.listByZoneId(zoneId); List<ClusterVO> clusters = clusterDao.listByZoneId(zoneId);
if (clusters != null && clusters.size() > 0) { if (!CollectionUtils.isNullOrEmpty(clusters)) {
// Look for VMware hypervisor. // Look for VMware hypervisor.
for (ClusterVO cluster : clusters) { for (ClusterVO cluster : clusters) {
if (cluster.getHypervisorType().equals(HypervisorType.VMware)) { if (cluster.getHypervisorType().equals(HypervisorType.VMware)) {
@ -1443,9 +1446,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} }
@Override @Override
public List<? extends VmwareDatacenter> listVmwareDatacenters(ListVmwareDcsCmd cmd) throws CloudRuntimeException, InvalidParameterValueException { public List<? extends VmwareDatacenter> listVmwareDatacenters(ListVmwareDcsCmd cmd) throws CloudRuntimeException {
Long zoneId = cmd.getZoneId(); Long zoneId = cmd.getZoneId();
List<VmwareDatacenterVO> vmwareDcList = new ArrayList<VmwareDatacenterVO>(); List<VmwareDatacenterVO> vmwareDcList = new ArrayList<>();
VmwareDatacenterZoneMapVO vmwareDcZoneMap; VmwareDatacenterZoneMapVO vmwareDcZoneMap;
VmwareDatacenterVO vmwareDatacenter; VmwareDatacenterVO vmwareDatacenter;
long vmwareDcId; long vmwareDcId;
@ -1503,7 +1506,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String vCenterHost = vmwareDatacenter.getVcenterHost(); String vCenterHost = vmwareDatacenter.getVcenterHost();
String userName = vmwareDatacenter.getUser(); String userName = vmwareDatacenter.getUser();
String password = vmwareDatacenter.getPassword(); String password = vmwareDatacenter.getPassword();
List<PbmProfile> storageProfiles = null; List<PbmProfile> storageProfiles;
try { try {
logger.debug(String.format("Importing vSphere Storage Policies for the vmware DC %d in zone %d", vmwareDcId, zoneId)); logger.debug(String.format("Importing vSphere Storage Policies for the vmware DC %d in zone %d", vmwareDcId, zoneId));
VmwareContext context = VmwareContextFactory.getContext(vCenterHost, userName, password); VmwareContext context = VmwareContextFactory.getContext(vCenterHost, userName, password);
@ -1531,16 +1534,15 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
List<VsphereStoragePolicyVO> allStoragePolicies = vsphereStoragePolicyDao.listAll(); List<VsphereStoragePolicyVO> allStoragePolicies = vsphereStoragePolicyDao.listAll();
List<PbmProfile> finalStorageProfiles = storageProfiles; List<PbmProfile> finalStorageProfiles = storageProfiles;
List<VsphereStoragePolicyVO> needToMarkRemoved = allStoragePolicies.stream() List<VsphereStoragePolicyVO> needToMarkRemoved = allStoragePolicies.stream()
.filter(existingPolicy -> !finalStorageProfiles.stream() .filter(existingPolicy -> finalStorageProfiles.stream()
.anyMatch(storageProfile -> storageProfile.getProfileId().getUniqueId().equals(existingPolicy.getPolicyId()))) .noneMatch(storageProfile -> storageProfile.getProfileId().getUniqueId().equals(existingPolicy.getPolicyId())))
.collect(Collectors.toList()); .collect(Collectors.toList());
for (VsphereStoragePolicyVO storagePolicy : needToMarkRemoved) { for (VsphereStoragePolicyVO storagePolicy : needToMarkRemoved) {
vsphereStoragePolicyDao.remove(storagePolicy.getId()); vsphereStoragePolicyDao.remove(storagePolicy.getId());
} }
List<VsphereStoragePolicyVO> storagePolicies = vsphereStoragePolicyDao.listAll(); return vsphereStoragePolicyDao.listAll();
return storagePolicies;
} }
@Override @Override
@ -1586,13 +1588,87 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} }
@Override @Override
public List<UnmanagedInstanceTO> listVMsInDatacenter(ListVmwareDcVmsCmd cmd) { public List<HostMO> listHostsInDatacenter(ListVmwareDcHostsCmd cmd) {
VcenterData vmwaredc = getVcenterData(cmd);
try {
VmwareContext context = getVmwareContext(vmwaredc);
DatacenterMO dcMo = getDatacenterMO(context, vmwaredc);
return dcMo.getAllHostsOnDatacenter();
} catch (RuntimeFaultFaultMsg | URISyntaxException | VmwareClientException | InvalidLocaleFaultMsg |
InvalidLoginFaultMsg | InvalidPropertyFaultMsg e) {
String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s",
vmwaredc.vcenter, vmwaredc.datacenterName, e.getMessage());
logger.error(errorMsg, e);
throw new CloudRuntimeException(errorMsg);
}
}
@Override
public Pair<String, List<UnmanagedInstanceTO>> listVMsInDatacenter(ListVmwareDcVmsCmd cmd) {
Integer maxObjects = cmd.getBatchSize();
String token = cmd.getToken();
String host = cmd.getHost();
VcenterData vmwaredc = getVcenterData(cmd);
try {
VmwareContext context = getVmwareContext(vmwaredc);
DatacenterMO dcMo = getDatacenterMO(context, vmwaredc);
if (com.cloud.utils.StringUtils.isNotBlank(host)) {
ManagedObjectReference hostMor = dcMo.findHost(host);
if (hostMor == null) {
throw new VmwareClientException(String.format("No host '%s' found on DC: %s.", host, dcMo.getName()));
}
HostMO hostMo = new HostMO(context, hostMor);
return hostMo.getVms(maxObjects, token);
} else {
return dcMo.getVms(maxObjects, token);
}
} catch (InvalidParameterValueException | VmwareClientException | InvalidLocaleFaultMsg | InvalidLoginFaultMsg |
RuntimeFaultFaultMsg | URISyntaxException | InvalidPropertyFaultMsg | InvocationTargetException |
NoSuchMethodException | IllegalAccessException e) {
String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s",
vmwaredc.vcenter, vmwaredc.datacenterName, e.getMessage());
logger.error(errorMsg, e);
throw new CloudRuntimeException(errorMsg);
}
}
@NotNull
private DatacenterMO getDatacenterMO(VmwareContext context, VcenterData vmwaredc) throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg {
DatacenterMO dcMo = new DatacenterMO(context, vmwaredc.datacenterName);
ManagedObjectReference dcMor = dcMo.getMor();
if (dcMor == null) {
String msg = String.format("Unable to find VMware datacenter %s in vCenter %s",
vmwaredc.datacenterName, vmwaredc.vcenter);
logger.error(msg);
throw new InvalidParameterValueException(msg);
}
return dcMo;
}
@NotNull
private VmwareContext getVmwareContext(VcenterData vmwaredc) throws RuntimeFaultFaultMsg, URISyntaxException, VmwareClientException, InvalidLocaleFaultMsg, InvalidLoginFaultMsg {
logger.debug(String.format("Connecting to the VMware datacenter %s at vCenter %s to retrieve VMs",
vmwaredc.datacenterName, vmwaredc.vcenter));
String serviceUrl = String.format("https://%s/sdk/vimService", vmwaredc.vcenter);
VmwareClient vimClient = new VmwareClient(vmwaredc.vcenter);
vimClient.connect(serviceUrl, vmwaredc.username, vmwaredc.password);
VmwareContext context = new VmwareContext(vimClient, vmwaredc.vcenter);
return context;
}
@NotNull
private VcenterData getVcenterData(ListVmwareDcItems cmd) {
String vcenter = cmd.getVcenter(); String vcenter = cmd.getVcenter();
String datacenterName = cmd.getDatacenterName(); String datacenterName = cmd.getDatacenterName();
String username = cmd.getUsername(); String username = cmd.getUsername();
String password = cmd.getPassword(); String password = cmd.getPassword();
Long existingVcenterId = cmd.getExistingVcenterId(); Long existingVcenterId = cmd.getExistingVcenterId();
String keyword = cmd.getKeyword();
if ((existingVcenterId == null && StringUtils.isBlank(vcenter)) || if ((existingVcenterId == null && StringUtils.isBlank(vcenter)) ||
(existingVcenterId != null && StringUtils.isNotBlank(vcenter))) { (existingVcenterId != null && StringUtils.isNotBlank(vcenter))) {
@ -1613,37 +1689,27 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
username = vmwareDc.getUser(); username = vmwareDc.getUser();
password = vmwareDc.getPassword(); password = vmwareDc.getPassword();
} }
VcenterData vmwaredc = new VcenterData(vcenter, datacenterName, username, password);
try { return vmwaredc;
logger.debug(String.format("Connecting to the VMware datacenter %s at vCenter %s to retrieve VMs",
datacenterName, vcenter));
String serviceUrl = String.format("https://%s/sdk/vimService", vcenter);
VmwareClient vimClient = new VmwareClient(vcenter);
vimClient.connect(serviceUrl, username, password);
VmwareContext context = new VmwareContext(vimClient, vcenter);
DatacenterMO dcMo = new DatacenterMO(context, datacenterName);
ManagedObjectReference dcMor = dcMo.getMor();
if (dcMor == null) {
String msg = String.format("Unable to find VMware datacenter %s in vCenter %s",
datacenterName, vcenter);
logger.error(msg);
throw new InvalidParameterValueException(msg);
} }
List<UnmanagedInstanceTO> instances = dcMo.getAllVmsOnDatacenter();
return StringUtils.isBlank(keyword) ? instances : private static class VcenterData {
instances.stream().filter(x -> x.getName().toLowerCase().contains(keyword.toLowerCase())).collect(Collectors.toList()); public final String vcenter;
} catch (Exception e) { public final String datacenterName;
String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s", public final String username;
vcenter, datacenterName, e.getMessage()); public final String password;
logger.error(errorMsg, e);
throw new CloudRuntimeException(errorMsg); public VcenterData(String vcenter, String datacenterName, String username, String password) {
this.vcenter = vcenter;
this.datacenterName = datacenterName;
this.username = username;
this.password = password;
} }
} }
@Override @Override
public boolean hasNexusVSM(Long clusterId) { public boolean hasNexusVSM(Long clusterId) {
ClusterVSMMapVO vsmMapVo = null; ClusterVSMMapVO vsmMapVo;
vsmMapVo = _vsmMapDao.findByClusterId(clusterId); vsmMapVo = _vsmMapDao.findByClusterId(clusterId);
if (vsmMapVo == null) { if (vsmMapVo == null) {
@ -1693,7 +1759,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} }
/** /**
* This task is to cleanup templates from primary storage that are otherwise not cleaned by the {@link com.cloud.storage.StorageManagerImpl.StorageGarbageCollector}. * This task is to clean-up templates from primary storage that are otherwise not cleaned by the {@see com.cloud.storage.StorageManagerImpl.StorageGarbageCollector}.
* it is called at regular intervals when storage.template.cleanup.enabled == true * it is called at regular intervals when storage.template.cleanup.enabled == true
* It collect all templates that * It collect all templates that
* - are deleted from cloudstack * - are deleted from cloudstack

View File

@ -45,6 +45,7 @@ import java.util.TimeZone;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.cloud.agent.api.CleanupVMCommand;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.datatype.XMLGregorianCalendar;
@ -583,6 +584,8 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
return execute((ResizeVolumeCommand) cmd); return execute((ResizeVolumeCommand) cmd);
} else if (clz == UnregisterVMCommand.class) { } else if (clz == UnregisterVMCommand.class) {
return execute((UnregisterVMCommand) cmd); return execute((UnregisterVMCommand) cmd);
} else if (clz == CleanupVMCommand.class) {
return execute((CleanupVMCommand) cmd);
} else if (cmd instanceof StorageSubSystemCommand) { } else if (cmd instanceof StorageSubSystemCommand) {
checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand) cmd); checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand) cmd);
return storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd); return storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd);
@ -5796,6 +5799,26 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
return new Answer(cmd, true, "success"); return new Answer(cmd, true, "success");
} }
protected Answer execute(CleanupVMCommand cmd) {
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
try {
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
if (vmMo == null) {
String msg = String.format("VM [%s] not found on vCenter, cleanup not needed.", cmd.getVmName());
logger.debug(msg);
return new Answer(cmd, true, msg);
}
vmMo.destroy();
String msg = String.format("VM [%s] remnants on vCenter cleaned up.", cmd.getVmName());
logger.debug(msg);
return new Answer(cmd, true, msg);
} catch (Exception e) {
return new Answer(cmd, false, createLogMessageException(e, cmd));
}
}
protected Answer execute(UnregisterVMCommand cmd) { protected Answer execute(UnregisterVMCommand cmd) {
VmwareContext context = getServiceContext(); VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context); VmwareHypervisorHost hyperHost = getHyperHost(context);

View File

@ -36,8 +36,8 @@ import com.cloud.dc.VmwareDatacenterVO;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "addVmwareDc", description = "Adds a VMware datacenter to specified zone", responseObject = VmwareDatacenterResponse.class, @APICommand(name = "addVmwareDc", description = "Adds a Vmware datacenter to specified zone",
requestHasSensitiveInfo = true, responseHasSensitiveInfo = false) responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false)
public class AddVmwareDcCmd extends BaseCmd { public class AddVmwareDcCmd extends BaseCmd {
@Inject @Inject
@ -45,7 +45,7 @@ public class AddVmwareDcCmd extends BaseCmd {
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of VMware datacenter to be added to specified zone.") @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of Vmware datacenter to be added to specified zone.")
private String name; private String name;
@Parameter(name = ApiConstants.VCENTER, @Parameter(name = ApiConstants.VCENTER,
@ -54,10 +54,10 @@ public class AddVmwareDcCmd extends BaseCmd {
description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.") description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
private String vCenter; private String vCenter;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = false, description = "The Username required to connect to resource.") @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.")
private String username; private String username;
@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = false, description = "The password for specified username.") @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.")
private String password; private String password;
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "The Zone ID.") @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "The Zone ID.")
@ -99,7 +99,7 @@ public class AddVmwareDcCmd extends BaseCmd {
response.setResponseName(getCommandName()); response.setResponseName(getCommandName());
response.setObjectName("vmwaredc"); response.setObjectName("vmwaredc");
} else { } else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add VMware Datacenter to zone."); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Vmware Datacenter to zone.");
} }
this.setResponseObject(response); this.setResponseObject(response);
} catch (DiscoveryException ex) { } catch (DiscoveryException ex) {

View File

@ -48,8 +48,6 @@ import java.util.List;
authorized = {RoleType.Admin}) authorized = {RoleType.Admin})
public class ImportVsphereStoragePoliciesCmd extends BaseCmd { public class ImportVsphereStoragePoliciesCmd extends BaseCmd {
@Inject @Inject
public VmwareDatacenterService _vmwareDatacenterService; public VmwareDatacenterService _vmwareDatacenterService;
@ -74,6 +72,13 @@ public class ImportVsphereStoragePoliciesCmd extends BaseCmd {
List<? extends VsphereStoragePolicy> storagePolicies = _vmwareDatacenterService.importVsphereStoragePolicies(this); List<? extends VsphereStoragePolicy> storagePolicies = _vmwareDatacenterService.importVsphereStoragePolicies(this);
final ListResponse<VsphereStoragePoliciesResponse> responseList = new ListResponse<>(); final ListResponse<VsphereStoragePoliciesResponse> responseList = new ListResponse<>();
final List<VsphereStoragePoliciesResponse> storagePoliciesResponseList = getVsphereStoragePoliciesResponses(storagePolicies, dataCenter);
responseList.setResponses(storagePoliciesResponseList);
responseList.setResponseName(getCommandName());
setResponseObject(responseList);
}
private static List<VsphereStoragePoliciesResponse> getVsphereStoragePoliciesResponses(List<? extends VsphereStoragePolicy> storagePolicies, DataCenter dataCenter) {
final List<VsphereStoragePoliciesResponse> storagePoliciesResponseList = new ArrayList<>(); final List<VsphereStoragePoliciesResponse> storagePoliciesResponseList = new ArrayList<>();
for (VsphereStoragePolicy storagePolicy : storagePolicies) { for (VsphereStoragePolicy storagePolicy : storagePolicies) {
final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse(); final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse();
@ -86,9 +91,7 @@ public class ImportVsphereStoragePoliciesCmd extends BaseCmd {
storagePoliciesResponseList.add(storagePoliciesResponse); storagePoliciesResponseList.add(storagePoliciesResponse);
} }
responseList.setResponses(storagePoliciesResponseList); return storagePoliciesResponseList;
responseList.setResponseName(getCommandName());
setResponseObject(responseList);
} }
@Override @Override

View File

@ -0,0 +1,144 @@
// 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.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.Hypervisor;
import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.user.Account;
import com.cloud.utils.exception.CloudRuntimeException;
import com.vmware.vim25.InvalidPropertyFaultMsg;
import com.vmware.vim25.RuntimeFaultFaultMsg;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
@APICommand(name = "listVmwareDcHosts", responseObject = VmwareRequestResponse.class,
description = "Lists the VMs in a Vmware Datacenter",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListVmwareDcHostsCmd extends BaseCmd implements ListVmwareDcItems {
@Inject
public VmwareDatacenterService _vmwareDatacenterService;
@Parameter(name = ApiConstants.EXISTING_VCENTER_ID,
type = CommandType.UUID,
entityType = VmwareDatacenterResponse.class,
description = "UUID of a linked existing vCenter")
private Long existingVcenterId;
@Parameter(name = ApiConstants.VCENTER,
type = CommandType.STRING,
description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
private String vcenter;
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of Vmware datacenter.")
private String datacenterName;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.")
private String username;
@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.")
private String password;
public String getVcenter() {
return vcenter;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getDatacenterName() {
return datacenterName;
}
public Long getExistingVcenterId() {
return existingVcenterId;
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
checkParameters();
try {
List<HostMO> hosts = _vmwareDatacenterService.listHostsInDatacenter(this);
List<BaseResponse> baseResponseList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(hosts)) {
for (HostMO vmwareHost : hosts) {
HostResponse resp = createHostResponse(vmwareHost);
baseResponseList.add(resp);
}
}
VmwareRequestResponse<BaseResponse> response = new VmwareRequestResponse<>();
response.setResponses(baseResponseList, baseResponseList.size());
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (CloudRuntimeException | InvalidPropertyFaultMsg | RuntimeFaultFaultMsg | InvocationTargetException |
NoSuchMethodException | IllegalAccessException e) {
String errorMsg = String.format("Error retrieving VMs from Vmware VC: %s", e.getMessage());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg);
}
}
private HostResponse createHostResponse(HostMO hostInstance) throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
HostResponse response = new HostResponse();
response.setHypervisor(Hypervisor.HypervisorType.VMware.toString());
response.setName(hostInstance.getHostName());
response.setObjectName("host");
return response;
}
private void checkParameters() {
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
"Please provide an existing vCenter ID or a vCenter IP/Name, parameters are mutually exclusive");
}
if (existingVcenterId == null && StringUtils.isAnyBlank(vcenter, datacenterName, username, password)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
"Please set all the information for a vCenter IP/Name, datacenter, username and password");
}
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,29 @@
// 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;
public interface ListVmwareDcItems {
String getVcenter();
String getDatacenterName();
String getUsername();
String getPassword();
Long getExistingVcenterId();
}

View File

@ -23,15 +23,15 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.UnmanagedInstanceResponse; import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
import org.apache.cloudstack.api.response.VmwareDatacenterResponse; import org.apache.cloudstack.api.response.VmwareDatacenterResponse;
import org.apache.cloudstack.vm.UnmanagedInstanceTO; import org.apache.cloudstack.vm.UnmanagedInstanceTO;
@ -42,10 +42,10 @@ import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@APICommand(name = "listVmwareDcVms", responseObject = UnmanagedInstanceResponse.class, @APICommand(name = "listVmwareDcVms", responseObject = VmwareRequestResponse.class,
description = "Lists the VMs in a VMware Datacenter", description = "Lists the VMs in a Vmware Datacenter",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListVmwareDcVmsCmd extends BaseListCmd { public class ListVmwareDcVmsCmd extends BaseCmd implements ListVmwareDcItems {
@Inject @Inject
public VmwareDatacenterService _vmwareDatacenterService; public VmwareDatacenterService _vmwareDatacenterService;
@ -61,7 +61,7 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.") description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.")
private String vcenter; private String vcenter;
@Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of VMware datacenter.") @Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of Vmware datacenter.")
private String datacenterName; private String datacenterName;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.") @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.")
@ -70,6 +70,18 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.") @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.")
private String password; private String password;
@Parameter(name = ApiConstants.HOST, type = CommandType.STRING, description = "get only the VMs from the specified host.")
private String host;
@Parameter(name = ApiConstants.BATCH_SIZE, type = CommandType.INTEGER, description = "The maximum number of results to return.")
private Integer batchSize;
@Parameter(name = ApiConstants.TOKEN, type = CommandType.STRING,
description = "For listVmwareDcVms, if the maximum number of results (the `batchsize`) is exceeded, " +
" a token is returned. This token can be used in subsequent calls to retrieve more results." +
" As long as a token is returned, more results can be retrieved.")
private String token;
public String getVcenter() { public String getVcenter() {
return vcenter; return vcenter;
} }
@ -82,6 +94,18 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
return password; return password;
} }
public Integer getBatchSize() {
return batchSize;
}
public String getHost() {
return host;
}
public String getToken() {
return token;
}
public String getDatacenterName() { public String getDatacenterName() {
return datacenterName; return datacenterName;
} }
@ -94,7 +118,8 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
checkParameters(); checkParameters();
try { try {
List<UnmanagedInstanceTO> vms = _vmwareDatacenterService.listVMsInDatacenter(this); Pair<String, List<UnmanagedInstanceTO>> results = _vmwareDatacenterService.listVMsInDatacenter(this);
List<UnmanagedInstanceTO> vms = results.second();
List<BaseResponse> baseResponseList = new ArrayList<>(); List<BaseResponse> baseResponseList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(vms)) { if (CollectionUtils.isNotEmpty(vms)) {
for (UnmanagedInstanceTO vmwareVm : vms) { for (UnmanagedInstanceTO vmwareVm : vms) {
@ -102,16 +127,13 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
baseResponseList.add(resp); baseResponseList.add(resp);
} }
} }
List<BaseResponse> pagingList = com.cloud.utils.StringUtils.applyPagination(baseResponseList, this.getStartIndex(), this.getPageSizeVal()); VmwareRequestResponse<BaseResponse> response = new VmwareRequestResponse<>();
if (CollectionUtils.isEmpty(pagingList)) { response.setResponses(baseResponseList, baseResponseList.size());
pagingList = baseResponseList;
}
ListResponse<BaseResponse> response = new ListResponse<>();
response.setResponses(pagingList, baseResponseList.size());
response.setResponseName(getCommandName()); response.setResponseName(getCommandName());
response.setToken(results.first());
setResponseObject(response); setResponseObject(response);
} catch (CloudRuntimeException e) { } catch (CloudRuntimeException e) {
String errorMsg = String.format("Error retrieving VMs from VMware VC: %s", e.getMessage()); String errorMsg = String.format("Error retrieving VMs from Vmware VC: %s", e.getMessage());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg);
} }
} }
@ -134,6 +156,6 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
@Override @Override
public String getCommandName() { public String getCommandName() {
return "listvmwaredcvmsresponse"; return "listVmwareDcVmsResponse".toLowerCase();
} }
} }

View File

@ -42,7 +42,7 @@ import com.cloud.dc.VmwareDatacenter;
import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.user.Account; import com.cloud.user.Account;
@APICommand(name = "listVmwareDcs", responseObject = VmwareDatacenterResponse.class, description = "Retrieves VMware DC(s) associated with a zone.", @APICommand(name = "listVmwareDcs", responseObject = VmwareDatacenterResponse.class, description = "Retrieves Vmware DC(s) associated with a zone.",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListVmwareDcsCmd extends BaseListCmd { public class ListVmwareDcsCmd extends BaseListCmd {
@ -50,7 +50,6 @@ public class ListVmwareDcsCmd extends BaseListCmd {
public VmwareDatacenterService _vmwareDatacenterService; public VmwareDatacenterService _vmwareDatacenterService;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
//////////////// API parameters ///////////////////// //////////////// API parameters /////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -73,20 +72,27 @@ public class ListVmwareDcsCmd extends BaseListCmd {
@Override @Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException { ResourceAllocationException {
List<? extends VmwareDatacenter> vmwareDcList = null; List<? extends VmwareDatacenter> vmwareDcList;
try { try {
vmwareDcList = _vmwareDatacenterService.listVmwareDatacenters(this); vmwareDcList = _vmwareDatacenterService.listVmwareDatacenters(this);
} catch (InvalidParameterValueException ie) { } catch (InvalidParameterValueException ie) {
throw new InvalidParameterValueException("Invalid zone id " + getZoneId()); throw new InvalidParameterValueException("Invalid zone id " + getZoneId());
} catch (Exception e) { } catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find associated VMware DCs associated with zone " + getZoneId()); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find associated Vmware DCs associated with zone " + getZoneId());
} }
ListResponse<VmwareDatacenterResponse> response = new ListResponse<VmwareDatacenterResponse>(); ListResponse<VmwareDatacenterResponse> response = new ListResponse<>();
List<VmwareDatacenterResponse> vmwareDcResponses = new ArrayList<VmwareDatacenterResponse>(); List<VmwareDatacenterResponse> vmwareDcResponses = getVmwareDatacenterResponses(vmwareDcList);
response.setResponses(vmwareDcResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
if (vmwareDcList != null && vmwareDcList.size() > 0) { private List<VmwareDatacenterResponse> getVmwareDatacenterResponses(List<? extends VmwareDatacenter> vmwareDcList) {
List<VmwareDatacenterResponse> vmwareDcResponses = new ArrayList<>();
if (vmwareDcList != null && !vmwareDcList.isEmpty()) {
for (VmwareDatacenter vmwareDc : vmwareDcList) { for (VmwareDatacenter vmwareDc : vmwareDcList) {
VmwareDatacenterResponse vmwareDcResponse = new VmwareDatacenterResponse(); VmwareDatacenterResponse vmwareDcResponse = new VmwareDatacenterResponse();
@ -94,14 +100,12 @@ public class ListVmwareDcsCmd extends BaseListCmd {
vmwareDcResponse.setVcenter(vmwareDc.getVcenterHost()); vmwareDcResponse.setVcenter(vmwareDc.getVcenterHost());
vmwareDcResponse.setName(vmwareDc.getVmwareDatacenterName()); vmwareDcResponse.setName(vmwareDc.getVmwareDatacenterName());
vmwareDcResponse.setZoneId(getZoneId()); vmwareDcResponse.setZoneId(getZoneId());
vmwareDcResponse.setObjectName("VMwareDC"); vmwareDcResponse.setObjectName(ApiConstants.VMWARE_DC);
vmwareDcResponses.add(vmwareDcResponse); vmwareDcResponses.add(vmwareDcResponse);
} }
} }
response.setResponses(vmwareDcResponses); return vmwareDcResponses;
response.setResponseName(getCommandName());
setResponseObject(response);
} }
@Override @Override

View File

@ -47,8 +47,6 @@ import java.util.List;
authorized = {RoleType.Admin}) authorized = {RoleType.Admin})
public class ListVsphereStoragePoliciesCmd extends BaseCmd { public class ListVsphereStoragePoliciesCmd extends BaseCmd {
@Inject @Inject
public VmwareDatacenterService _vmwareDatacenterService; public VmwareDatacenterService _vmwareDatacenterService;
@ -73,6 +71,13 @@ public class ListVsphereStoragePoliciesCmd extends BaseCmd {
List<? extends VsphereStoragePolicy> storagePolicies = _vmwareDatacenterService.listVsphereStoragePolicies(this); List<? extends VsphereStoragePolicy> storagePolicies = _vmwareDatacenterService.listVsphereStoragePolicies(this);
final ListResponse<VsphereStoragePoliciesResponse> responseList = new ListResponse<>(); final ListResponse<VsphereStoragePoliciesResponse> responseList = new ListResponse<>();
final List<VsphereStoragePoliciesResponse> storagePoliciesResponseList = getVsphereStoragePoliciesResponses(storagePolicies, dataCenter);
responseList.setResponses(storagePoliciesResponseList);
responseList.setResponseName(getCommandName());
setResponseObject(responseList);
}
private static List<VsphereStoragePoliciesResponse> getVsphereStoragePoliciesResponses(List<? extends VsphereStoragePolicy> storagePolicies, DataCenter dataCenter) {
final List<VsphereStoragePoliciesResponse> storagePoliciesResponseList = new ArrayList<>(); final List<VsphereStoragePoliciesResponse> storagePoliciesResponseList = new ArrayList<>();
for (VsphereStoragePolicy storagePolicy : storagePolicies) { for (VsphereStoragePolicy storagePolicy : storagePolicies) {
final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse(); final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse();
@ -81,13 +86,11 @@ public class ListVsphereStoragePoliciesCmd extends BaseCmd {
storagePoliciesResponse.setName(storagePolicy.getName()); storagePoliciesResponse.setName(storagePolicy.getName());
storagePoliciesResponse.setPolicyId(storagePolicy.getPolicyId()); storagePoliciesResponse.setPolicyId(storagePolicy.getPolicyId());
storagePoliciesResponse.setDescription(storagePolicy.getDescription()); storagePoliciesResponse.setDescription(storagePolicy.getDescription());
storagePoliciesResponse.setObjectName("StoragePolicy"); storagePoliciesResponse.setObjectName(ApiConstants.STORAGE_POLICY);
storagePoliciesResponseList.add(storagePoliciesResponse); storagePoliciesResponseList.add(storagePoliciesResponse);
} }
responseList.setResponses(storagePoliciesResponseList); return storagePoliciesResponseList;
responseList.setResponseName(getCommandName());
setResponseObject(responseList);
} }
@Override @Override

View File

@ -68,7 +68,7 @@ public class ListVsphereStoragePolicyCompatiblePoolsCmd extends BaseListCmd {
List<StoragePoolResponse> poolResponses = new ArrayList<>(); List<StoragePoolResponse> poolResponses = new ArrayList<>();
for (StoragePool pool : pools) { for (StoragePool pool : pools) {
StoragePoolResponse poolResponse = _responseGenerator.createStoragePoolForMigrationResponse(pool); StoragePoolResponse poolResponse = _responseGenerator.createStoragePoolForMigrationResponse(pool);
poolResponse.setObjectName("storagepool"); poolResponse.setObjectName(ApiConstants.STORAGE_POOL);
poolResponses.add(poolResponse); poolResponses.add(poolResponse);
} }
response.setResponses(poolResponses); response.setResponses(poolResponses);

View File

@ -34,7 +34,7 @@ import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "removeVmwareDc", responseObject = SuccessResponse.class, description = "Remove a VMware datacenter from a zone.", @APICommand(name = "removeVmwareDc", responseObject = SuccessResponse.class, description = "Remove a Vmware datacenter from a zone.",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class RemoveVmwareDcCmd extends BaseCmd { public class RemoveVmwareDcCmd extends BaseCmd {
@ -47,7 +47,7 @@ public class RemoveVmwareDcCmd extends BaseCmd {
type = CommandType.UUID, type = CommandType.UUID,
entityType = ZoneResponse.class, entityType = ZoneResponse.class,
required = true, required = true,
description = "The id of Zone from which VMware datacenter has to be removed.") description = "The id of Zone from which Vmware datacenter has to be removed.")
private Long zoneId; private Long zoneId;
public Long getZoneId() { public Long getZoneId() {
@ -63,7 +63,7 @@ public class RemoveVmwareDcCmd extends BaseCmd {
response.setResponseName(getCommandName()); response.setResponseName(getCommandName());
setResponseObject(response); setResponseObject(response);
} else { } else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove VMware datacenter from zone"); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove Vmware datacenter from zone");
} }
} catch (ResourceInUseException ex) { } catch (ResourceInUseException ex) {
logger.warn("The zone has one or more resources (like cluster), hence not able to remove VMware datacenter from zone." logger.warn("The zone has one or more resources (like cluster), hence not able to remove VMware datacenter from zone."

View File

@ -33,12 +33,11 @@ import com.cloud.dc.VmwareDatacenter;
import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.user.Account; import com.cloud.user.Account;
@APICommand(name = "updateVmwareDc", description = "Updates a VMware datacenter details for a zone", @APICommand(name = "updateVmwareDc", description = "Updates a Vmware datacenter details for a zone",
responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false, responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false,
since = "4.12.0", authorized = {RoleType.Admin}) since = "4.12.0", authorized = {RoleType.Admin})
public class UpdateVmwareDcCmd extends BaseCmd { public class UpdateVmwareDcCmd extends BaseCmd {
@Inject @Inject
public VmwareDatacenterService vmwareDatacenterService; public VmwareDatacenterService vmwareDatacenterService;
@ -51,7 +50,7 @@ public class UpdateVmwareDcCmd extends BaseCmd {
private Long zoneId; private Long zoneId;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, @Parameter(name = ApiConstants.NAME, type = CommandType.STRING,
description = "VMware datacenter name.") description = "Vmware datacenter name.")
private String name; private String name;
@Parameter(name = ApiConstants.VCENTER, type = CommandType.STRING, @Parameter(name = ApiConstants.VCENTER, type = CommandType.STRING,
@ -106,13 +105,13 @@ public class UpdateVmwareDcCmd extends BaseCmd {
public void execute() { public void execute() {
final VmwareDatacenter vmwareDatacenter = vmwareDatacenterService.updateVmwareDatacenter(this); final VmwareDatacenter vmwareDatacenter = vmwareDatacenterService.updateVmwareDatacenter(this);
if (vmwareDatacenter == null) { if (vmwareDatacenter == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VMware datacenter"); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update Vmware datacenter");
} }
final VmwareDatacenterResponse response = new VmwareDatacenterResponse(); final VmwareDatacenterResponse response = new VmwareDatacenterResponse();
response.setId(vmwareDatacenter.getUuid()); response.setId(vmwareDatacenter.getUuid());
response.setName(vmwareDatacenter.getVmwareDatacenterName()); response.setName(vmwareDatacenter.getVmwareDatacenterName());
response.setResponseName(getCommandName()); response.setResponseName(getCommandName());
response.setObjectName("vmwaredc"); response.setObjectName(ApiConstants.VMWARE_DC);
setResponseObject(response); setResponseObject(response);
} }

View File

@ -0,0 +1,38 @@
// 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.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.response.ListResponse;
public class VmwareRequestResponse<T extends ResponseObject> extends ListResponse<T> {
@SerializedName(ApiConstants.TOKEN)
@Param(description = "The Vmware API token to use for retrieving further responses with")
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}

View File

@ -23,10 +23,8 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
@ -206,14 +204,12 @@ public class KubernetesClusterActionWorker {
protected String getControlNodeLoginUser() { protected String getControlNodeLoginUser() {
List<KubernetesClusterVmMapVO> vmMapVOList = getKubernetesClusterVMMaps(); List<KubernetesClusterVmMapVO> vmMapVOList = getKubernetesClusterVMMaps();
if (vmMapVOList.size() > 0) { if (!vmMapVOList.isEmpty()) {
long vmId = vmMapVOList.get(0).getVmId(); long vmId = vmMapVOList.get(0).getVmId();
UserVmVO userVM = userVmDao.findById(vmId); UserVmVO userVM = userVmDao.findById(vmId);
if (userVM == null) { if (userVM == null) {
throw new CloudRuntimeException("Failed to find login user, Unable to log in to node to fetch details"); throw new CloudRuntimeException("Failed to find login user, Unable to log in to node to fetch details");
} }
Set<String> vm = new HashSet<>();
vm.add(userVM.getName());
UserVmDetailVO vmDetail = userVmDetailsDao.findDetail(vmId, VmDetailConstants.CKS_CONTROL_NODE_LOGIN_USER); UserVmDetailVO vmDetail = userVmDetailsDao.findDetail(vmId, VmDetailConstants.CKS_CONTROL_NODE_LOGIN_USER);
if (vmDetail != null && !org.apache.commons.lang3.StringUtils.isEmpty(vmDetail.getValue())) { if (vmDetail != null && !org.apache.commons.lang3.StringUtils.isEmpty(vmDetail.getValue())) {
return vmDetail.getValue(); return vmDetail.getValue();
@ -309,7 +305,7 @@ public class KubernetesClusterActionWorker {
} }
protected KubernetesClusterVmMapVO addKubernetesClusterVm(final long kubernetesClusterId, final long vmId, boolean isControlNode) { protected KubernetesClusterVmMapVO addKubernetesClusterVm(final long kubernetesClusterId, final long vmId, boolean isControlNode) {
return Transaction.execute(new TransactionCallback<KubernetesClusterVmMapVO>() { return Transaction.execute(new TransactionCallback<>() {
@Override @Override
public KubernetesClusterVmMapVO doInTransaction(TransactionStatus status) { public KubernetesClusterVmMapVO doInTransaction(TransactionStatus status) {
KubernetesClusterVmMapVO newClusterVmMap = new KubernetesClusterVmMapVO(kubernetesClusterId, vmId, isControlNode); KubernetesClusterVmMapVO newClusterVmMap = new KubernetesClusterVmMapVO(kubernetesClusterId, vmId, isControlNode);
@ -361,7 +357,12 @@ public class KubernetesClusterActionWorker {
} }
IpAddress address = ipAddressDao.findByUuid(detailsVO.getValue()); IpAddress address = ipAddressDao.findByUuid(detailsVO.getValue());
if (address == null || !Objects.equals(network.getVpcId(), address.getVpcId())) { if (address == null || !Objects.equals(network.getVpcId(), address.getVpcId())) {
logger.warn(String.format("Public IP with ID: %s linked to the Kubernetes cluster: %s is not usable", detailsVO.getValue(), kubernetesCluster.getName())); logger.warn("Public IP with ID: {} linked to the Kubernetes cluster: {} is not usable", detailsVO.getValue(), kubernetesCluster.getName());
if (address == null) {
logger.warn("Public IP with ID: {} was not found by uuid", detailsVO.getValue());
} else {
logger.warn("Public IP with ID: {} was associated with vpc {} instead of {}", detailsVO.getValue(), address.getVpcId(), network.getVpcId());
}
return null; return null;
} }
return address; return address;
@ -517,8 +518,7 @@ public class KubernetesClusterActionWorker {
} }
protected List<KubernetesClusterVmMapVO> getKubernetesClusterVMMaps() { protected List<KubernetesClusterVmMapVO> getKubernetesClusterVMMaps() {
List<KubernetesClusterVmMapVO> clusterVMs = kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId()); return kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId());
return clusterVMs;
} }
protected List<KubernetesClusterVmMapVO> getKubernetesClusterVMMapsForNodes(List<Long> nodeIds) { protected List<KubernetesClusterVmMapVO> getKubernetesClusterVMMapsForNodes(List<Long> nodeIds) {

View File

@ -193,7 +193,7 @@ public class KubernetesClusterUtil {
while (System.currentTimeMillis() < timeoutTime) { while (System.currentTimeMillis() < timeoutTime) {
try { try {
Pair<Boolean, String> result = SshHelper.sshExecute(ipAddress, port, user, Pair<Boolean, String> result = SshHelper.sshExecute(ipAddress, port, user,
sshKeyFile, null, "sudo cat /etc/kubernetes/admin.conf", sshKeyFile, null, "sudo cat /etc/kubernetes/user.conf 2>/dev/null || sudo cat /etc/kubernetes/admin.conf",
10000, 10000, 10000); 10000, 10000, 10000);
if (result.first() && StringUtils.isNotEmpty(result.second())) { if (result.first() && StringUtils.isNotEmpty(result.second())) {

View File

@ -5,12 +5,23 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2025-01-27]
### Fixed
- Use of multiple primary storages on the same linstor controller
## [2025-01-20] ## [2025-01-20]
### Fixed ### Fixed
- Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev - Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev
## [2024-12-19]
### Added
- Native CloudStack encryption support
## [2024-12-13] ## [2024-12-13]
### Fixed ### Fixed

View File

@ -97,18 +97,23 @@ public final class LinstorBackupSnapshotCommandWrapper
// NOTE: the qemu img will also contain the drbd metadata at the end // NOTE: the qemu img will also contain the drbd metadata at the end
final QemuImg qemu = new QemuImg(waitMilliSeconds); final QemuImg qemu = new QemuImg(waitMilliSeconds);
qemu.convert(srcFile, dstFile); qemu.convert(srcFile, dstFile);
LOGGER.info("Backup snapshot " + srcFile + " to " + dstPath); LOGGER.info("Backup snapshot '{}' to '{}'", srcPath, dstPath);
return dstPath; return dstPath;
} }
private SnapshotObjectTO setCorrectSnapshotSize(final SnapshotObjectTO dst, final String dstPath) { private SnapshotObjectTO setCorrectSnapshotSize(final SnapshotObjectTO dst, final String dstPath) {
final File snapFile = new File(dstPath); final File snapFile = new File(dstPath);
final long size = snapFile.exists() ? snapFile.length() : 0; long size;
if (snapFile.exists()) {
size = snapFile.length();
} else {
LOGGER.warn("Snapshot file {} does not exist. Reporting size 0", dstPath);
size = 0;
}
final SnapshotObjectTO snapshot = new SnapshotObjectTO(); dst.setPath(dst.getPath() + File.separator + dst.getName());
snapshot.setPath(dst.getPath() + File.separator + dst.getName()); dst.setPhysicalSize(size);
snapshot.setPhysicalSize(size); return dst;
return snapshot;
} }
@Override @Override
@ -158,6 +163,7 @@ public final class LinstorBackupSnapshotCommandWrapper
LOGGER.info("Backup shrunk " + dstPath + " to actual size " + src.getVolume().getSize()); LOGGER.info("Backup shrunk " + dstPath + " to actual size " + src.getVolume().getSize());
SnapshotObjectTO snapshot = setCorrectSnapshotSize(dst, dstPath); SnapshotObjectTO snapshot = setCorrectSnapshotSize(dst, dstPath);
LOGGER.info("Actual file size for '{}' is {}", dstPath, snapshot.getPhysicalSize());
return new CopyCmdAnswer(snapshot); return new CopyCmdAnswer(snapshot);
} catch (final Exception e) { } catch (final Exception e) {
final String error = String.format("Failed to backup snapshot with id [%s] with a pool %s, due to %s", final String error = String.format("Failed to backup snapshot with id [%s] with a pool %s, due to %s",

View File

@ -61,6 +61,11 @@ import com.linbit.linstor.api.model.Volume;
import com.linbit.linstor.api.model.VolumeDefinition; import com.linbit.linstor.api.model.VolumeDefinition;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class LinstorStorageAdaptor implements StorageAdaptor { public class LinstorStorageAdaptor implements StorageAdaptor {
protected Logger logger = LogManager.getLogger(getClass()); protected Logger logger = LogManager.getLogger(getClass());
@ -202,10 +207,10 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
final DevelopersApi api = getLinstorAPI(pool); final DevelopersApi api = getLinstorAPI(pool);
try { try {
List<ResourceDefinition> definitionList = api.resourceDefinitionList( ResourceDefinition resourceDefinition = LinstorUtil.findResourceDefinition(
Collections.singletonList(rscName), null, null, null); api, rscName, lpool.getResourceGroup());
if (definitionList.isEmpty()) { if (resourceDefinition == null) {
ResourceGroupSpawn rgSpawn = new ResourceGroupSpawn(); ResourceGroupSpawn rgSpawn = new ResourceGroupSpawn();
rgSpawn.setResourceDefinitionName(rscName); rgSpawn.setResourceDefinitionName(rscName);
rgSpawn.addVolumeSizesItem(size / 1024); // linstor uses KiB rgSpawn.addVolumeSizesItem(size / 1024); // linstor uses KiB
@ -215,22 +220,28 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
handleLinstorApiAnswers(answers, "Linstor: Unable to spawn resource."); handleLinstorApiAnswers(answers, "Linstor: Unable to spawn resource.");
} }
String foundRscName = resourceDefinition != null ? resourceDefinition.getName() : rscName;
// query linstor for the device path // query linstor for the device path
List<ResourceWithVolumes> resources = api.viewResources( List<ResourceWithVolumes> resources = api.viewResources(
Collections.emptyList(), Collections.emptyList(),
Collections.singletonList(rscName), Collections.singletonList(foundRscName),
Collections.emptyList(), Collections.emptyList(),
null, null,
null, null,
null); null);
makeResourceAvailable(api, rscName, false); makeResourceAvailable(api, foundRscName, false);
if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) { if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) {
final String devPath = resources.get(0).getVolumes().get(0).getDevicePath(); final String devPath = resources.get(0).getVolumes().get(0).getDevicePath();
logger.info("Linstor: Created drbd device: " + devPath); logger.info("Linstor: Created drbd device: " + devPath);
final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool); final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool);
kvmDisk.setFormat(QemuImg.PhysicalDiskFormat.RAW); kvmDisk.setFormat(QemuImg.PhysicalDiskFormat.RAW);
long allocatedKib = resources.get(0).getVolumes().get(0).getAllocatedSizeKib() != null ?
resources.get(0).getVolumes().get(0).getAllocatedSizeKib() : 0;
kvmDisk.setSize(allocatedKib >= 0 ? allocatedKib * 1024 : 0);
kvmDisk.setVirtualSize(size);
return kvmDisk; return kvmDisk;
} else { } else {
logger.error("Linstor: viewResources didn't return resources or volumes."); logger.error("Linstor: viewResources didn't return resources or volumes.");
@ -410,7 +421,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
if (rsc.getFlags() != null && if (rsc.getFlags() != null &&
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) && rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) &&
!rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) { !rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) {
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName); ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName, true);
logLinstorAnswers(delAnswers); logLinstorAnswers(delAnswers);
} }
} catch (ApiException apiEx) { } catch (ApiException apiEx) {
@ -473,21 +484,56 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
return false; return false;
} }
/**
* Decrements the aux property key for template resource and deletes or just deletes if not template resource.
* @param api
* @param rscName
* @param rscGrpName
* @return
* @throws ApiException
*/
private boolean deRefOrDeleteResource(DevelopersApi api, String rscName, String rscGrpName) throws ApiException {
boolean deleted = false;
List<ResourceDefinition> existingRDs = LinstorUtil.getRDListStartingWith(api, rscName);
for (ResourceDefinition rd : existingRDs) {
int expectedProps = 0; // if it is a non template resource, we don't expect any _cs-template-for- prop
String propKey = LinstorUtil.getTemplateForAuxPropKey(rscGrpName);
if (rd.getProps().containsKey(propKey)) {
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
rdm.deleteProps(Collections.singletonList(propKey));
api.resourceDefinitionModify(rd.getName(), rdm);
expectedProps = 1;
}
// if there is only one template-for property left for templates, the template isn't needed anymore
// or if it isn't a template anyway, it will not have this Aux property
// _cs-template-for- poperties work like a ref-count.
if (rd.getProps().keySet().stream()
.filter(key -> key.startsWith("Aux/" + LinstorUtil.CS_TEMPLATE_FOR_PREFIX))
.count() == expectedProps) {
ApiCallRcList answers = api.resourceDefinitionDelete(rd.getName());
checkLinstorAnswersThrow(answers);
deleted = true;
}
}
return deleted;
}
@Override @Override
public boolean deletePhysicalDisk(String name, KVMStoragePool pool, Storage.ImageFormat format) public boolean deletePhysicalDisk(String name, KVMStoragePool pool, Storage.ImageFormat format)
{ {
logger.debug("Linstor: deletePhysicalDisk " + name); logger.debug("Linstor: deletePhysicalDisk " + name);
final DevelopersApi api = getLinstorAPI(pool); final DevelopersApi api = getLinstorAPI(pool);
final String rscName = getLinstorRscName(name);
final LinstorStoragePool linstorPool = (LinstorStoragePool) pool;
String rscGrpName = linstorPool.getResourceGroup();
try { try {
final String rscName = getLinstorRscName(name); return deRefOrDeleteResource(api, rscName, rscGrpName);
logger.debug("Linstor: delete resource definition " + rscName);
ApiCallRcList answers = api.resourceDefinitionDelete(rscName);
handleLinstorApiAnswers(answers, "Linstor: Unable to delete resource definition " + rscName);
} catch (ApiException apiEx) { } catch (ApiException apiEx) {
logger.error("Linstor: ApiEx - " + apiEx.getMessage());
throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx); throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx);
} }
return true;
} }
@Override @Override
@ -561,6 +607,56 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
return false; return false;
} }
/**
* Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
* The initial systemvm template resource isn't created on the management server, but
* we now need to know if the systemvm template is used, while copying.
* @param disk
* @return True if it is the systemvm template disk, else false.
*/
private static boolean isSystemTemplate(KVMPhysicalDisk disk) {
Path diskPath = Paths.get(disk.getPath());
Path propFile = diskPath.getParent().resolve("template.properties");
if (Files.exists(propFile)) {
java.util.Properties templateProps = new java.util.Properties();
try {
templateProps.load(new FileInputStream(propFile.toFile()));
String desc = templateProps.getProperty("description");
if (desc.startsWith("SystemVM Template")) {
return true;
}
} catch (IOException e) {
return false;
}
}
return false;
}
/**
* Conditionally sets the correct aux properties for templates or basic resources.
* @param api
* @param srcDisk
* @param destPool
* @param name
*/
private void setRscDfnAuxProperties(
DevelopersApi api, KVMPhysicalDisk srcDisk, KVMStoragePool destPool, String name) {
// if it is the initial systemvm disk copy, we need to apply the _cs-template-for property.
if (isSystemTemplate(srcDisk)) {
applyAuxProps(api, name, "SystemVM Template", null);
LinstorStoragePool linPool = (LinstorStoragePool) destPool;
final String rscName = getLinstorRscName(name);
try {
LinstorUtil.setAuxTemplateForProperty(api, rscName, linPool.getResourceGroup());
} catch (ApiException apiExc) {
logger.error("Error setting aux template for property for {}", rscName);
logLinstorAnswers(apiExc.getApiCallRcList());
}
} else {
applyAuxProps(api, name, srcDisk.getDispName(), srcDisk.getVmName());
}
}
@Override @Override
public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPools, int timeout, byte[] srcPassphrase, byte[] destPassphrase, Storage.ProvisioningType provisioningType) public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMStoragePool destPools, int timeout, byte[] srcPassphrase, byte[] destPassphrase, Storage.ProvisioningType provisioningType)
{ {
@ -574,15 +670,14 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
name, QemuImg.PhysicalDiskFormat.RAW, provisioningType, disk.getVirtualSize(), null); name, QemuImg.PhysicalDiskFormat.RAW, provisioningType, disk.getVirtualSize(), null);
final DevelopersApi api = getLinstorAPI(destPools); final DevelopersApi api = getLinstorAPI(destPools);
applyAuxProps(api, name, disk.getDispName(), disk.getVmName()); setRscDfnAuxProperties(api, disk, destPools, name);
logger.debug("Linstor.copyPhysicalDisk: dstPath: {}", dstDisk.getPath()); logger.debug("Linstor.copyPhysicalDisk: dstPath: {}", dstDisk.getPath());
final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath()); final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath());
destFile.setFormat(dstDisk.getFormat()); destFile.setFormat(dstDisk.getFormat());
destFile.setSize(disk.getVirtualSize()); destFile.setSize(disk.getVirtualSize());
boolean zeroedDevice = resourceSupportZeroBlocks(destPools, LinstorUtil.RSC_PREFIX + name); boolean zeroedDevice = resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
try { try {
final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true); final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true);
qemu.convert(srcFile, destFile); qemu.convert(srcFile, destFile);

View File

@ -21,11 +21,16 @@ import com.linbit.linstor.api.CloneWaiter;
import com.linbit.linstor.api.DevelopersApi; import com.linbit.linstor.api.DevelopersApi;
import com.linbit.linstor.api.model.ApiCallRc; import com.linbit.linstor.api.model.ApiCallRc;
import com.linbit.linstor.api.model.ApiCallRcList; import com.linbit.linstor.api.model.ApiCallRcList;
import com.linbit.linstor.api.model.AutoSelectFilter;
import com.linbit.linstor.api.model.LayerType;
import com.linbit.linstor.api.model.Properties; import com.linbit.linstor.api.model.Properties;
import com.linbit.linstor.api.model.ResourceDefinition; import com.linbit.linstor.api.model.ResourceDefinition;
import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest; import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest;
import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted; import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted;
import com.linbit.linstor.api.model.ResourceDefinitionCreate; import com.linbit.linstor.api.model.ResourceDefinitionCreate;
import com.linbit.linstor.api.model.ResourceDefinitionModify;
import com.linbit.linstor.api.model.ResourceGroup;
import com.linbit.linstor.api.model.ResourceGroupSpawn; import com.linbit.linstor.api.model.ResourceGroupSpawn;
import com.linbit.linstor.api.model.ResourceMakeAvailable; import com.linbit.linstor.api.model.ResourceMakeAvailable;
import com.linbit.linstor.api.model.Snapshot; import com.linbit.linstor.api.model.Snapshot;
@ -34,6 +39,7 @@ import com.linbit.linstor.api.model.VolumeDefinition;
import com.linbit.linstor.api.model.VolumeDefinitionModify; import com.linbit.linstor.api.model.VolumeDefinitionModify;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Arrays; import java.util.Arrays;
@ -43,6 +49,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.storage.ResizeVolumeAnswer; import com.cloud.agent.api.storage.ResizeVolumeAnswer;
@ -66,6 +73,7 @@ import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.Volume; import com.cloud.storage.Volume;
import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeDetailVO;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
@ -85,6 +93,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
@ -93,6 +102,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.RemoteHostEndPoint; import org.apache.cloudstack.storage.RemoteHostEndPoint;
import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateObjectAnswer;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -103,8 +113,12 @@ import org.apache.cloudstack.storage.snapshot.SnapshotObject;
import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.cloudstack.storage.volume.VolumeObject; import org.apache.cloudstack.storage.volume.VolumeObject;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.commons.collections.CollectionUtils;
import java.nio.charset.StandardCharsets;
public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver {
protected Logger logger = LogManager.getLogger(getClass()); protected Logger logger = LogManager.getLogger(getClass());
@ -216,7 +230,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
} }
throw new CloudRuntimeException("Linstor: Unable to delete resource definition: " + rscDefName); throw new CloudRuntimeException("Linstor: Unable to delete resource definition: " + rscDefName);
} }
logger.info(String.format("Linstor: Deleted resource %s", rscDefName)); logger.info("Linstor: Deleted resource {}", rscDefName);
} catch (ApiException apiEx) } catch (ApiException apiEx)
{ {
logger.error("Linstor: ApiEx - " + apiEx.getMessage()); logger.error("Linstor: ApiEx - " + apiEx.getMessage());
@ -394,22 +408,166 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
storagePoolVO.getUserInfo() : "DfltRscGrp"; storagePoolVO.getUserInfo() : "DfltRscGrp";
} }
private String createResourceBase( /**
String rscName, long sizeInBytes, String volName, String vmName, DevelopersApi api, String rscGrp) { * Returns the layerlist of the resourceGroup with encryption(LUKS) added above STORAGE.
ResourceGroupSpawn rscGrpSpawn = new ResourceGroupSpawn(); * If the resourceGroup layer list already contains LUKS this layer list will be returned.
rscGrpSpawn.setResourceDefinitionName(rscName); * @param api Linstor developers API
rscGrpSpawn.addVolumeSizesItem(sizeInBytes / 1024); * @param resourceGroup Resource group to get the encryption layer list
* @return layer list with LUKS added
*/
public List<LayerType> getEncryptedLayerList(DevelopersApi api, String resourceGroup) {
try {
List<ResourceGroup> rscGrps = api.resourceGroupList(
Collections.singletonList(resourceGroup), Collections.emptyList(), null, null);
if (CollectionUtils.isEmpty(rscGrps)) {
throw new CloudRuntimeException(
String.format("Resource Group %s not found on Linstor cluster.", resourceGroup));
}
final ResourceGroup rscGrp = rscGrps.get(0);
List<LayerType> layers = Arrays.asList(LayerType.DRBD, LayerType.LUKS, LayerType.STORAGE);
List<String> curLayerStack = rscGrp.getSelectFilter() != null ?
rscGrp.getSelectFilter().getLayerStack() : Collections.emptyList();
if (CollectionUtils.isNotEmpty(curLayerStack)) {
layers = curLayerStack.stream().map(LayerType::valueOf).collect(Collectors.toList());
if (!layers.contains(LayerType.LUKS)) {
layers.add(layers.size() - 1, LayerType.LUKS); // lowest layer is STORAGE
}
}
return layers;
} catch (ApiException e) {
throw new CloudRuntimeException(
String.format("Resource Group %s not found on Linstor cluster.", resourceGroup));
}
}
/**
* Spawns a new Linstor resource with the given arguments.
* @param api
* @param newRscName
* @param sizeInBytes
* @param isTemplate
* @param rscGrpName
* @param volName
* @param vmName
* @throws ApiException
*/
private void spawnResource(
DevelopersApi api, String newRscName, long sizeInBytes, boolean isTemplate, String rscGrpName,
String volName, String vmName, @Nullable Long passPhraseId, @Nullable byte[] passPhrase) throws ApiException
{
ResourceGroupSpawn rscGrpSpawn = new ResourceGroupSpawn();
rscGrpSpawn.setResourceDefinitionName(newRscName);
rscGrpSpawn.addVolumeSizesItem(sizeInBytes / 1024);
if (passPhraseId != null) {
AutoSelectFilter asf = new AutoSelectFilter();
List<LayerType> luksLayers = getEncryptedLayerList(api, rscGrpName);
asf.setLayerStack(luksLayers.stream().map(LayerType::toString).collect(Collectors.toList()));
rscGrpSpawn.setSelectFilter(asf);
if (passPhrase != null) {
String utf8Passphrase = new String(passPhrase, StandardCharsets.UTF_8);
rscGrpSpawn.setVolumePassphrases(Collections.singletonList(utf8Passphrase));
}
}
if (isTemplate) {
Properties props = new Properties();
props.put(LinstorUtil.getTemplateForAuxPropKey(rscGrpName), "true");
rscGrpSpawn.setResourceDefinitionProps(props);
}
logger.info("Linstor: Spawn resource " + newRscName);
ApiCallRcList answers = api.resourceGroupSpawn(rscGrpName, rscGrpSpawn);
checkLinstorAnswersThrow(answers);
answers = LinstorUtil.applyAuxProps(api, newRscName, volName, vmName);
checkLinstorAnswersThrow(answers);
}
/**
* Condition if a template resource can be shared with the given resource group.
* @param tgtRscGrp
* @param tgtLayerStack
* @param rg
* @return True if the template resource can be shared, else false.
*/
private boolean canShareTemplateForResourceGroup(
ResourceGroup tgtRscGrp, List<String> tgtLayerStack, ResourceGroup rg) {
List<String> rgLayerStack = rg.getSelectFilter() != null ?
rg.getSelectFilter().getLayerStack() : null;
return Objects.equals(tgtLayerStack, rgLayerStack) &&
Objects.equals(tgtRscGrp.getSelectFilter().getStoragePoolList(),
rg.getSelectFilter().getStoragePoolList());
}
/**
* Searches for a shareable template for this rscGrpName and sets the aux template property.
* @param api
* @param rscName
* @param rscGrpName
* @param existingRDs
* @return
* @throws ApiException
*/
private boolean foundShareableTemplate(
DevelopersApi api, String rscName, String rscGrpName,
List<Pair<ResourceDefinition, ResourceGroup>> existingRDs) throws ApiException {
if (!existingRDs.isEmpty()) {
ResourceGroup tgtRscGrp = api.resourceGroupList(
Collections.singletonList(rscGrpName), null, null, null).get(0);
List<String> tgtLayerStack = tgtRscGrp.getSelectFilter() != null ?
tgtRscGrp.getSelectFilter().getLayerStack() : null;
// check if there is already a template copy, that we could reuse
// this means if select filters are similar enough to allow cloning from
for (Pair<ResourceDefinition, ResourceGroup> rdPair : existingRDs) {
ResourceGroup rg = rdPair.second();
if (canShareTemplateForResourceGroup(tgtRscGrp, tgtLayerStack, rg)) {
LinstorUtil.setAuxTemplateForProperty(api, rscName, rscGrpName);
return true;
}
}
}
return false;
}
/**
* Creates a new Linstor resource.
* @param rscName
* @param sizeInBytes
* @param volName
* @param vmName
* @param api
* @param rscGrp
* @param poolId
* @param isTemplate indicates if the resource is a template
* @return true if a new resource was created, false if it already existed or was reused.
*/
private boolean createResourceBase(
String rscName, long sizeInBytes, String volName, String vmName,
@Nullable Long passPhraseId, @Nullable byte[] passPhrase, DevelopersApi api,
String rscGrp, long poolId, boolean isTemplate)
{
try try
{ {
logger.info("Linstor: Spawn resource " + rscName); logger.debug("createRscBase: {} :: {} :: {}", rscName, rscGrp, isTemplate);
ApiCallRcList answers = api.resourceGroupSpawn(rscGrp, rscGrpSpawn); List<Pair<ResourceDefinition, ResourceGroup>> existingRDs = LinstorUtil.getRDAndRGListStartingWith(api, rscName);
checkLinstorAnswersThrow(answers);
answers = LinstorUtil.applyAuxProps(api, rscName, volName, vmName); String fullRscName = String.format("%s-%d", rscName, poolId);
checkLinstorAnswersThrow(answers); boolean alreadyCreated = existingRDs.stream()
.anyMatch(p -> p.first().getName().equalsIgnoreCase(fullRscName)) ||
return LinstorUtil.getDevicePath(api, rscName); existingRDs.stream().anyMatch(p -> p.first().getProps().containsKey(LinstorUtil.getTemplateForAuxPropKey(rscGrp)));
if (!alreadyCreated) {
boolean createNewRsc = !foundShareableTemplate(api, rscName, rscGrp, existingRDs);
if (createNewRsc) {
String newRscName = existingRDs.isEmpty() ? rscName : fullRscName;
spawnResource(api, newRscName, sizeInBytes, isTemplate, rscGrp,
volName, vmName, passPhraseId, passPhrase);
}
return createNewRsc;
}
return false;
} catch (ApiException apiEx) } catch (ApiException apiEx)
{ {
logger.error("Linstor: ApiEx - " + apiEx.getMessage()); logger.error("Linstor: ApiEx - " + apiEx.getMessage());
@ -422,8 +580,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
final String rscGrp = getRscGrp(storagePoolVO); final String rscGrp = getRscGrp(storagePoolVO);
final String rscName = LinstorUtil.RSC_PREFIX + vol.getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + vol.getUuid();
String deviceName = createResourceBase( createResourceBase(
rscName, vol.getSize(), vol.getName(), vol.getAttachedVmName(), linstorApi, rscGrp); rscName, vol.getSize(), vol.getName(), vol.getAttachedVmName(), vol.getPassphraseId(), vol.getPassphrase(),
linstorApi, rscGrp, storagePoolVO.getId(), false);
try try
{ {
@ -450,20 +609,83 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
} }
} }
/**
* Update resource-definitions resource-group to the correct one if it isn't already the intended.
* @param api Linstor api
* @param rscName resource name to check the resource group
* @param tgtRscGrp resource group name to set
* @throws ApiException exception if any api error occurred
*/
private void updateRscGrpIfNecessary(DevelopersApi api, String rscName, String tgtRscGrp) throws ApiException {
List<ResourceDefinition> rscDfns = api.resourceDefinitionList(
Collections.singletonList(rscName), null, null, null);
if (rscDfns != null && !rscDfns.isEmpty()) {
ResourceDefinition rscDfn = rscDfns.get(0);
if (!rscDfn.getResourceGroupName().equalsIgnoreCase(tgtRscGrp)) {
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
rdm.setResourceGroup(tgtRscGrp);
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
if (answers.hasError()) {
String bestError = LinstorUtil.getBestErrorMessage(answers);
logger.error("Update resource group on {} error: {}", rscName, bestError);
throw new CloudRuntimeException(bestError);
} else {
logger.info("Successfully changed resource group to {} on {}", tgtRscGrp, rscName);
}
}
}
}
/**
* If a resource is cloned, all properties are cloned too, but the _cs-template-for properties,
* should only stay on the template resource, so delete them in this method.
* @param api
* @param rscName
* @throws ApiException
*/
private void deleteTemplateForProps(
DevelopersApi api, String rscName) throws ApiException {
List<ResourceDefinition> rdList = api.resourceDefinitionList(
Collections.singletonList(rscName), null, null, null);
if (CollectionUtils.isNotEmpty(rdList)) {
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
List<String> deleteProps = rdList.get(0).getProps().keySet().stream()
.filter(key -> key.startsWith("Aux/" + LinstorUtil.CS_TEMPLATE_FOR_PREFIX))
.collect(Collectors.toList());
rdm.deleteProps(deleteProps);
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
checkLinstorAnswers(answers);
}
}
private String cloneResource(long csCloneId, VolumeInfo volumeInfo, StoragePoolVO storagePoolVO) { private String cloneResource(long csCloneId, VolumeInfo volumeInfo, StoragePoolVO storagePoolVO) {
// get the cached template on this storage // get the cached template on this storage
VMTemplateStoragePoolVO tmplPoolRef = _vmTemplatePoolDao.findByPoolTemplate( VMTemplateStoragePoolVO tmplPoolRef = _vmTemplatePoolDao.findByPoolTemplate(
storagePoolVO.getId(), csCloneId, null); storagePoolVO.getId(), csCloneId, null);
if (tmplPoolRef != null) { if (tmplPoolRef != null) {
final String cloneRes = LinstorUtil.RSC_PREFIX + tmplPoolRef.getLocalDownloadPath(); final String templateRscName = LinstorUtil.RSC_PREFIX + tmplPoolRef.getLocalDownloadPath();
final String rscName = LinstorUtil.RSC_PREFIX + volumeInfo.getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + volumeInfo.getUuid();
final DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress()); final DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress());
try { try {
logger.info("Clone resource definition " + cloneRes + " to " + rscName); ResourceDefinition templateRD = LinstorUtil.findResourceDefinition(
linstorApi, templateRscName, getRscGrp(storagePoolVO));
final String cloneRes = templateRD != null ? templateRD.getName() : templateRscName;
logger.info("Clone resource definition {} to {}", cloneRes, rscName);
ResourceDefinitionCloneRequest cloneRequest = new ResourceDefinitionCloneRequest(); ResourceDefinitionCloneRequest cloneRequest = new ResourceDefinitionCloneRequest();
cloneRequest.setName(rscName); cloneRequest.setName(rscName);
if (volumeInfo.getPassphraseId() != null) {
List<LayerType> encryptionLayer = getEncryptedLayerList(linstorApi, getRscGrp(storagePoolVO));
cloneRequest.setLayerList(encryptionLayer);
if (volumeInfo.getPassphrase() != null) {
String utf8Passphrase = new String(volumeInfo.getPassphrase(), StandardCharsets.UTF_8);
cloneRequest.setVolumePassphrases(Collections.singletonList(utf8Passphrase));
}
}
ResourceDefinitionCloneStarted cloneStarted = linstorApi.resourceDefinitionClone( ResourceDefinitionCloneStarted cloneStarted = linstorApi.resourceDefinitionClone(
cloneRes, cloneRequest); cloneRes, cloneRequest);
@ -479,6 +701,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
resizeResource(linstorApi, rscName, volumeInfo.getSize()); resizeResource(linstorApi, rscName, volumeInfo.getSize());
} }
updateRscGrpIfNecessary(linstorApi, rscName, getRscGrp(storagePoolVO));
deleteTemplateForProps(linstorApi, rscName);
LinstorUtil.applyAuxProps(linstorApi, rscName, volumeInfo.getName(), volumeInfo.getAttachedVmName()); LinstorUtil.applyAuxProps(linstorApi, rscName, volumeInfo.getName(), volumeInfo.getAttachedVmName());
applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeInfo.getMaxIops()); applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeInfo.getMaxIops());
@ -906,19 +1131,50 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
return LinstorUtil.getDevicePath(api, restoredName); return LinstorUtil.getDevicePath(api, restoredName);
} }
/**
* Updates the template_spool_ref DB entry to indicate that this template was fully downloaded and is ready.
* @param templateId
* @param destTemplateInfoUuid
* @param destDataStoreId
* @param templateSize
*/
private void updateTemplateSpoolRef(
long templateId, String destTemplateInfoUuid, long destDataStoreId, long templateSize) {
VMTemplateStoragePoolVO destVolumeTemplateStoragePoolVO = _vmTemplatePoolDao.findByPoolTemplate(
destDataStoreId, templateId, null);
if (destVolumeTemplateStoragePoolVO == null) {
throw new CloudRuntimeException(
String.format("Unable to find template_spool_ref entry for pool_id %d and template_id %d",
destDataStoreId, templateId));
}
destVolumeTemplateStoragePoolVO.setDownloadPercent(100);
destVolumeTemplateStoragePoolVO.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
destVolumeTemplateStoragePoolVO.setState(ObjectInDataStoreStateMachine.State.Ready);
destVolumeTemplateStoragePoolVO.setTemplateSize(templateSize);
destVolumeTemplateStoragePoolVO.setLocalDownloadPath(destTemplateInfoUuid);
destVolumeTemplateStoragePoolVO.setInstallPath(destTemplateInfoUuid);
_vmTemplatePoolDao.persist(destVolumeTemplateStoragePoolVO);
}
private Answer copyTemplate(DataObject srcData, DataObject dstData) { private Answer copyTemplate(DataObject srcData, DataObject dstData) {
TemplateInfo tInfo = (TemplateInfo) dstData; TemplateInfo tInfo = (TemplateInfo) dstData;
final StoragePoolVO pool = _storagePoolDao.findById(dstData.getDataStore().getId()); final StoragePoolVO pool = _storagePoolDao.findById(dstData.getDataStore().getId());
final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress()); final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress());
final String rscName = LinstorUtil.RSC_PREFIX + dstData.getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + dstData.getUuid();
createResourceBase( boolean newCreated = createResourceBase(
LinstorUtil.RSC_PREFIX + dstData.getUuid(), LinstorUtil.RSC_PREFIX + dstData.getUuid(),
tInfo.getSize(), tInfo.getSize(),
tInfo.getName(), tInfo.getName(),
"", "",
null,
null,
api, api,
getRscGrp(pool)); getRscGrp(pool),
pool.getId(),
true);
Answer answer;
if (newCreated) {
int nMaxExecutionMinutes = NumbersUtil.parseInt( int nMaxExecutionMinutes = NumbersUtil.parseInt(
_configDao.getValue(Config.SecStorageCmdExecutionTimeMax.key()), 30); _configDao.getValue(Config.SecStorageCmdExecutionTimeMax.key()), 30);
CopyCommand cmd = new CopyCommand( CopyCommand cmd = new CopyCommand(
@ -926,14 +1182,12 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
dstData.getTO(), dstData.getTO(),
nMaxExecutionMinutes * 60 * 1000, nMaxExecutionMinutes * 60 * 1000,
VirtualMachineManager.ExecuteInSequence.value()); VirtualMachineManager.ExecuteInSequence.value());
Answer answer;
try { try {
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName); Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
if (optEP.isPresent()) { if (optEP.isPresent()) {
answer = optEP.get().sendMessage(cmd); answer = optEP.get().sendMessage(cmd);
} } else {
else {
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint."); answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
deleteResourceDefinition(pool, rscName); deleteResourceDefinition(pool, rscName);
} }
@ -942,6 +1196,10 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
deleteResourceDefinition(pool, rscName); deleteResourceDefinition(pool, rscName);
throw new CloudRuntimeException(exc.getBestMessage()); throw new CloudRuntimeException(exc.getBestMessage());
} }
} else {
updateTemplateSpoolRef(dstData.getId(), tInfo.getUuid(), dstData.getDataStore().getId(), srcData.getSize());
answer = new Answer(new CopyCmdAnswer(dstData.getTO()));
}
return answer; return answer;
} }

View File

@ -26,6 +26,7 @@ import com.linbit.linstor.api.model.Node;
import com.linbit.linstor.api.model.Properties; import com.linbit.linstor.api.model.Properties;
import com.linbit.linstor.api.model.ProviderKind; import com.linbit.linstor.api.model.ProviderKind;
import com.linbit.linstor.api.model.Resource; import com.linbit.linstor.api.model.Resource;
import com.linbit.linstor.api.model.ResourceDefinition;
import com.linbit.linstor.api.model.ResourceDefinitionModify; import com.linbit.linstor.api.model.ResourceDefinitionModify;
import com.linbit.linstor.api.model.ResourceGroup; import com.linbit.linstor.api.model.ResourceGroup;
import com.linbit.linstor.api.model.ResourceWithVolumes; import com.linbit.linstor.api.model.ResourceWithVolumes;
@ -37,8 +38,11 @@ import javax.annotation.Nonnull;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -49,6 +53,7 @@ public class LinstorUtil {
public final static String PROVIDER_NAME = "Linstor"; public final static String PROVIDER_NAME = "Linstor";
public static final String RSC_PREFIX = "cs-"; public static final String RSC_PREFIX = "cs-";
public static final String RSC_GROUP = "resourceGroup"; public static final String RSC_GROUP = "resourceGroup";
public static final String CS_TEMPLATE_FOR_PREFIX = "_cs-template-for-";
public static final String TEMP_VOLUME_ID = "tempVolumeId"; public static final String TEMP_VOLUME_ID = "tempVolumeId";
@ -288,4 +293,114 @@ public class LinstorUtil {
} }
return answers; return answers;
} }
/**
* Returns all resource definitions that start with the given `startWith` name.
* @param api
* @param startWith startWith String
* @return a List with all ResourceDefinition starting with `startWith`
* @throws ApiException
*/
public static List<ResourceDefinition> getRDListStartingWith(DevelopersApi api, String startWith)
throws ApiException
{
List<ResourceDefinition> rscDfns = api.resourceDefinitionList(null, null, null, null);
return rscDfns.stream()
.filter(rscDfn -> rscDfn.getName().toLowerCase().startsWith(startWith.toLowerCase()))
.collect(Collectors.toList());
}
/**
* Returns a pair list of resource-definitions with ther 1:1 mapped resource-group objects that start with the
* resource name `startWith`
* @param api
* @param startWith
* @return
* @throws ApiException
*/
public static List<Pair<ResourceDefinition, ResourceGroup>> getRDAndRGListStartingWith(DevelopersApi api, String startWith)
throws ApiException
{
List<ResourceDefinition> foundRDs = getRDListStartingWith(api, startWith);
List<String> rscGrpStrings = foundRDs.stream()
.map(ResourceDefinition::getResourceGroupName)
.collect(Collectors.toList());
Map<String, ResourceGroup> rscGrps = api.resourceGroupList(rscGrpStrings, null, null, null).stream()
.collect(Collectors.toMap(ResourceGroup::getName, rscGrp -> rscGrp));
return foundRDs.stream()
.map(rd -> new Pair<>(rd, rscGrps.get(rd.getResourceGroupName())))
.collect(Collectors.toList());
}
/**
* The full name of template-for aux property key.
* @param rscGrpName
* @return
*/
public static String getTemplateForAuxPropKey(String rscGrpName) {
return String.format("Aux/%s%s", CS_TEMPLATE_FOR_PREFIX, rscGrpName);
}
/**
* Template resource should have a _cs-template-for-... property, that indicates to which resource-group
* this template belongs, it works like a refcount to keep it alive if there are still such properties on the
* template resource. That methods set the correct property on the given resource.
* @param api
* @param rscName Resource name to set the property.
* @param rscGrpName Resource group this template should belong too.
* @throws ApiException
*/
public static void setAuxTemplateForProperty(DevelopersApi api, String rscName, String rscGrpName)
throws ApiException
{
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
Properties props = new Properties();
String propKey = LinstorUtil.getTemplateForAuxPropKey(rscGrpName);
props.put(propKey, "true");
rdm.setOverrideProps(props);
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
if (answers.hasError()) {
String bestError = LinstorUtil.getBestErrorMessage(answers);
LOGGER.error("Set {} on {} error: {}", propKey, rscName, bestError);
throw new CloudRuntimeException(bestError);
} else {
LOGGER.info("Set {} property on {}", propKey, rscName);
}
}
/**
* Find the correct resource definition to clone from.
* There could be multiple resource definitions for the same template, with the same prefix.
* This method searches for which resource group the resource definition was intended and returns that.
* If no exact resource definition could be found, we return the first with a similar name as a fallback.
* If there is not even one with the correct prefix, we return null.
* @param api
* @param rscName
* @param rscGrpName
* @return The resource-definition to clone from, if no template and no match, return null.
* @throws ApiException
*/
public static ResourceDefinition findResourceDefinition(DevelopersApi api, String rscName, String rscGrpName)
throws ApiException {
List<ResourceDefinition> rscDfns = api.resourceDefinitionList(null, null, null, null);
List<ResourceDefinition> rdsStartingWith = rscDfns.stream()
.filter(rscDfn -> rscDfn.getName().toLowerCase().startsWith(rscName.toLowerCase()))
.collect(Collectors.toList());
if (rdsStartingWith.isEmpty()) {
return null;
}
Optional<ResourceDefinition> rd = rdsStartingWith.stream()
.filter(rscDfn -> rscDfn.getProps().containsKey(LinstorUtil.getTemplateForAuxPropKey(rscGrpName)))
.findFirst();
return rd.orElseGet(() -> rdsStartingWith.get(0));
}
} }

View File

@ -0,0 +1,87 @@
// 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.datastore.driver;
import com.linbit.linstor.api.ApiException;
import com.linbit.linstor.api.DevelopersApi;
import com.linbit.linstor.api.model.AutoSelectFilter;
import com.linbit.linstor.api.model.LayerType;
import com.linbit.linstor.api.model.ResourceGroup;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LinstorPrimaryDataStoreDriverImplTest {
private DevelopersApi api;
@InjectMocks
private LinstorPrimaryDataStoreDriverImpl linstorPrimaryDataStoreDriver;
@Before
public void setUp() {
api = mock(DevelopersApi.class);
}
@Test
public void testGetEncryptedLayerList() throws ApiException {
ResourceGroup dfltRscGrp = new ResourceGroup();
dfltRscGrp.setName("DfltRscGrp");
ResourceGroup bCacheRscGrp = new ResourceGroup();
bCacheRscGrp.setName("BcacheGrp");
AutoSelectFilter asf = new AutoSelectFilter();
asf.setLayerStack(Arrays.asList(LayerType.DRBD.name(), LayerType.BCACHE.name(), LayerType.STORAGE.name()));
asf.setStoragePool("nvmePool");
bCacheRscGrp.setSelectFilter(asf);
ResourceGroup encryptedGrp = new ResourceGroup();
encryptedGrp.setName("EncryptedGrp");
AutoSelectFilter asf2 = new AutoSelectFilter();
asf2.setLayerStack(Arrays.asList(LayerType.DRBD.name(), LayerType.LUKS.name(), LayerType.STORAGE.name()));
asf2.setStoragePool("ssdPool");
encryptedGrp.setSelectFilter(asf2);
when(api.resourceGroupList(Collections.singletonList("DfltRscGrp"), Collections.emptyList(), null, null))
.thenReturn(Collections.singletonList(dfltRscGrp));
when(api.resourceGroupList(Collections.singletonList("BcacheGrp"), Collections.emptyList(), null, null))
.thenReturn(Collections.singletonList(bCacheRscGrp));
when(api.resourceGroupList(Collections.singletonList("EncryptedGrp"), Collections.emptyList(), null, null))
.thenReturn(Collections.singletonList(encryptedGrp));
List<LayerType> layers = linstorPrimaryDataStoreDriver.getEncryptedLayerList(api, "DfltRscGrp");
Assert.assertEquals(Arrays.asList(LayerType.DRBD, LayerType.LUKS, LayerType.STORAGE), layers);
layers = linstorPrimaryDataStoreDriver.getEncryptedLayerList(api, "BcacheGrp");
Assert.assertEquals(Arrays.asList(LayerType.DRBD, LayerType.BCACHE, LayerType.LUKS, LayerType.STORAGE), layers);
layers = linstorPrimaryDataStoreDriver.getEncryptedLayerList(api, "EncryptedGrp");
Assert.assertEquals(Arrays.asList(LayerType.DRBD, LayerType.LUKS, LayerType.STORAGE), layers);
}
}

View File

@ -0,0 +1,127 @@
// 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.datastore.util;
import com.linbit.linstor.api.ApiException;
import com.linbit.linstor.api.DevelopersApi;
import com.linbit.linstor.api.model.AutoSelectFilter;
import com.linbit.linstor.api.model.Node;
import com.linbit.linstor.api.model.Properties;
import com.linbit.linstor.api.model.ProviderKind;
import com.linbit.linstor.api.model.ResourceGroup;
import com.linbit.linstor.api.model.StoragePool;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LinstorUtilTest {
private static final String LINSTOR_URL_TEST = "devnull.com:3370";
private DevelopersApi api;
private Node mockNode(String name) {
Node nodeMock = new Node();
nodeMock.setName(name);
return nodeMock;
}
private StoragePool mockStoragePool(String name, String node, ProviderKind kind) {
StoragePool sp = new StoragePool();
sp.setStoragePoolName(name);
sp.setNodeName(node);
sp.setProviderKind(kind);
return sp;
}
@Before
public void setUp() throws ApiException {
api = mock(DevelopersApi.class);
when(api.nodeList(Collections.emptyList(), Collections.emptyList(), null, null))
.thenReturn(Arrays.asList(mockNode("nodeA"), mockNode("nodeB"), mockNode("nodeC")));
ResourceGroup csGroup = new ResourceGroup();
csGroup.setName("cloudstack");
AutoSelectFilter asf = new AutoSelectFilter();
asf.setPlaceCount(2);
csGroup.setSelectFilter(asf);
when(api.resourceGroupList(Collections.singletonList("cloudstack"), null, null, null))
.thenReturn(Collections.singletonList(csGroup));
when(api.viewStoragePools(Collections.emptyList(), null, null, null, null, true))
.thenReturn(Arrays.asList(
mockStoragePool("thinpool", "nodeA", ProviderKind.LVM_THIN),
mockStoragePool("thinpool", "nodeB", ProviderKind.LVM_THIN),
mockStoragePool("thinpool", "nodeC", ProviderKind.LVM_THIN)
));
// when(LinstorUtil.getLinstorAPI(LINSTOR_URL_TEST)).thenReturn(api);
}
@Test
public void testGetLinstorNodeNames() throws ApiException {
List<String> linstorNodes = LinstorUtil.getLinstorNodeNames(api);
Assert.assertEquals(Arrays.asList("nodeA", "nodeB", "nodeC"), linstorNodes);
}
@Test
public void testGetSnapshotPath() {
{
StoragePool spLVMThin = new StoragePool();
Properties lvmThinProps = new Properties();
lvmThinProps.put("StorDriver/StorPoolName", "storage/storage-thin");
spLVMThin.setProps(lvmThinProps);
spLVMThin.setProviderKind(ProviderKind.LVM_THIN);
String snapPath = LinstorUtil.getSnapshotPath(spLVMThin, "cs-cb32532a-dd8f-47e0-a81c-8a75573d3545", "snap3");
Assert.assertEquals("/dev/mapper/storage-cs--cb32532a--dd8f--47e0--a81c--8a75573d3545_00000_snap3", snapPath);
}
{
StoragePool spZFS = new StoragePool();
Properties zfsProps = new Properties();
zfsProps.put("StorDriver/StorPoolName", "linstorPool");
spZFS.setProps(zfsProps);
spZFS.setProviderKind(ProviderKind.ZFS);
String snapPath = LinstorUtil.getSnapshotPath(spZFS, "cs-cb32532a-dd8f-47e0-a81c-8a75573d3545", "snap2");
Assert.assertEquals("zfs://linstorPool/cs-cb32532a-dd8f-47e0-a81c-8a75573d3545_00000@snap2", snapPath);
}
}
@Test
public void testGetRscGroupStoragePools() throws ApiException {
List<StoragePool> storagePools = LinstorUtil.getRscGroupStoragePools(api, "cloudstack");
List<String> names = storagePools.stream()
.map(sp -> String.format("%s::%s", sp.getNodeName(), sp.getStoragePoolName()))
.collect(Collectors.toList());
Assert.assertEquals(names, Arrays.asList("nodeA::thinpool", "nodeB::thinpool", "nodeC::thinpool"));
}
}

View File

@ -146,16 +146,18 @@ public class PrimeraAdapter implements ProviderAdapter {
} }
// determine volume type based on offering // determine volume type based on offering
// THIN: tpvv=true, reduce=false // tpvv -- thin provisioned virtual volume (no deduplication)
// SPARSE: tpvv=true, reduce=true // reduce -- thin provisioned virtual volume (with duplication and compression, also known as DECO)
// THICK: tpvv=false, tpZeroFill=true (not supported) // these are the only choices with newer Primera devices
// we will use THIN for the deduplicated/compressed type and SPARSE for thin-only without dedup/compress
// note: DECO/reduce type must be at least 16GB in size
if (diskOffering != null) { if (diskOffering != null) {
if (diskOffering.getType() == ProvisioningType.THIN) { if (diskOffering.getType() == ProvisioningType.THIN) {
request.setTpvv(true);
request.setReduce(false);
} else if (diskOffering.getType() == ProvisioningType.SPARSE) {
request.setTpvv(false); request.setTpvv(false);
request.setReduce(true); request.setReduce(true);
} else if (diskOffering.getType() == ProvisioningType.SPARSE) {
request.setTpvv(true);
request.setReduce(false);
} else if (diskOffering.getType() == ProvisioningType.FAT) { } else if (diskOffering.getType() == ProvisioningType.FAT) {
throw new RuntimeException("This storage provider does not support FAT provisioned volumes"); throw new RuntimeException("This storage provider does not support FAT provisioned volumes");
} }
@ -166,8 +168,16 @@ public class PrimeraAdapter implements ProviderAdapter {
} }
} else { } else {
// default to deduplicated volume // default to deduplicated volume
request.setReduce(true);
request.setTpvv(false); request.setTpvv(false);
request.setReduce(true);
}
if (request.getReduce() == true) {
// check if sizeMiB is less than 16GB adjust up to 16GB. The AdaptiveDatastoreDriver will automatically
// update this on the cloudstack side to match
if (request.getSizeMiB() < 16 * 1024) {
request.setSizeMiB(16 * 1024);
}
} }
request.setComment(ProviderVolumeNamer.generateObjectComment(context, dataIn)); request.setComment(ProviderVolumeNamer.generateObjectComment(context, dataIn));
@ -185,8 +195,11 @@ public class PrimeraAdapter implements ProviderAdapter {
if (host == null) { if (host == null) {
throw new RuntimeException("Unable to find host " + hostname + " on storage provider"); throw new RuntimeException("Unable to find host " + hostname + " on storage provider");
} }
request.setHostname(host.getName());
// check if we already have a vlun for requested host
Integer vlun = hasVlun(hostname, hostname);
if (vlun == null) {
request.setHostname(host.getName());
request.setVolumeName(dataIn.getExternalName()); request.setVolumeName(dataIn.getExternalName());
request.setAutoLun(true); request.setAutoLun(true);
// auto-lun returned here: Location: /api/v1/vluns/test_vv02,252,mysystem,2:2:4 // auto-lun returned here: Location: /api/v1/vluns/test_vv02,252,mysystem,2:2:4
@ -198,7 +211,13 @@ public class PrimeraAdapter implements ProviderAdapter {
if (toks.length <2) { if (toks.length <2) {
throw new RuntimeException("Attach volume failed with invalid location response to vlun add command on storage provider. Provided location: " + location); throw new RuntimeException("Attach volume failed with invalid location response to vlun add command on storage provider. Provided location: " + location);
} }
return toks[1]; try {
vlun = Integer.parseInt(toks[1]);
} catch (NumberFormatException e) {
throw new RuntimeException("VLUN attach request succeeded but the VLUN value is not a valid number: " + toks[1]);
}
}
return vlun.toString();
} }
/** /**
@ -233,6 +252,20 @@ public class PrimeraAdapter implements ProviderAdapter {
} }
} }
private Integer hasVlun(String externalName, String hostname) {
PrimeraVlunList list = getVluns(externalName);
if (list != null && list.getMembers().size() > 0) {
for (PrimeraVlun vlun: list.getMembers()) {
if (hostname != null) {
if (vlun.getHostname().equals(hostname) || vlun.getHostname().equals(hostname.split("\\.")[0])) {
return vlun.getLun();
}
}
}
}
return null;
}
public void removeVlun(String name, Integer lunid, String hostString) { public void removeVlun(String name, Integer lunid, String hostString) {
// hostString can be a hostname OR "set:<hostsetname>". It is stored this way // hostString can be a hostname OR "set:<hostsetname>". It is stored this way
// in the appliance and returned as the vlun's name/string. // in the appliance and returned as the vlun's name/string.

View File

@ -175,7 +175,7 @@
<cs.nitro.version>10.1</cs.nitro.version> <cs.nitro.version>10.1</cs.nitro.version>
<cs.opensaml.version>2.6.6</cs.opensaml.version> <cs.opensaml.version>2.6.6</cs.opensaml.version>
<cs.rados-java.version>0.6.0</cs.rados-java.version> <cs.rados-java.version>0.6.0</cs.rados-java.version>
<cs.java-linstor.version>0.5.2</cs.java-linstor.version> <cs.java-linstor.version>0.6.0</cs.java-linstor.version>
<cs.reflections.version>0.10.2</cs.reflections.version> <cs.reflections.version>0.10.2</cs.reflections.version>
<cs.servicemix.version>3.4.4_1</cs.servicemix.version> <cs.servicemix.version>3.4.4_1</cs.servicemix.version>
<cs.servlet.version>4.0.1</cs.servlet.version> <cs.servlet.version>4.0.1</cs.servlet.version>

View File

@ -22,10 +22,18 @@
# #
############################################################################################# #############################################################################################
SCRIPT_NAME=$(basename "$0")
if [[ $(pgrep -f ${SCRIPT_NAME}) != "$$" ]]; then
echo "Another instance of ${SCRIPT_NAME} is already running! Exiting"
exit
fi
cd $(dirname $0) cd $(dirname $0)
for WWID in $(multipathd list maps status | awk '{ if ($4 == 0) { print substr($1,2); }}'); do for WWID in $(multipathd list maps status | awk '{ if ($4 == 0) { print substr($1,2); }}'); do
./removeVolume.sh ${WWID} ./disconnectVolume.sh ${WWID}
done done
exit 0 exit 0

View File

@ -66,6 +66,9 @@ fi
logger -t CS_SCSI_VOL_REMOVE "${WWID} successfully purged from multipath along with slave devices" logger -t CS_SCSI_VOL_REMOVE "${WWID} successfully purged from multipath along with slave devices"
# Added to give time for the event to be fired to the server
sleep 10
echo "$(date): ${WWID} removed" echo "$(date): ${WWID} removed"
exit 0 exit 0

View File

@ -356,263 +356,263 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
private static final String ID_FIELD = "id"; private static final String ID_FIELD = "id";
@Inject @Inject
private AccountManager accountMgr; AccountManager accountMgr;
@Inject @Inject
private ProjectManager _projectMgr; ProjectManager _projectMgr;
@Inject @Inject
private DomainDao _domainDao; DomainDao _domainDao;
@Inject @Inject
private DomainJoinDao _domainJoinDao; DomainJoinDao _domainJoinDao;
@Inject @Inject
private UserAccountJoinDao _userAccountJoinDao; UserAccountJoinDao _userAccountJoinDao;
@Inject @Inject
private EventDao eventDao; EventDao eventDao;
@Inject @Inject
private EventJoinDao _eventJoinDao; EventJoinDao _eventJoinDao;
@Inject @Inject
private ResourceTagJoinDao _resourceTagJoinDao; ResourceTagJoinDao _resourceTagJoinDao;
@Inject @Inject
private InstanceGroupJoinDao _vmGroupJoinDao; InstanceGroupJoinDao _vmGroupJoinDao;
@Inject @Inject
private UserVmJoinDao _userVmJoinDao; UserVmJoinDao _userVmJoinDao;
@Inject @Inject
private UserVmDao userVmDao; UserVmDao userVmDao;
@Inject @Inject
private VMInstanceDao _vmInstanceDao; VMInstanceDao _vmInstanceDao;
@Inject @Inject
private SecurityGroupJoinDao _securityGroupJoinDao; SecurityGroupJoinDao _securityGroupJoinDao;
@Inject @Inject
private SecurityGroupVMMapDao securityGroupVMMapDao; SecurityGroupVMMapDao securityGroupVMMapDao;
@Inject @Inject
private DomainRouterJoinDao _routerJoinDao; DomainRouterJoinDao _routerJoinDao;
@Inject @Inject
private ProjectInvitationJoinDao _projectInvitationJoinDao; ProjectInvitationJoinDao _projectInvitationJoinDao;
@Inject @Inject
private ProjectJoinDao _projectJoinDao; ProjectJoinDao _projectJoinDao;
@Inject @Inject
private ProjectDao _projectDao; ProjectDao _projectDao;
@Inject @Inject
private ProjectAccountDao _projectAccountDao; ProjectAccountDao _projectAccountDao;
@Inject @Inject
private ProjectAccountJoinDao _projectAccountJoinDao; ProjectAccountJoinDao _projectAccountJoinDao;
@Inject @Inject
private HostJoinDao hostJoinDao; HostJoinDao hostJoinDao;
@Inject @Inject
private VolumeJoinDao _volumeJoinDao; VolumeJoinDao _volumeJoinDao;
@Inject @Inject
private AccountDao _accountDao; AccountDao _accountDao;
@Inject @Inject
private AccountJoinDao _accountJoinDao; AccountJoinDao _accountJoinDao;
@Inject @Inject
private AsyncJobJoinDao _jobJoinDao; AsyncJobJoinDao _jobJoinDao;
@Inject @Inject
private StoragePoolJoinDao _poolJoinDao; StoragePoolJoinDao _poolJoinDao;
@Inject @Inject
private StoragePoolTagsDao _storageTagDao; StoragePoolTagsDao _storageTagDao;
@Inject @Inject
private HostTagsDao _hostTagDao; HostTagsDao _hostTagDao;
@Inject @Inject
private ImageStoreJoinDao _imageStoreJoinDao; ImageStoreJoinDao _imageStoreJoinDao;
@Inject @Inject
private DiskOfferingJoinDao _diskOfferingJoinDao; DiskOfferingJoinDao _diskOfferingJoinDao;
@Inject @Inject
private DiskOfferingDetailsDao _diskOfferingDetailsDao; DiskOfferingDetailsDao _diskOfferingDetailsDao;
@Inject @Inject
private ServiceOfferingJoinDao _srvOfferingJoinDao; ServiceOfferingJoinDao _srvOfferingJoinDao;
@Inject @Inject
private ServiceOfferingDao _srvOfferingDao; ServiceOfferingDao _srvOfferingDao;
@Inject @Inject
private ServiceOfferingDetailsDao _srvOfferingDetailsDao; ServiceOfferingDetailsDao _srvOfferingDetailsDao;
@Inject @Inject
private DiskOfferingDao _diskOfferingDao; DiskOfferingDao _diskOfferingDao;
@Inject @Inject
private DataCenterJoinDao _dcJoinDao; DataCenterJoinDao _dcJoinDao;
@Inject @Inject
private DomainRouterDao _routerDao; DomainRouterDao _routerDao;
@Inject @Inject
private HighAvailabilityManager _haMgr; HighAvailabilityManager _haMgr;
@Inject @Inject
private VMTemplateDao _templateDao; VMTemplateDao _templateDao;
@Inject @Inject
private TemplateJoinDao _templateJoinDao; TemplateJoinDao _templateJoinDao;
@Inject @Inject
private ResourceManager _resourceMgr; ResourceManager _resourceMgr;
@Inject @Inject
private ResourceMetaDataService _resourceMetaDataMgr; ResourceMetaDataService _resourceMetaDataMgr;
@Inject @Inject
private ResourceManagerUtil resourceManagerUtil; ResourceManagerUtil resourceManagerUtil;
@Inject @Inject
private AffinityGroupVMMapDao _affinityGroupVMMapDao; AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Inject @Inject
private AffinityGroupJoinDao _affinityGroupJoinDao; AffinityGroupJoinDao _affinityGroupJoinDao;
@Inject @Inject
private DedicatedResourceDao _dedicatedDao; DedicatedResourceDao _dedicatedDao;
@Inject @Inject
private DomainManager _domainMgr; DomainManager _domainMgr;
@Inject @Inject
private AffinityGroupDomainMapDao _affinityGroupDomainMapDao; AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
@Inject @Inject
private ResourceTagDao resourceTagDao; ResourceTagDao resourceTagDao;
@Inject @Inject
private DataStoreManager dataStoreManager; DataStoreManager dataStoreManager;
@Inject @Inject
ManagementServerJoinDao managementServerJoinDao; ManagementServerJoinDao managementServerJoinDao;
@Inject @Inject
public VpcVirtualNetworkApplianceService routerService; VpcVirtualNetworkApplianceService routerService;
@Inject @Inject
private ResponseGenerator responseGenerator; ResponseGenerator responseGenerator;
@Inject @Inject
private RouterHealthCheckResultDao routerHealthCheckResultDao; RouterHealthCheckResultDao routerHealthCheckResultDao;
@Inject @Inject
private PrimaryDataStoreDao storagePoolDao; PrimaryDataStoreDao storagePoolDao;
@Inject @Inject
private StoragePoolDetailsDao _storagePoolDetailsDao; StoragePoolDetailsDao _storagePoolDetailsDao;
@Inject @Inject
private ProjectInvitationDao projectInvitationDao; ProjectInvitationDao projectInvitationDao;
@Inject @Inject
private TemplateDataStoreDao templateDataStoreDao; TemplateDataStoreDao templateDataStoreDao;
@Inject @Inject
private VMTemplatePoolDao templatePoolDao; VMTemplatePoolDao templatePoolDao;
@Inject @Inject
private SnapshotDataStoreDao snapshotDataStoreDao; SnapshotDataStoreDao snapshotDataStoreDao;
@Inject @Inject
private UserDao userDao; UserDao userDao;
@Inject @Inject
private VirtualMachineManager virtualMachineManager; VirtualMachineManager virtualMachineManager;
@Inject @Inject
private VolumeDao volumeDao; VolumeDao volumeDao;
@Inject @Inject
private ResourceIconDao resourceIconDao; ResourceIconDao resourceIconDao;
@Inject @Inject
StorageManager storageManager; StorageManager storageManager;
@Inject @Inject
private ManagementServerHostDao msHostDao; ManagementServerHostDao msHostDao;
@Inject @Inject
private SecondaryStorageHeuristicDao secondaryStorageHeuristicDao; SecondaryStorageHeuristicDao secondaryStorageHeuristicDao;
@Inject @Inject
private NetworkDao networkDao; NetworkDao networkDao;
@Inject @Inject
private IPAddressDao ipAddressDao; IPAddressDao ipAddressDao;
@Inject @Inject
private NicDao nicDao; NicDao nicDao;
@Inject @Inject
private HostDao hostDao; HostDao hostDao;
@Inject @Inject
private OutOfBandManagementDao outOfBandManagementDao; OutOfBandManagementDao outOfBandManagementDao;
@Inject @Inject
private InstanceGroupVMMapDao instanceGroupVMMapDao; InstanceGroupVMMapDao instanceGroupVMMapDao;
@Inject @Inject
private AffinityGroupVMMapDao affinityGroupVMMapDao; AffinityGroupVMMapDao affinityGroupVMMapDao;
@Inject @Inject
private UserVmDetailsDao userVmDetailsDao; UserVmDetailsDao userVmDetailsDao;
@Inject @Inject
private SSHKeyPairDao sshKeyPairDao; SSHKeyPairDao sshKeyPairDao;
@Inject @Inject
private BackupOfferingDao backupOfferingDao; BackupOfferingDao backupOfferingDao;
@Inject @Inject
private AutoScaleVmGroupDao autoScaleVmGroupDao; AutoScaleVmGroupDao autoScaleVmGroupDao;
@Inject @Inject
private AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDao; AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDao;
@Inject @Inject
private SnapshotJoinDao snapshotJoinDao; SnapshotJoinDao snapshotJoinDao;
@Inject @Inject
private ObjectStoreDao objectStoreDao; ObjectStoreDao objectStoreDao;
@Inject @Inject
private BucketDao bucketDao; BucketDao bucketDao;
@Inject @Inject
EntityManager entityManager; EntityManager entityManager;
@Inject @Inject
private PublicIpQuarantineDao publicIpQuarantineDao; PublicIpQuarantineDao publicIpQuarantineDao;
@Inject @Inject
private StoragePoolHostDao storagePoolHostDao; StoragePoolHostDao storagePoolHostDao;
@Inject @Inject
private ClusterDao clusterDao; ClusterDao clusterDao;
@Inject @Inject
private ManagementServerHostPeerJoinDao mshostPeerJoinDao; ManagementServerHostPeerJoinDao mshostPeerJoinDao;
@Inject @Inject
private AsyncJobManager jobManager; private AsyncJobManager jobManager;
@ -666,7 +666,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<UserResponse> searchForUsers(ResponseView responseView, ListUsersCmd cmd) throws PermissionDeniedException { public ListResponse<UserResponse> searchForUsers(ResponseView responseView, ListUsersCmd cmd) throws PermissionDeniedException {
Pair<List<UserAccountJoinVO>, Integer> result = searchForUsersInternal(cmd); Pair<List<UserAccountJoinVO>, Integer> result = searchForUsersInternal(cmd);
ListResponse<UserResponse> response = new ListResponse<UserResponse>(); ListResponse<UserResponse> response = new ListResponse<>();
if (CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN) { if (CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN) {
responseView = ResponseView.Full; responseView = ResponseView.Full;
} }
@ -842,7 +842,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<EventResponse> searchForEvents(ListEventsCmd cmd) { public ListResponse<EventResponse> searchForEvents(ListEventsCmd cmd) {
Pair<List<EventJoinVO>, Integer> result = searchForEventsInternal(cmd); Pair<List<EventJoinVO>, Integer> result = searchForEventsInternal(cmd);
ListResponse<EventResponse> response = new ListResponse<EventResponse>(); ListResponse<EventResponse> response = new ListResponse<>();
List<EventResponse> eventResponses = ViewResponseHelper.createEventResponse(result.first().toArray(new EventJoinVO[result.first().size()])); List<EventResponse> eventResponses = ViewResponseHelper.createEventResponse(result.first().toArray(new EventJoinVO[result.first().size()]));
response.setResponses(eventResponses, result.second()); response.setResponses(eventResponses, result.second());
return response; return response;
@ -914,7 +914,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} }
} }
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second(); Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1005,7 +1005,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("archived", cmd.getArchived()); sc.setParameters("archived", cmd.getArchived());
} }
Pair<List<Long>, Integer> eventPair = null; Pair<List<Long>, Integer> eventPair;
// event_view will not have duplicate rows for each event, so // event_view will not have duplicate rows for each event, so
// searchAndCount should be good enough. // searchAndCount should be good enough.
if ((entryTime != null) && (duration != null)) { if ((entryTime != null) && (duration != null)) {
@ -1042,7 +1042,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<ResourceTagResponse> listTags(ListTagsCmd cmd) { public ListResponse<ResourceTagResponse> listTags(ListTagsCmd cmd) {
Pair<List<ResourceTagJoinVO>, Integer> tags = listTagsInternal(cmd); Pair<List<ResourceTagJoinVO>, Integer> tags = listTagsInternal(cmd);
ListResponse<ResourceTagResponse> response = new ListResponse<ResourceTagResponse>(); ListResponse<ResourceTagResponse> response = new ListResponse<>();
List<ResourceTagResponse> tagResponses = ViewResponseHelper.createResourceTagResponse(false, tags.first().toArray(new ResourceTagJoinVO[tags.first().size()])); List<ResourceTagResponse> tagResponses = ViewResponseHelper.createResourceTagResponse(false, tags.first().toArray(new ResourceTagJoinVO[tags.first().size()]));
response.setResponses(tagResponses, tags.second()); response.setResponses(tagResponses, tags.second());
return response; return response;
@ -1050,7 +1050,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
private Pair<List<ResourceTagJoinVO>, Integer> listTagsInternal(ListTagsCmd cmd) { private Pair<List<ResourceTagJoinVO>, Integer> listTagsInternal(ListTagsCmd cmd) {
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
String key = cmd.getKey(); String key = cmd.getKey();
String value = cmd.getValue(); String value = cmd.getValue();
String resourceId = cmd.getResourceId(); String resourceId = cmd.getResourceId();
@ -1070,7 +1070,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} }
} }
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), projectId, permittedAccounts, domainIdRecursiveListProject, listAll, false); accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), projectId, permittedAccounts, domainIdRecursiveListProject, listAll, false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();
@ -1122,14 +1122,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("customer", customerName); sc.setParameters("customer", customerName);
} }
Pair<List<ResourceTagJoinVO>, Integer> result = _resourceTagJoinDao.searchAndCount(sc, searchFilter); return _resourceTagJoinDao.searchAndCount(sc, searchFilter);
return result;
} }
@Override @Override
public ListResponse<InstanceGroupResponse> searchForVmGroups(ListVMGroupsCmd cmd) { public ListResponse<InstanceGroupResponse> searchForVmGroups(ListVMGroupsCmd cmd) {
Pair<List<InstanceGroupJoinVO>, Integer> groups = searchForVmGroupsInternal(cmd); Pair<List<InstanceGroupJoinVO>, Integer> groups = searchForVmGroupsInternal(cmd);
ListResponse<InstanceGroupResponse> response = new ListResponse<InstanceGroupResponse>(); ListResponse<InstanceGroupResponse> response = new ListResponse<>();
List<InstanceGroupResponse> grpResponses = ViewResponseHelper.createInstanceGroupResponse(groups.first().toArray(new InstanceGroupJoinVO[groups.first().size()])); List<InstanceGroupResponse> grpResponses = ViewResponseHelper.createInstanceGroupResponse(groups.first().toArray(new InstanceGroupJoinVO[groups.first().size()]));
response.setResponses(grpResponses, groups.second()); response.setResponses(grpResponses, groups.second());
return response; return response;
@ -1141,9 +1140,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
String keyword = cmd.getKeyword(); String keyword = cmd.getKeyword();
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second(); Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1337,7 +1336,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Filter searchFilter = new Filter(UserVmVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); Filter searchFilter = new Filter(UserVmVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
List<Long> ids = null; List<Long> ids;
if (cmd.getId() != null) { if (cmd.getId() != null) {
if (cmd.getIds() != null && !cmd.getIds().isEmpty()) { if (cmd.getIds() != null && !cmd.getIds().isEmpty()) {
throw new InvalidParameterValueException("Specify either id or ids but not both parameters"); throw new InvalidParameterValueException("Specify either id or ids but not both parameters");
@ -1703,7 +1702,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<SecurityGroupResponse> searchForSecurityGroups(ListSecurityGroupsCmd cmd) { public ListResponse<SecurityGroupResponse> searchForSecurityGroups(ListSecurityGroupsCmd cmd) {
Pair<List<SecurityGroupJoinVO>, Integer> result = searchForSecurityGroupsInternal(cmd); Pair<List<SecurityGroupJoinVO>, Integer> result = searchForSecurityGroupsInternal(cmd);
ListResponse<SecurityGroupResponse> response = new ListResponse<SecurityGroupResponse>(); ListResponse<SecurityGroupResponse> response = new ListResponse<>();
List<SecurityGroupResponse> routerResponses = ViewResponseHelper.createSecurityGroupResponses(result.first()); List<SecurityGroupResponse> routerResponses = ViewResponseHelper.createSecurityGroupResponses(result.first());
response.setResponses(routerResponses, result.second()); response.setResponses(routerResponses, result.second());
return response; return response;
@ -1715,7 +1714,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
String securityGroup = cmd.getSecurityGroupName(); String securityGroup = cmd.getSecurityGroupName();
Long id = cmd.getId(); Long id = cmd.getId();
Object keyword = cmd.getKeyword(); Object keyword = cmd.getKeyword();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
Map<String, String> tags = cmd.getTags(); Map<String, String> tags = cmd.getTags();
if (instanceId != null) { if (instanceId != null) {
@ -1727,7 +1726,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
return listSecurityGroupRulesByVM(instanceId.longValue(), cmd.getStartIndex(), cmd.getPageSizeVal()); return listSecurityGroupRulesByVM(instanceId.longValue(), cmd.getStartIndex(), cmd.getPageSizeVal());
} }
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second(); Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1786,7 +1785,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sgIds[i++] = v.getId(); sgIds[i++] = v.getId();
} }
List<SecurityGroupJoinVO> sgs = _securityGroupJoinDao.searchByIds(sgIds); List<SecurityGroupJoinVO> sgs = _securityGroupJoinDao.searchByIds(sgIds);
return new Pair<List<SecurityGroupJoinVO>, Integer>(sgs, count); return new Pair<>(sgs, count);
} }
private Pair<List<SecurityGroupJoinVO>, Integer> listSecurityGroupRulesByVM(long vmId, long pageInd, long pageSize) { private Pair<List<SecurityGroupJoinVO>, Integer> listSecurityGroupRulesByVM(long vmId, long pageInd, long pageSize) {
@ -1795,7 +1794,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = sgVmMappingPair.second(); Integer count = sgVmMappingPair.second();
if (count.intValue() == 0) { if (count.intValue() == 0) {
// handle empty result cases // handle empty result cases
return new Pair<List<SecurityGroupJoinVO>, Integer>(new ArrayList<SecurityGroupJoinVO>(), count); return new Pair<>(new ArrayList<>(), count);
} }
List<SecurityGroupVMMapVO> sgVmMappings = sgVmMappingPair.first(); List<SecurityGroupVMMapVO> sgVmMappings = sgVmMappingPair.first();
Long[] sgIds = new Long[sgVmMappings.size()]; Long[] sgIds = new Long[sgVmMappings.size()];
@ -1804,14 +1803,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sgIds[i++] = sgVm.getSecurityGroupId(); sgIds[i++] = sgVm.getSecurityGroupId();
} }
List<SecurityGroupJoinVO> sgs = _securityGroupJoinDao.searchByIds(sgIds); List<SecurityGroupJoinVO> sgs = _securityGroupJoinDao.searchByIds(sgIds);
return new Pair<List<SecurityGroupJoinVO>, Integer>(sgs, count); return new Pair<>(sgs, count);
} }
@Override @Override
public ListResponse<DomainRouterResponse> searchForRouters(ListRoutersCmd cmd) { public ListResponse<DomainRouterResponse> searchForRouters(ListRoutersCmd cmd) {
Pair<List<DomainRouterJoinVO>, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getClusterId(), Pair<List<DomainRouterJoinVO>, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), cmd.getState(), cmd.getZoneId(), cmd.getPodId(), cmd.getClusterId(),
cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getVersion(), cmd.isHealthCheckFailed()); cmd.getHostId(), cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), cmd.getVersion(), cmd.isHealthCheckFailed());
ListResponse<DomainRouterResponse> response = new ListResponse<DomainRouterResponse>(); ListResponse<DomainRouterResponse> response = new ListResponse<>();
List<DomainRouterResponse> routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); List<DomainRouterResponse> routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()]));
if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) { if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) {
for (DomainRouterResponse res : routerResponses) { for (DomainRouterResponse res : routerResponses) {
@ -1831,7 +1830,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
public ListResponse<DomainRouterResponse> searchForInternalLbVms(ListInternalLBVMsCmd cmd) { public ListResponse<DomainRouterResponse> searchForInternalLbVms(ListInternalLBVMsCmd cmd) {
Pair<List<DomainRouterJoinVO>, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), cmd.getState(), cmd.getZoneId(), cmd.getPodId(), null, cmd.getHostId(), Pair<List<DomainRouterJoinVO>, Integer> result = searchForRoutersInternal(cmd, cmd.getId(), cmd.getRouterName(), cmd.getState(), cmd.getZoneId(), cmd.getPodId(), null, cmd.getHostId(),
cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), null, null); cmd.getKeyword(), cmd.getNetworkId(), cmd.getVpcId(), cmd.getForVpc(), cmd.getRole(), null, null);
ListResponse<DomainRouterResponse> response = new ListResponse<DomainRouterResponse>(); ListResponse<DomainRouterResponse> response = new ListResponse<>();
List<DomainRouterResponse> routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()])); List<DomainRouterResponse> routerResponses = ViewResponseHelper.createDomainRouterResponse(result.first().toArray(new DomainRouterJoinVO[result.first().size()]));
if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) { if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) {
for (DomainRouterResponse res : routerResponses) { for (DomainRouterResponse res : routerResponses) {
@ -1852,9 +1851,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Long hostId, String keyword, Long networkId, Long vpcId, Boolean forVpc, String role, String version, Boolean isHealthCheckFailed) { Long hostId, String keyword, Long networkId, Long vpcId, Boolean forVpc, String role, String version, Boolean isHealthCheckFailed) {
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second(); Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1910,7 +1909,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sb.and("routerId", sb.entity().getId(), SearchCriteria.Op.NIN); sb.and("routerId", sb.entity().getId(), SearchCriteria.Op.NIN);
} }
} else if (isHealthCheckFailed) { } else if (isHealthCheckFailed) {
return new Pair<List<DomainRouterJoinVO>, Integer>(Collections.emptyList(), 0); return new Pair<>(Collections.emptyList(), 0);
} }
} }
@ -1990,13 +1989,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
vrIds[i++] = v.getId(); vrIds[i++] = v.getId();
} }
List<DomainRouterJoinVO> vrs = _routerJoinDao.searchByIds(vrIds); List<DomainRouterJoinVO> vrs = _routerJoinDao.searchByIds(vrIds);
return new Pair<List<DomainRouterJoinVO>, Integer>(vrs, count); return new Pair<>(vrs, count);
} }
@Override @Override
public ListResponse<ProjectResponse> listProjects(ListProjectsCmd cmd) { public ListResponse<ProjectResponse> listProjects(ListProjectsCmd cmd) {
Pair<List<ProjectJoinVO>, Integer> projects = listProjectsInternal(cmd); Pair<List<ProjectJoinVO>, Integer> projects = listProjectsInternal(cmd);
ListResponse<ProjectResponse> response = new ListResponse<ProjectResponse>(); ListResponse<ProjectResponse> response = new ListResponse<>();
List<ProjectResponse> projectResponses = ViewResponseHelper.createProjectResponse(cmd.getDetails(), projects.first().toArray(new ProjectJoinVO[projects.first().size()])); List<ProjectResponse> projectResponses = ViewResponseHelper.createProjectResponse(cmd.getDetails(), projects.first().toArray(new ProjectJoinVO[projects.first().size()]));
response.setResponses(projectResponses, projects.second()); response.setResponses(projectResponses, projects.second());
return response; return response;
@ -2164,13 +2163,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
prjIds[i++] = v.getId(); prjIds[i++] = v.getId();
} }
List<ProjectJoinVO> prjs = _projectJoinDao.searchByIds(prjIds); List<ProjectJoinVO> prjs = _projectJoinDao.searchByIds(prjIds);
return new Pair<List<ProjectJoinVO>, Integer>(prjs, count); return new Pair<>(prjs, count);
} }
@Override @Override
public ListResponse<ProjectInvitationResponse> listProjectInvitations(ListProjectInvitationsCmd cmd) { public ListResponse<ProjectInvitationResponse> listProjectInvitations(ListProjectInvitationsCmd cmd) {
Pair<List<ProjectInvitationJoinVO>, Integer> invites = listProjectInvitationsInternal(cmd); Pair<List<ProjectInvitationJoinVO>, Integer> invites = listProjectInvitationsInternal(cmd);
ListResponse<ProjectInvitationResponse> response = new ListResponse<ProjectInvitationResponse>(); ListResponse<ProjectInvitationResponse> response = new ListResponse<>();
List<ProjectInvitationResponse> projectInvitationResponses = ViewResponseHelper.createProjectInvitationResponse(invites.first().toArray(new ProjectInvitationJoinVO[invites.first().size()])); List<ProjectInvitationResponse> projectInvitationResponses = ViewResponseHelper.createProjectInvitationResponse(invites.first().toArray(new ProjectInvitationJoinVO[invites.first().size()]));
response.setResponses(projectInvitationResponses, invites.second()); response.setResponses(projectInvitationResponses, invites.second());
@ -2192,9 +2191,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
User callingUser = CallContext.current().getCallingUser(); User callingUser = CallContext.current().getCallingUser();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive, null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(domainId, isRecursive, null);
accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccounts, domainIdRecursiveListProject, listAll, true); accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccounts, domainIdRecursiveListProject, listAll, true);
domainId = domainIdRecursiveListProject.first(); domainId = domainIdRecursiveListProject.first();
isRecursive = domainIdRecursiveListProject.second(); isRecursive = domainIdRecursiveListProject.second();
@ -2246,7 +2245,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<ProjectAccountResponse> listProjectAccounts(ListProjectAccountsCmd cmd) { public ListResponse<ProjectAccountResponse> listProjectAccounts(ListProjectAccountsCmd cmd) {
Pair<List<ProjectAccountJoinVO>, Integer> projectAccounts = listProjectAccountsInternal(cmd); Pair<List<ProjectAccountJoinVO>, Integer> projectAccounts = listProjectAccountsInternal(cmd);
ListResponse<ProjectAccountResponse> response = new ListResponse<ProjectAccountResponse>(); ListResponse<ProjectAccountResponse> response = new ListResponse<>();
List<ProjectAccountResponse> projectResponses = ViewResponseHelper.createProjectAccountResponse(projectAccounts.first().toArray(new ProjectAccountJoinVO[projectAccounts.first().size()])); List<ProjectAccountResponse> projectResponses = ViewResponseHelper.createProjectAccountResponse(projectAccounts.first().toArray(new ProjectAccountJoinVO[projectAccounts.first().size()]));
response.setResponses(projectResponses, projectAccounts.second()); response.setResponses(projectResponses, projectAccounts.second());
return response; return response;
@ -2320,7 +2319,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// Right now it is handled separately outside this QueryService // Right now it is handled separately outside this QueryService
logger.debug(">>>Searching for hosts>>>"); logger.debug(">>>Searching for hosts>>>");
Pair<List<HostJoinVO>, Integer> hosts = searchForServersInternal(cmd); Pair<List<HostJoinVO>, Integer> hosts = searchForServersInternal(cmd);
ListResponse<HostResponse> response = new ListResponse<HostResponse>(); ListResponse<HostResponse> response = new ListResponse<>();
logger.debug(">>>Generating Response>>>"); logger.debug(">>>Generating Response>>>");
List<HostResponse> hostResponses = ViewResponseHelper.createHostResponse(cmd.getDetails(), hosts.first().toArray(new HostJoinVO[hosts.first().size()])); List<HostResponse> hostResponses = ViewResponseHelper.createHostResponse(cmd.getDetails(), hosts.first().toArray(new HostJoinVO[hosts.first().size()]));
response.setResponses(hostResponses, hosts.second()); response.setResponses(hostResponses, hosts.second());
@ -2741,7 +2740,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<DomainResponse> searchForDomains(ListDomainsCmd cmd) { public ListResponse<DomainResponse> searchForDomains(ListDomainsCmd cmd) {
Pair<List<DomainJoinVO>, Integer> result = searchForDomainsInternal(cmd); Pair<List<DomainJoinVO>, Integer> result = searchForDomainsInternal(cmd);
ListResponse<DomainResponse> response = new ListResponse<DomainResponse>(); ListResponse<DomainResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted; ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListDomainsCmdByAdmin) { if (cmd instanceof ListDomainsCmdByAdmin) {
@ -2843,7 +2842,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<AccountResponse> searchForAccounts(ListAccountsCmd cmd) { public ListResponse<AccountResponse> searchForAccounts(ListAccountsCmd cmd) {
Pair<List<AccountJoinVO>, Integer> result = searchForAccountsInternal(cmd); Pair<List<AccountJoinVO>, Integer> result = searchForAccountsInternal(cmd);
ListResponse<AccountResponse> response = new ListResponse<AccountResponse>(); ListResponse<AccountResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted; ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListAccountsCmdByAdmin) { if (cmd instanceof ListAccountsCmdByAdmin) {
@ -3029,7 +3028,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<AsyncJobResponse> searchForAsyncJobs(ListAsyncJobsCmd cmd) { public ListResponse<AsyncJobResponse> searchForAsyncJobs(ListAsyncJobsCmd cmd) {
Pair<List<AsyncJobJoinVO>, Integer> result = searchForAsyncJobsInternal(cmd); Pair<List<AsyncJobJoinVO>, Integer> result = searchForAsyncJobsInternal(cmd);
ListResponse<AsyncJobResponse> response = new ListResponse<AsyncJobResponse>(); ListResponse<AsyncJobResponse> response = new ListResponse<>();
List<AsyncJobResponse> jobResponses = ViewResponseHelper.createAsyncJobResponse(result.first().toArray(new AsyncJobJoinVO[result.first().size()])); List<AsyncJobResponse> jobResponses = ViewResponseHelper.createAsyncJobResponse(result.first().toArray(new AsyncJobJoinVO[result.first().size()]));
response.setResponses(jobResponses, result.second()); response.setResponses(jobResponses, result.second());
return response; return response;
@ -3039,9 +3038,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), null, permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), null, permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second(); Boolean isRecursive = domainIdRecursiveListProject.second();
@ -3201,7 +3200,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<StorageTagResponse> searchForStorageTags(ListStorageTagsCmd cmd) { public ListResponse<StorageTagResponse> searchForStorageTags(ListStorageTagsCmd cmd) {
Pair<List<StoragePoolTagVO>, Integer> result = searchForStorageTagsInternal(cmd); Pair<List<StoragePoolTagVO>, Integer> result = searchForStorageTagsInternal(cmd);
ListResponse<StorageTagResponse> response = new ListResponse<StorageTagResponse>(); ListResponse<StorageTagResponse> response = new ListResponse<>();
List<StorageTagResponse> tagResponses = ViewResponseHelper.createStorageTagResponse(result.first().toArray(new StoragePoolTagVO[result.first().size()])); List<StorageTagResponse> tagResponses = ViewResponseHelper.createStorageTagResponse(result.first().toArray(new StoragePoolTagVO[result.first().size()]));
response.setResponses(tagResponses, result.second()); response.setResponses(tagResponses, result.second());
@ -3236,13 +3235,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<StoragePoolTagVO> vrs = _storageTagDao.searchByIds(vrIds); List<StoragePoolTagVO> vrs = _storageTagDao.searchByIds(vrIds);
return new Pair<List<StoragePoolTagVO>, Integer>(vrs, count); return new Pair<>(vrs, count);
} }
@Override @Override
public ListResponse<HostTagResponse> searchForHostTags(ListHostTagsCmd cmd) { public ListResponse<HostTagResponse> searchForHostTags(ListHostTagsCmd cmd) {
Pair<List<HostTagVO>, Integer> result = searchForHostTagsInternal(cmd); Pair<List<HostTagVO>, Integer> result = searchForHostTagsInternal(cmd);
ListResponse<HostTagResponse> response = new ListResponse<HostTagResponse>(); ListResponse<HostTagResponse> response = new ListResponse<>();
List<HostTagResponse> tagResponses = ViewResponseHelper.createHostTagResponse(result.first().toArray(new HostTagVO[result.first().size()])); List<HostTagResponse> tagResponses = ViewResponseHelper.createHostTagResponse(result.first().toArray(new HostTagVO[result.first().size()]));
response.setResponses(tagResponses, result.second()); response.setResponses(tagResponses, result.second());
@ -3277,7 +3276,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<HostTagVO> vrs = _hostTagDao.searchByIds(vrIds); List<HostTagVO> vrs = _hostTagDao.searchByIds(vrIds);
return new Pair<List<HostTagVO>, Integer>(vrs, count); return new Pair<>(vrs, count);
} }
@Override @Override
@ -3360,14 +3359,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
vrIds[i++] = v.getId(); vrIds[i++] = v.getId();
} }
List<ImageStoreJoinVO> vrs = _imageStoreJoinDao.searchByIds(vrIds); List<ImageStoreJoinVO> vrs = _imageStoreJoinDao.searchByIds(vrIds);
return new Pair<List<ImageStoreJoinVO>, Integer>(vrs, count); return new Pair<>(vrs, count);
} }
@Override @Override
public ListResponse<ImageStoreResponse> searchForSecondaryStagingStores(ListSecondaryStagingStoresCmd cmd) { public ListResponse<ImageStoreResponse> searchForSecondaryStagingStores(ListSecondaryStagingStoresCmd cmd) {
Pair<List<ImageStoreJoinVO>, Integer> result = searchForCacheStoresInternal(cmd); Pair<List<ImageStoreJoinVO>, Integer> result = searchForCacheStoresInternal(cmd);
ListResponse<ImageStoreResponse> response = new ListResponse<ImageStoreResponse>(); ListResponse<ImageStoreResponse> response = new ListResponse<>();
List<ImageStoreResponse> poolResponses = ViewResponseHelper.createImageStoreResponse(result.first().toArray(new ImageStoreJoinVO[result.first().size()])); List<ImageStoreResponse> poolResponses = ViewResponseHelper.createImageStoreResponse(result.first().toArray(new ImageStoreJoinVO[result.first().size()]));
response.setResponses(poolResponses, result.second()); response.setResponses(poolResponses, result.second());
@ -3439,7 +3438,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
vrIds[i++] = v.getId(); vrIds[i++] = v.getId();
} }
List<ImageStoreJoinVO> vrs = _imageStoreJoinDao.searchByIds(vrIds); List<ImageStoreJoinVO> vrs = _imageStoreJoinDao.searchByIds(vrIds);
return new Pair<List<ImageStoreJoinVO>, Integer>(vrs, count); return new Pair<>(vrs, count);
} }
@ -4263,7 +4262,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<ZoneResponse> listDataCenters(ListZonesCmd cmd) { public ListResponse<ZoneResponse> listDataCenters(ListZonesCmd cmd) {
Pair<List<DataCenterJoinVO>, Integer> result = listDataCentersInternal(cmd); Pair<List<DataCenterJoinVO>, Integer> result = listDataCentersInternal(cmd);
ListResponse<ZoneResponse> response = new ListResponse<ZoneResponse>(); ListResponse<ZoneResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted; ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListZonesCmdByAdmin || CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN) { if (cmd instanceof ListZonesCmdByAdmin || CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN) {
@ -4350,7 +4349,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// list // list
// find all domain Id up to root domain for this account // find all domain Id up to root domain for this account
List<Long> domainIds = new ArrayList<Long>(); List<Long> domainIds = new ArrayList<>();
DomainVO domainRecord = _domainDao.findById(account.getDomainId()); DomainVO domainRecord = _domainDao.findById(account.getDomainId());
if (domainRecord == null) { if (domainRecord == null) {
logger.error("Could not find the domainId for account: {}", account); logger.error("Could not find the domainId for account: {}", account);
@ -4390,7 +4389,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// it was decided to return all zones for the domain admin, and // it was decided to return all zones for the domain admin, and
// everything above till root, as well as zones till the domain // everything above till root, as well as zones till the domain
// leaf // leaf
List<Long> domainIds = new ArrayList<Long>(); List<Long> domainIds = new ArrayList<>();
DomainVO domainRecord = _domainDao.findById(account.getDomainId()); DomainVO domainRecord = _domainDao.findById(account.getDomainId());
if (domainRecord == null) { if (domainRecord == null) {
logger.error("Could not find the domainId for account: {}", account); logger.error("Could not find the domainId for account: {}", account);
@ -4430,8 +4429,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// one VM running there // one VM running there
Boolean available = cmd.isAvailable(); Boolean available = cmd.isAvailable();
if (account != null) { if (account != null) {
if ((available != null) && Boolean.FALSE.equals(available)) { if (Boolean.FALSE.equals(available)) {
Set<Long> dcIds = new HashSet<Long>(); // data centers with Set<Long> dcIds = new HashSet<>(); // data centers with
// at least one VM // at least one VM
// running // running
List<DomainRouterVO> routers = _routerDao.listBy(account.getId()); List<DomainRouterVO> routers = _routerDao.listBy(account.getId());
@ -4439,7 +4438,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
dcIds.add(router.getDataCenterId()); dcIds.add(router.getDataCenterId());
} }
if (dcIds.size() == 0) { if (dcIds.size() == 0) {
return new Pair<List<DataCenterJoinVO>, Integer>(new ArrayList<DataCenterJoinVO>(), 0); return new Pair<>(new ArrayList<>(), 0);
} else { } else {
sc.addAnd("id", SearchCriteria.Op.IN, dcIds.toArray()); sc.addAnd("id", SearchCriteria.Op.IN, dcIds.toArray());
} }
@ -4463,7 +4462,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
private List<Long> removeDedicatedZoneNotSuitabe(List<Long> domainIds) { private List<Long> removeDedicatedZoneNotSuitabe(List<Long> domainIds) {
// remove dedicated zone of other domain // remove dedicated zone of other domain
List<Long> dedicatedZoneIds = new ArrayList<Long>(); List<Long> dedicatedZoneIds = new ArrayList<>();
List<DedicatedResourceVO> dedicatedResources = _dedicatedDao.listZonesNotInDomainIds(domainIds); List<DedicatedResourceVO> dedicatedResources = _dedicatedDao.listZonesNotInDomainIds(domainIds);
for (DedicatedResourceVO dr : dedicatedResources) { for (DedicatedResourceVO dr : dedicatedResources) {
if (dr != null) { if (dr != null) {
@ -4504,7 +4503,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override @Override
public ListResponse<TemplateResponse> listTemplates(ListTemplatesCmd cmd) { public ListResponse<TemplateResponse> listTemplates(ListTemplatesCmd cmd) {
Pair<List<TemplateJoinVO>, Integer> result = searchForTemplatesInternal(cmd); Pair<List<TemplateJoinVO>, Integer> result = searchForTemplatesInternal(cmd);
ListResponse<TemplateResponse> response = new ListResponse<TemplateResponse>(); ListResponse<TemplateResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted; ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListTemplatesCmdByAdmin) { if (cmd instanceof ListTemplatesCmdByAdmin) {
@ -4532,14 +4531,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
listAll = true; listAll = true;
} }
List<Long> permittedAccountIds = new ArrayList<Long>(); List<Long> permittedAccountIds = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters( accountMgr.buildACLSearchParameters(
caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccountIds, caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccountIds,
domainIdRecursiveListProject, listAll, false domainIdRecursiveListProject, listAll, false
); );
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
List<Account> permittedAccounts = new ArrayList<Account>(); List<Account> permittedAccounts = new ArrayList<>();
for (Long accountId : permittedAccountIds) { for (Long accountId : permittedAccountIds) {
permittedAccounts.add(accountMgr.getAccount(accountId)); permittedAccounts.add(accountMgr.getAccount(accountId));
} }
@ -4577,11 +4576,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (!isIso) { if (!isIso) {
hypers = _resourceMgr.listAvailHypervisorInZone(null); hypers = _resourceMgr.listAvailHypervisorInZone(null);
if (hypers == null || hypers.isEmpty()) { if (hypers == null || hypers.isEmpty()) {
return new Pair<List<TemplateJoinVO>, Integer>(new ArrayList<TemplateJoinVO>(), 0); return new Pair<>(new ArrayList<>(), 0);
} }
} }
VMTemplateVO template = null; VMTemplateVO template;
Filter searchFilter = new Filter(TemplateJoinVO.class, "sortKey", SortKeyAscending.value(), startIndex, pageSize); Filter searchFilter = new Filter(TemplateJoinVO.class, "sortKey", SortKeyAscending.value(), startIndex, pageSize);
searchFilter.addOrderBy(TemplateJoinVO.class, "tempZonePair", SortKeyAscending.value()); searchFilter.addOrderBy(TemplateJoinVO.class, "tempZonePair", SortKeyAscending.value());
@ -4652,7 +4651,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.addAnd("id", SearchCriteria.Op.EQ, templateId); sc.addAnd("id", SearchCriteria.Op.EQ, templateId);
} else { } else {
DomainVO domain = null; DomainVO domain;
if (!permittedAccounts.isEmpty()) { if (!permittedAccounts.isEmpty()) {
domain = _domainDao.findById(permittedAccounts.get(0).getDomainId()); domain = _domainDao.findById(permittedAccounts.get(0).getDomainId());
} else { } else {
@ -4674,15 +4673,15 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domain.getPath() + "%"); sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domain.getPath() + "%");
} }
List<Long> relatedDomainIds = new ArrayList<Long>(); List<Long> relatedDomainIds = new ArrayList<>();
List<Long> permittedAccountIds = new ArrayList<Long>(); List<Long> permittedAccountIds = new ArrayList<>();
if (!permittedAccounts.isEmpty()) { if (!permittedAccounts.isEmpty()) {
for (Account account : permittedAccounts) { for (Account account : permittedAccounts) {
permittedAccountIds.add(account.getId()); permittedAccountIds.add(account.getId());
boolean publicTemplates = (templateFilter == TemplateFilter.featured || templateFilter == TemplateFilter.community); boolean publicTemplates = (templateFilter == TemplateFilter.featured || templateFilter == TemplateFilter.community);
// get all parent domain ID's all the way till root domain // get all parent domain ID's all the way till root domain
DomainVO domainTreeNode = null; DomainVO domainTreeNode;
//if template filter is featured, or community, all child domains should be included in search //if template filter is featured, or community, all child domains should be included in search
if (publicTemplates) { if (publicTemplates) {
domainTreeNode = _domainDao.findById(Domain.ROOT_DOMAIN); domainTreeNode = _domainDao.findById(Domain.ROOT_DOMAIN);
@ -4913,7 +4912,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// sc.addAnd("removed", SearchCriteria.Op.NULL); // sc.addAnd("removed", SearchCriteria.Op.NULL);
// search unique templates and find details by Ids // search unique templates and find details by Ids
Pair<List<TemplateJoinVO>, Integer> uniqueTmplPair = null; Pair<List<TemplateJoinVO>, Integer> uniqueTmplPair;
if (showRemovedTmpl) { if (showRemovedTmpl) {
uniqueTmplPair = _templateJoinDao.searchIncludingRemovedAndCount(sc, searchFilter); uniqueTmplPair = _templateJoinDao.searchIncludingRemovedAndCount(sc, searchFilter);
} else { } else {
@ -4944,7 +4943,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
return templateDataPair; return templateDataPair;
} }
List<TemplateJoinVO> templateData = templateDataPair.first(); List<TemplateJoinVO> templateData = templateDataPair.first();
List<TemplateJoinVO> templates = null; List<TemplateJoinVO> templates;
if (showUnique) { if (showUnique) {
Long[] templateIds = templateData.stream().map(template -> template.getId()).toArray(Long[]::new); Long[] templateIds = templateData.stream().map(template -> template.getId()).toArray(Long[]::new);
templates = _templateJoinDao.findByDistinctIds(templateIds); templates = _templateJoinDao.findByDistinctIds(templateIds);
@ -4953,7 +4952,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
templates = _templateJoinDao.searchByTemplateZonePair(showRemoved, templateZonePairs); templates = _templateJoinDao.searchByTemplateZonePair(showRemoved, templateZonePairs);
} }
return new Pair<List<TemplateJoinVO>, Integer>(templates, count); return new Pair<>(templates, count);
} }
@Override @Override
@ -5074,7 +5073,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (HypervisorType.KVM.equals(hypervisorType)) { if (HypervisorType.KVM.equals(hypervisorType)) {
options.put(VmDetailConstants.CPU_THREAD_PER_CORE, Collections.emptyList()); options.put(VmDetailConstants.CPU_THREAD_PER_CORE, Collections.emptyList());
options.put(VmDetailConstants.NIC_ADAPTER, Arrays.asList("e1000", "virtio", "rtl8139", "vmxnet3", "ne2k_pci")); options.put(VmDetailConstants.NIC_ADAPTER, Arrays.asList("e1000", "virtio", "rtl8139", "vmxnet3", "ne2k_pci"));
options.put(VmDetailConstants.ROOT_DISK_CONTROLLER, Arrays.asList("osdefault", "ide", "scsi", "virtio")); options.put(VmDetailConstants.ROOT_DISK_CONTROLLER, Arrays.asList("osdefault", "ide", "scsi", "virtio", "virtio-blk"));
options.put(VmDetailConstants.VIDEO_HARDWARE, Arrays.asList("cirrus", "vga", "qxl", "virtio")); options.put(VmDetailConstants.VIDEO_HARDWARE, Arrays.asList("cirrus", "vga", "qxl", "virtio"));
options.put(VmDetailConstants.VIDEO_RAM, Collections.emptyList()); options.put(VmDetailConstants.VIDEO_RAM, Collections.emptyList());
options.put(VmDetailConstants.IO_POLICY, Arrays.asList("threads", "native", "io_uring", "storage_specific")); options.put(VmDetailConstants.IO_POLICY, Arrays.asList("threads", "native", "io_uring", "storage_specific"));
@ -5128,8 +5127,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
return listAffinityGroupsByVM(vmId.longValue(), startIndex, pageSize); return listAffinityGroupsByVM(vmId.longValue(), startIndex, pageSize);
} }
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> ternary = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive, null); Ternary<Long, Boolean, ListProjectResourcesCriteria> ternary = new Ternary<>(domainId, isRecursive, null);
accountMgr.buildACLSearchParameters(caller, affinityGroupId, accountName, projectId, permittedAccounts, ternary, listAll, false); accountMgr.buildACLSearchParameters(caller, affinityGroupId, accountName, projectId, permittedAccounts, ternary, listAll, false);
@ -5145,7 +5144,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc, searchFilter); Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc, searchFilter);
// search group details by ids // search group details by ids
List<AffinityGroupJoinVO> affinityGroups = new ArrayList<AffinityGroupJoinVO>(); List<AffinityGroupJoinVO> affinityGroups = new ArrayList<>();
Integer count = uniqueGroupsPair.second(); Integer count = uniqueGroupsPair.second();
if (count.intValue() != 0) { if (count.intValue() != 0) {
@ -5161,7 +5160,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (!permittedAccounts.isEmpty()) { if (!permittedAccounts.isEmpty()) {
// add domain level affinity groups // add domain level affinity groups
if (domainId != null) { if (domainId != null) {
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<>(), listProjectResourcesCriteria, affinityGroupId,
affinityGroupName, affinityGroupType, keyword); affinityGroupName, affinityGroupType, keyword);
Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, domainId); Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, domainId);
affinityGroups.addAll(groupsPair.first()); affinityGroups.addAll(groupsPair.first());
@ -5170,7 +5169,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
for (Long permAcctId : permittedAccounts) { for (Long permAcctId : permittedAccounts) {
Account permittedAcct = _accountDao.findById(permAcctId); Account permittedAcct = _accountDao.findById(permAcctId);
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<>(), listProjectResourcesCriteria, affinityGroupId,
affinityGroupName, affinityGroupType, keyword); affinityGroupName, affinityGroupType, keyword);
Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, permittedAcct.getDomainId()); Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, permittedAcct.getDomainId());
affinityGroups.addAll(groupsPair.first()); affinityGroups.addAll(groupsPair.first());
@ -5179,14 +5178,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} }
} else if (((permittedAccounts.isEmpty()) && (domainId != null) && isRecursive)) { } else if (((permittedAccounts.isEmpty()) && (domainId != null) && isRecursive)) {
// list all domain level affinity groups for the domain admin case // list all domain level affinity groups for the domain admin case
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, affinityGroupName, SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<>(), listProjectResourcesCriteria, affinityGroupId, affinityGroupName,
affinityGroupType, keyword); affinityGroupType, keyword);
Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, domainId); Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, domainId);
affinityGroups.addAll(groupsPair.first()); affinityGroups.addAll(groupsPair.first());
count += groupsPair.second(); count += groupsPair.second();
} }
return new Pair<List<AffinityGroupJoinVO>, Integer>(affinityGroups, count); return new Pair<>(affinityGroups, count);
} }
@ -5272,7 +5271,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = agVmMappingPair.second(); Integer count = agVmMappingPair.second();
if (count.intValue() == 0) { if (count.intValue() == 0) {
// handle empty result cases // handle empty result cases
return new Pair<List<AffinityGroupJoinVO>, Integer>(new ArrayList<AffinityGroupJoinVO>(), count); return new Pair<>(new ArrayList<>(), count);
} }
List<AffinityGroupVMMapVO> agVmMappings = agVmMappingPair.first(); List<AffinityGroupVMMapVO> agVmMappings = agVmMappingPair.first();
Long[] agIds = new Long[agVmMappings.size()]; Long[] agIds = new Long[agVmMappings.size()];
@ -5281,11 +5280,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
agIds[i++] = agVm.getAffinityGroupId(); agIds[i++] = agVm.getAffinityGroupId();
} }
List<AffinityGroupJoinVO> ags = _affinityGroupJoinDao.searchByIds(agIds); List<AffinityGroupJoinVO> ags = _affinityGroupJoinDao.searchByIds(agIds);
return new Pair<List<AffinityGroupJoinVO>, Integer>(ags, count); return new Pair<>(ags, count);
} }
private Pair<List<AffinityGroupJoinVO>, Integer> listDomainLevelAffinityGroups(SearchCriteria<AffinityGroupJoinVO> sc, Filter searchFilter, long domainId) { private Pair<List<AffinityGroupJoinVO>, Integer> listDomainLevelAffinityGroups(SearchCriteria<AffinityGroupJoinVO> sc, Filter searchFilter, long domainId) {
List<Long> affinityGroupIds = new ArrayList<Long>(); List<Long> affinityGroupIds = new ArrayList<>();
Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId); Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
List<AffinityGroupDomainMapVO> maps = _affinityGroupDomainMapDao.listByDomain(allowedDomains.toArray()); List<AffinityGroupDomainMapVO> maps = _affinityGroupDomainMapDao.listByDomain(allowedDomains.toArray());
@ -5308,7 +5307,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = uniqueGroupsPair.second(); Integer count = uniqueGroupsPair.second();
if (count.intValue() == 0) { if (count.intValue() == 0) {
// empty result // empty result
return new Pair<>(new ArrayList<AffinityGroupJoinVO>(), 0); return new Pair<>(new ArrayList<>(), 0);
} }
List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first(); List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
Long[] vrIds = new Long[uniqueGroups.size()]; Long[] vrIds = new Long[uniqueGroups.size()];
@ -5319,7 +5318,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<AffinityGroupJoinVO> vrs = _affinityGroupJoinDao.searchByIds(vrIds); List<AffinityGroupJoinVO> vrs = _affinityGroupJoinDao.searchByIds(vrIds);
return new Pair<>(vrs, count); return new Pair<>(vrs, count);
} else { } else {
return new Pair<>(new ArrayList<AffinityGroupJoinVO>(), 0); return new Pair<>(new ArrayList<>(), 0);
} }
} }
@ -5350,7 +5349,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} }
} }
List<? extends ResourceDetail> detailList = new ArrayList<ResourceDetail>(); List<? extends ResourceDetail> detailList = new ArrayList<>();
ResourceDetail requestedDetail = null; ResourceDetail requestedDetail = null;
if (key == null) { if (key == null) {
@ -5364,7 +5363,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
detailList = _resourceMetaDataMgr.getDetails(resourceType, key, value, forDisplay); detailList = _resourceMetaDataMgr.getDetails(resourceType, key, value, forDisplay);
} }
List<ResourceDetailResponse> responseList = new ArrayList<ResourceDetailResponse>(); List<ResourceDetailResponse> responseList = new ArrayList<>();
if (requestedDetail != null) { if (requestedDetail != null) {
ResourceDetailResponse detailResponse = createResourceDetailsResponse(requestedDetail, resourceType); ResourceDetailResponse detailResponse = createResourceDetailsResponse(requestedDetail, resourceType);
responseList.add(detailResponse); responseList.add(detailResponse);
@ -5431,7 +5430,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
mgmtResponse.setLastServerStart(mgmt.getLastJvmStart()); mgmtResponse.setLastServerStart(mgmt.getLastJvmStart());
mgmtResponse.setLastServerStop(mgmt.getLastJvmStop()); mgmtResponse.setLastServerStop(mgmt.getLastJvmStop());
mgmtResponse.setLastBoot(mgmt.getLastSystemBoot()); mgmtResponse.setLastBoot(mgmt.getLastSystemBoot());
mgmtResponse.setServiceIp(mgmt.getServiceIP());
if (listPeers) { if (listPeers) {
List<ManagementServerHostPeerJoinVO> peers = mshostPeerJoinDao.listByOwnerMshostId(mgmt.getId()); List<ManagementServerHostPeerJoinVO> peers = mshostPeerJoinDao.listByOwnerMshostId(mgmt.getId());
for (ManagementServerHostPeerJoinVO peer: peers) { for (ManagementServerHostPeerJoinVO peer: peers) {
@ -5440,6 +5438,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} }
mgmtResponse.setAgentsCount((long) hostDao.countByMs(mgmt.getMsid())); mgmtResponse.setAgentsCount((long) hostDao.countByMs(mgmt.getMsid()));
mgmtResponse.setPendingJobsCount(jobManager.countPendingNonPseudoJobs(mgmt.getMsid())); mgmtResponse.setPendingJobsCount(jobManager.countPendingNonPseudoJobs(mgmt.getMsid()));
mgmtResponse.setIpAddress(mgmt.getServiceIP());
mgmtResponse.setObjectName("managementserver"); mgmtResponse.setObjectName("managementserver");
return mgmtResponse; return mgmtResponse;
} }
@ -5616,7 +5615,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Filter searchFilter = new Filter(SnapshotJoinVO.class, "snapshotStorePair", SortKeyAscending.value(), startIndex, pageSize); Filter searchFilter = new Filter(SnapshotJoinVO.class, "snapshotStorePair", SortKeyAscending.value(), startIndex, pageSize);
List<Long> permittedAccountIds = new ArrayList<>(); List<Long> permittedAccountIds = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive, null); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(domainId, isRecursive, null);
accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccountIds, domainIdRecursiveListProject, listAll, false); accountMgr.buildACLSearchParameters(caller, id, accountName, projectId, permittedAccountIds, domainIdRecursiveListProject, listAll, false);
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
domainId = domainIdRecursiveListProject.first(); domainId = domainIdRecursiveListProject.first();
@ -5749,7 +5748,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = snapshotDataPair.second(); Integer count = snapshotDataPair.second();
if (count == 0) { if (count == 0) {
// empty result
return snapshotDataPair; return snapshotDataPair;
} }
List<SnapshotJoinVO> snapshotData = snapshotDataPair.first(); List<SnapshotJoinVO> snapshotData = snapshotDataPair.first();
@ -5759,13 +5757,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} else { } else {
snapshots = snapshotJoinDao.searchBySnapshotStorePair(snapshotData.stream().map(SnapshotJoinVO::getSnapshotStorePair).toArray(String[]::new)); snapshots = snapshotJoinDao.searchBySnapshotStorePair(snapshotData.stream().map(SnapshotJoinVO::getSnapshotStorePair).toArray(String[]::new));
} }
return new Pair<>(snapshots, count); return new Pair<>(snapshots, count);
} }
public ListResponse<ObjectStoreResponse> searchForObjectStores(ListObjectStoragePoolsCmd cmd) { public ListResponse<ObjectStoreResponse> searchForObjectStores(ListObjectStoragePoolsCmd cmd) {
Pair<List<ObjectStoreVO>, Integer> result = searchForObjectStoresInternal(cmd); Pair<List<ObjectStoreVO>, Integer> result = searchForObjectStoresInternal(cmd);
ListResponse<ObjectStoreResponse> response = new ListResponse<ObjectStoreResponse>(); ListResponse<ObjectStoreResponse> response = new ListResponse<>();
List<ObjectStoreResponse> poolResponses = ViewResponseHelper.createObjectStoreResponse(result.first().toArray(new ObjectStoreVO[result.first().size()])); List<ObjectStoreResponse> poolResponses = ViewResponseHelper.createObjectStoreResponse(result.first().toArray(new ObjectStoreVO[result.first().size()]));
response.setResponses(poolResponses, result.second()); response.setResponses(poolResponses, result.second());
@ -5850,7 +5847,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Long startIndex = cmd.getStartIndex(); Long startIndex = cmd.getStartIndex();
Long pageSize = cmd.getPageSizeVal(); Long pageSize = cmd.getPageSizeVal();
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>(); List<Long> permittedAccounts = new ArrayList<>();
// Verify parameters // Verify parameters
if (id != null) { if (id != null) {
@ -5862,7 +5859,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(),
cmd.isRecursive(), null); cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first(); Long domainId = domainIdRecursiveListProject.first();

View File

@ -23,10 +23,7 @@ import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.response.SnapshotResponse; import org.apache.cloudstack.api.response.SnapshotResponse;
import com.cloud.api.query.vo.SnapshotJoinVO; import com.cloud.api.query.vo.SnapshotJoinVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.SearchCriteria;
public interface SnapshotJoinDao extends GenericDao<SnapshotJoinVO, Long> { public interface SnapshotJoinDao extends GenericDao<SnapshotJoinVO, Long> {
@ -34,8 +31,7 @@ public interface SnapshotJoinDao extends GenericDao<SnapshotJoinVO, Long> {
SnapshotResponse setSnapshotResponse(SnapshotResponse snapshotResponse, SnapshotJoinVO snapshot); SnapshotResponse setSnapshotResponse(SnapshotResponse snapshotResponse, SnapshotJoinVO snapshot);
Pair<List<SnapshotJoinVO>, Integer> searchIncludingRemovedAndCount(final SearchCriteria<SnapshotJoinVO> sc, final Filter filter);
List<SnapshotJoinVO> searchBySnapshotStorePair(String... pairs); List<SnapshotJoinVO> searchBySnapshotStorePair(String... pairs);
List<SnapshotJoinVO> findByDistinctIds(Long zoneId, Long... ids); List<SnapshotJoinVO> findByDistinctIds(Long zoneId, Long... ids);
} }

View File

@ -18,6 +18,8 @@
package com.cloud.api.query.dao; package com.cloud.api.query.dao;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -34,6 +36,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.query.QueryService;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiDBUtils;
import com.cloud.api.ApiResponseHelper; import com.cloud.api.ApiResponseHelper;
import com.cloud.api.query.vo.SnapshotJoinVO; import com.cloud.api.query.vo.SnapshotJoinVO;
@ -44,7 +48,6 @@ import com.cloud.storage.Volume.Type;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter; import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
@ -53,11 +56,11 @@ import com.cloud.vm.VMInstanceVO;
public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<SnapshotJoinVO, SnapshotResponse> implements SnapshotJoinDao { public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<SnapshotJoinVO, SnapshotResponse> implements SnapshotJoinDao {
@Inject @Inject
private AccountService accountService; AccountService accountService;
@Inject @Inject
private AnnotationDao annotationDao; AnnotationDao annotationDao;
@Inject @Inject
private ConfigurationDao configDao; ConfigurationDao configDao;
@Inject @Inject
SnapshotDataFactory snapshotDataFactory; SnapshotDataFactory snapshotDataFactory;
@ -85,7 +88,7 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
if (snapshot.getDataCenterId() == null) { if (snapshot.getDataCenterId() == null) {
return; return;
} }
SnapshotInfo snapshotInfo = null; SnapshotInfo snapshotInfo;
snapshotInfo = snapshotDataFactory.getSnapshotWithRoleAndZone(snapshot.getId(), snapshot.getStoreRole(), snapshot.getDataCenterId()); snapshotInfo = snapshotDataFactory.getSnapshotWithRoleAndZone(snapshot.getId(), snapshot.getStoreRole(), snapshot.getDataCenterId());
if (snapshotInfo == null) { if (snapshotInfo == null) {
logger.debug("Unable to find info for image store snapshot {}", snapshot); logger.debug("Unable to find info for image store snapshot {}", snapshot);
@ -192,13 +195,6 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
return snapshotResponse; return snapshotResponse;
} }
@Override
public Pair<List<SnapshotJoinVO>, Integer> searchIncludingRemovedAndCount(final SearchCriteria<SnapshotJoinVO> sc, final Filter filter) {
List<SnapshotJoinVO> objects = searchIncludingRemoved(sc, filter, null, false);
Integer count = getDistinctCount(sc);
return new Pair<>(objects, count);
}
@Override @Override
public List<SnapshotJoinVO> searchBySnapshotStorePair(String... pairs) { public List<SnapshotJoinVO> searchBySnapshotStorePair(String... pairs) {
// set detail batch query size // set detail batch query size
@ -243,14 +239,33 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
return uvList; return uvList;
} }
protected List<SnapshotJoinVO> findById(Long zoneId, long id) {
SearchBuilder<SnapshotJoinVO> sb = createSearchBuilder();
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("zoneId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
sb.done();
SearchCriteria<SnapshotJoinVO> sc = sb.create();
sc.setParameters("id", id);
if (zoneId != null) {
sc.setParameters("zoneId", zoneId);
}
List<SnapshotJoinVO> snapshotJoinVOS = search(sc, null);
if (CollectionUtils.isEmpty(snapshotJoinVOS)) {
return null;
}
snapshotJoinVOS.sort(Comparator.comparing(SnapshotJoinVO::getSnapshotStorePair));
return Collections.singletonList(snapshotJoinVOS.get(0));
}
@Override @Override
public List<SnapshotJoinVO> findByDistinctIds(Long zoneId, Long... ids) { public List<SnapshotJoinVO> findByDistinctIds(Long zoneId, Long... ids) {
if (ids == null || ids.length == 0) { if (ids == null || ids.length == 0) {
return new ArrayList<>(); return new ArrayList<>();
} }
if (ids.length == 1) {
return findById(zoneId, ids[0]);
}
Filter searchFilter = new Filter(SnapshotJoinVO.class, "snapshotStorePair", QueryService.SortKeyAscending.value(), null, null); Filter searchFilter = new Filter(SnapshotJoinVO.class, "snapshotStorePair", QueryService.SortKeyAscending.value(), null, null);
SearchCriteria<SnapshotJoinVO> sc = snapshotIdsSearch.create(); SearchCriteria<SnapshotJoinVO> sc = snapshotIdsSearch.create();
if (zoneId != null) { if (zoneId != null) {
sc.setParameters("zoneId", zoneId); sc.setParameters("zoneId", zoneId);

View File

@ -506,7 +506,7 @@ public enum Config {
"The time interval in seconds when the management server polls for snapshots to be scheduled.", "The time interval in seconds when the management server polls for snapshots to be scheduled.",
null), null),
SnapshotDeltaMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.delta.max", "16", "max delta snapshots between two full snapshots.", null), SnapshotDeltaMax("Snapshots", SnapshotManager.class, Integer.class, "snapshot.delta.max", "16", "max delta snapshots between two full snapshots.", null),
KVMSnapshotEnabled("Hidden", SnapshotManager.class, Boolean.class, "kvm.snapshot.enabled", "false", "whether snapshot is enabled for KVM hosts", null), KVMSnapshotEnabled("Hidden", SnapshotManager.class, Boolean.class, "kvm.snapshot.enabled", "false", "Whether volume snapshot is enabled on running instances on a KVM host", null),
// Advanced // Advanced
EventPurgeInterval( EventPurgeInterval(
@ -665,8 +665,8 @@ public enum Config {
ManagementServer.class, ManagementServer.class,
String.class, String.class,
"hypervisor.list", "hypervisor.list",
HypervisorType.Hyperv + "," + HypervisorType.KVM + "," + HypervisorType.XenServer + "," + HypervisorType.VMware + "," + HypervisorType.BareMetal + "," + HypervisorType.KVM + "," + HypervisorType.VMware + "," + HypervisorType.XenServer + "," + HypervisorType.Hyperv + "," +
HypervisorType.Ovm + "," + HypervisorType.LXC + "," + HypervisorType.Ovm3, HypervisorType.BareMetal + "," + HypervisorType.Ovm + "," + HypervisorType.LXC + "," + HypervisorType.Ovm3,
"The list of hypervisors that this deployment will use.", "The list of hypervisors that this deployment will use.",
"hypervisorList", "hypervisorList",
ConfigKey.Kind.CSV, ConfigKey.Kind.CSV,

View File

@ -7225,10 +7225,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
sc.addAnd("id", SearchCriteria.Op.EQ, id); sc.addAnd("id", SearchCriteria.Op.EQ, id);
} }
if (tags != null) {
sc.addAnd("tags", SearchCriteria.Op.EQ, tags);
}
if (isTagged != null) { if (isTagged != null) {
if (isTagged) { if (isTagged) {
sc.addAnd("tags", SearchCriteria.Op.NNULL); sc.addAnd("tags", SearchCriteria.Op.NNULL);
@ -7237,6 +7233,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
} }
} }
if (tags != null) {
if (GuestType.Shared.name().equalsIgnoreCase(guestIpType)) {
SearchCriteria<NetworkOfferingJoinVO> tagsSc = networkOfferingJoinDao.createSearchCriteria();
tagsSc.addAnd("tags", SearchCriteria.Op.EQ, tags);
tagsSc.addOr("isDefault", SearchCriteria.Op.EQ, true);
sc.addAnd("tags", SearchCriteria.Op.SC, tagsSc);
} else {
sc.addAnd("tags", SearchCriteria.Op.EQ, tags);
}
}
if (zoneId != null) { if (zoneId != null) {
SearchBuilder<NetworkOfferingJoinVO> sb = networkOfferingJoinDao.createSearchBuilder(); SearchBuilder<NetworkOfferingJoinVO> sb = networkOfferingJoinDao.createSearchBuilder();
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.FIND_IN_SET); sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.FIND_IN_SET);

View File

@ -934,8 +934,12 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
@Override @Override
public UserDataServiceProvider getUserDataUpdateProvider(Network network) { public UserDataServiceProvider getUserDataUpdateProvider(Network network) {
String userDataProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData); if (network == null) {
logger.warn("No network details, can't fetch user data provider");
return null;
}
String userDataProvider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.UserData);
if (userDataProvider == null) { if (userDataProvider == null) {
logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName()); logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName());
return null; return null;

View File

@ -325,8 +325,12 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
try { try {
final Network network = _networkMgr.getNetwork(nic.getNetworkId()); final Network network = _networkMgr.getNetwork(nic.getNetworkId());
final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network); final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
if (userDataUpdateProvider == null) {
logger.warn("Failed to get user data provider");
return false;
}
final Provider provider = userDataUpdateProvider.getProvider(); final Provider provider = userDataUpdateProvider.getProvider();
if (provider.equals(Provider.ConfigDrive)) { if (Provider.ConfigDrive.equals(provider)) {
try { try {
return deleteConfigDriveIso(vm); return deleteConfigDriveIso(vm);
} catch (ResourceUnavailableException e) { } catch (ResourceUnavailableException e) {
@ -341,8 +345,13 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
@Override @Override
public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) { public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) {
if (_networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.ConfigDrive)) { final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
logger.trace(String.format("[prepareMigration] for vm: %s", vm)); if (userDataUpdateProvider == null) {
logger.warn("Failed to prepare for migration, can't get user data provider");
return false;
}
if (Provider.ConfigDrive.equals(userDataUpdateProvider.getProvider())) {
logger.trace(String.format("[prepareMigration] for vm: %s", vm.getInstanceName()));
try { try {
if (isConfigDriveIsoOnHostCache(vm.getId())) { if (isConfigDriveIsoOnHostCache(vm.getId())) {
vm.setConfigDriveLocation(Location.HOST); vm.setConfigDriveLocation(Location.HOST);
@ -392,7 +401,11 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
} }
private void recreateConfigDriveIso(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException { private void recreateConfigDriveIso(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException {
if (nic.isDefaultNic() && _networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.ConfigDrive)) { final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
if (userDataUpdateProvider == null) {
return;
}
if (nic.isDefaultNic() && Provider.ConfigDrive.equals(userDataUpdateProvider.getProvider())) {
DiskTO diskToUse = null; DiskTO diskToUse = null;
for (DiskTO disk : vm.getDisks()) { for (DiskTO disk : vm.getDisks()) {
if (disk.getType() == Volume.Type.ISO && disk.getPath() != null && disk.getPath().contains("configdrive")) { if (disk.getType() == Volume.Type.ISO && disk.getPath() != null && disk.getPath().contains("configdrive")) {

View File

@ -769,7 +769,12 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
@Override @Override
public boolean saveHypervisorHostname(NicProfile nicProfile, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException { public boolean saveHypervisorHostname(NicProfile nicProfile, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException {
if (_networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.VirtualRouter) && vm.getVirtualMachine().getType() == VirtualMachine.Type.User) { final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
if (userDataUpdateProvider == null) {
logger.warn("Failed to update hypervisor host details, can't get user data provider");
return false;
}
if (Provider.VirtualRouter.equals(userDataUpdateProvider.getProvider()) && vm.getVirtualMachine().getType() == VirtualMachine.Type.User) {
VirtualMachine uvm = vm.getVirtualMachine(); VirtualMachine uvm = vm.getVirtualMachine();
UserVmVO destVm = _userVmDao.findById(uvm.getId()); UserVmVO destVm = _userVmDao.findById(uvm.getId());
VirtualMachineProfile profile = null; VirtualMachineProfile profile = null;

View File

@ -343,7 +343,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
private void validatePrerequisiteVpnGateway(Site2SiteVpnGateway vpnGateway) { private void validatePrerequisiteVpnGateway(Site2SiteVpnGateway vpnGateway) {
// check if gateway has been defined on the VPC // check if gateway has been defined on the VPC
if (_vpnGatewayDao.findByVpcId(vpnGateway.getVpcId()) == null) { if (_vpnGatewayDao.findByVpcId(vpnGateway.getVpcId()) == null) {
throw new InvalidParameterValueException("we can not create a VPN connection for a VPC that does not have a VPN gateway defined"); throw new InvalidParameterValueException("We can not create a VPN connection for a VPC that does not have a VPN gateway defined");
} }
} }
@ -590,7 +590,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
private void stopVpnConnection(Long id) throws ResourceUnavailableException { private void stopVpnConnection(Long id) throws ResourceUnavailableException {
Site2SiteVpnConnectionVO conn = _vpnConnectionDao.acquireInLockTable(id); Site2SiteVpnConnectionVO conn = _vpnConnectionDao.acquireInLockTable(id);
if (conn == null) { if (conn == null) {
throw new CloudRuntimeException("Unable to acquire lock for stopping of VPN connection with ID " + id); throw new CloudRuntimeException("Unable to acquire lock for stopping VPN connection with ID " + id);
} }
try { try {
if (conn.getState() == State.Pending) { if (conn.getState() == State.Pending) {

View File

@ -3622,8 +3622,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
templateVO = _templateStoreDao.findByStoreTemplate(store.getId(), templateId); templateVO = _templateStoreDao.findByStoreTemplate(store.getId(), templateId);
if (templateVO != null) { if (templateVO != null) {
try { try {
if (SystemVmTemplateRegistration.validateIfSeeded( if (systemVmTemplateRegistration.validateIfSeeded(
url, templateVO.getInstallPath(), nfsVersion)) { templateVO, url, templateVO.getInstallPath(), nfsVersion)) {
continue; continue;
} }
} catch (Exception e) { } catch (Exception e) {

View File

@ -2484,10 +2484,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
return existingVolumeOfVm; return existingVolumeOfVm;
} }
protected StoragePool getPoolForAllocatedOrUploadedVolumeForAttach(final VolumeInfo volumeToAttach, final UserVmVO vm) { protected StoragePool getSuitablePoolForAllocatedOrUploadedVolumeForAttach(final VolumeInfo volumeToAttach, final UserVmVO vm) {
DataCenter zone = _dcDao.findById(vm.getDataCenterId()); DataCenter zone = _dcDao.findById(vm.getDataCenterId());
Pair<Long, Long> clusterHostId = virtualMachineManager.findClusterAndHostIdForVm(vm, false); Pair<Long, Long> clusterHostId = virtualMachineManager.findClusterAndHostIdForVm(vm, false);
long podId = vm.getPodIdToDeployIn(); Long podId = vm.getPodIdToDeployIn();
if (clusterHostId.first() != null) { if (clusterHostId.first() != null) {
Cluster cluster = clusterDao.findById(clusterHostId.first()); Cluster cluster = clusterDao.findById(clusterHostId.first());
podId = cluster.getPodId(); podId = cluster.getPodId();
@ -2499,12 +2499,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
offering.isUseLocalStorage(), offering.isRecreatable(), offering.isUseLocalStorage(), offering.isRecreatable(),
volumeToAttach.getTemplateId()); volumeToAttach.getTemplateId());
diskProfile.setHyperType(vm.getHypervisorType()); diskProfile.setHyperType(vm.getHypervisorType());
StoragePool pool = _volumeMgr.findStoragePool(diskProfile, zone, pod, clusterHostId.first(), return _volumeMgr.findStoragePool(diskProfile, zone, pod, clusterHostId.first(),
clusterHostId.second(), vm, Collections.emptySet()); clusterHostId.second(), vm, Collections.emptySet());
if (pool == null) {
throw new CloudRuntimeException(String.format("Failed to find a primary storage for volume in state: %s", volumeToAttach.getState()));
}
return pool;
} }
protected VolumeInfo createVolumeOnPrimaryForAttachIfNeeded(final VolumeInfo volumeToAttach, final UserVmVO vm, VolumeVO existingVolumeOfVm) { protected VolumeInfo createVolumeOnPrimaryForAttachIfNeeded(final VolumeInfo volumeToAttach, final UserVmVO vm, VolumeVO existingVolumeOfVm) {
@ -2522,7 +2518,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
} }
} }
if (destPrimaryStorage == null) { if (destPrimaryStorage == null) {
destPrimaryStorage = getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); destPrimaryStorage = getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
if (destPrimaryStorage == null) {
if (Volume.State.Allocated.equals(volumeToAttach.getState()) && State.Stopped.equals(vm.getState())) {
return newVolumeOnPrimaryStorage;
}
throw new CloudRuntimeException(String.format("Failed to find a primary storage for volume in state: %s", volumeToAttach.getState()));
}
} }
try { try {
if (volumeOnSecondary && Storage.StoragePoolType.PowerFlex.equals(destPrimaryStorage.getPoolType())) { if (volumeOnSecondary && Storage.StoragePoolType.PowerFlex.equals(destPrimaryStorage.getPoolType())) {

View File

@ -498,8 +498,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (apiNameList == null) { if (apiNameList == null) {
long startTime = System.nanoTime(); long startTime = System.nanoTime();
apiNameList = new ArrayList<String>(); apiNameList = new ArrayList<>();
Set<Class<?>> cmdClasses = new LinkedHashSet<Class<?>>(); Set<Class<?>> cmdClasses = new LinkedHashSet<>();
for (PluggableService service : services) { for (PluggableService service : services) {
logger.debug(String.format("getting api commands of service: %s", service.getClass().getName())); logger.debug(String.format("getting api commands of service: %s", service.getClass().getName()));
cmdClasses.addAll(service.getCommands()); cmdClasses.addAll(service.getCommands());
@ -513,7 +513,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
protected List<String> createApiNameList(Set<Class<?>> cmdClasses) { protected List<String> createApiNameList(Set<Class<?>> cmdClasses) {
List<String> apiNameList = new ArrayList<String>(); List<String> apiNameList = new ArrayList<>();
for (Class<?> cmdClass : cmdClasses) { for (Class<?> cmdClass : cmdClasses) {
APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class); APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class);
@ -698,7 +698,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return; return;
} }
HashMap<Long, List<ControlledEntity>> domains = new HashMap<Long, List<ControlledEntity>>(); HashMap<Long, List<ControlledEntity>> domains = new HashMap<>();
for (ControlledEntity entity : entities) { for (ControlledEntity entity : entities) {
long domainId = entity.getDomainId(); long domainId = entity.getDomainId();
@ -713,7 +713,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId()); List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId());
// for templates, we don't have to do cross domains check // for templates, we don't have to do cross domains check
if (toBeChecked == null) { if (toBeChecked == null) {
toBeChecked = new ArrayList<ControlledEntity>(); toBeChecked = new ArrayList<>();
domains.put(domainId, toBeChecked); domains.put(domainId, toBeChecked);
} }
toBeChecked.add(entity); toBeChecked.add(entity);
@ -722,7 +722,11 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
for (SecurityChecker checker : _securityCheckers) { for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(caller, entity, accessType, apiName)) { if (checker.checkAccess(caller, entity, accessType, apiName)) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Access to " + entity + " granted to " + caller + " by " + checker.getName()); User user = CallContext.current().getCallingUser();
String userName = "";
if (user != null)
userName = user.getUsername();
logger.debug("Access to {} granted to {} by {} on behalf of user {}", entity, caller, checker.getName(), userName);
} }
granted = true; granted = true;
break; break;
@ -1023,12 +1027,12 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
logger.debug("Deleting networks for account {}", account); logger.debug("Deleting networks for account {}", account);
List<NetworkVO> networks = _networkDao.listByOwner(accountId); List<NetworkVO> networks = _networkDao.listByOwner(accountId);
if (networks != null) { if (networks != null) {
Collections.sort(networks, new Comparator<NetworkVO>() { Collections.sort(networks, new Comparator<>() {
@Override @Override
public int compare(NetworkVO network1, NetworkVO network2) { public int compare(NetworkVO network1, NetworkVO network2) {
if (network1.getGuestType() != network2.getGuestType() && Network.GuestType.Isolated.equals(network2.getGuestType())) { if (network1.getGuestType() != network2.getGuestType() && Network.GuestType.Isolated.equals(network2.getGuestType())) {
return -1; return -1;
}; }
return 1; return 1;
} }
}); });
@ -1300,7 +1304,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
final String accountNameFinal = accountName; final String accountNameFinal = accountName;
final Long domainIdFinal = domainId; final Long domainIdFinal = domainId;
final String accountUUIDFinal = accountUUID; final String accountUUIDFinal = accountUUID;
Pair<Long, Account> pair = Transaction.execute(new TransactionCallback<Pair<Long, Account>>() { Pair<Long, Account> pair = Transaction.execute(new TransactionCallback<>() {
@Override @Override
public Pair<Long, Account> doInTransaction(TransactionStatus status) { public Pair<Long, Account> doInTransaction(TransactionStatus status) {
// create account // create account
@ -1323,7 +1327,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
user.setRegistrationToken(registrationToken); user.setRegistrationToken(registrationToken);
} }
return new Pair<Long, Account>(user.getId(), account); return new Pair<>(user.getId(), account);
} }
}); });
@ -1332,7 +1336,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
// create correct account and group association based on accountType // create correct account and group association based on accountType
if (accountType != Account.Type.PROJECT) { if (accountType != Account.Type.PROJECT) {
Map<Long, Long> accountGroupMap = new HashMap<Long, Long>(); Map<Long, Long> accountGroupMap = new HashMap<>();
accountGroupMap.put(account.getId(), (long) (accountType.ordinal() + 1)); accountGroupMap.put(account.getId(), (long) (accountType.ordinal() + 1));
_messageBus.publish(_name, MESSAGE_ADD_ACCOUNT_EVENT, PublishScope.LOCAL, accountGroupMap); _messageBus.publish(_name, MESSAGE_ADD_ACCOUNT_EVENT, PublishScope.LOCAL, accountGroupMap);
} }
@ -1476,7 +1480,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) { if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
throw new CloudRuntimeException(String.format("The user %s already exists in domain %s", userName, domain)); throw new CloudRuntimeException(String.format("The user %s already exists in domain %s", userName, domain));
} }
UserVO user = null; UserVO user;
user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone, userUUID, source); user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone, userUUID, source);
return user; return user;
} }
@ -1731,7 +1735,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
Long callingUserId = CallContext.current().getCallingUserId(); Long callingUserId = CallContext.current().getCallingUserId();
Account callingAccount = CallContext.current().getCallingAccount(); Account callingAccount = CallContext.current().getCallingAccount();
ActionEventUtils.onActionEvent(callingUserId, callingAccount.getAccountId(), callingAccount.getDomainId(), ActionEventUtils.onActionEvent(callingUserId, callingAccount.getAccountId(), callingAccount.getDomainId(),
EventTypes.API_KEY_ACCESS_UPDATE, "Api key access was changed for the User to " + access.toString(), EventTypes.API_KEY_ACCESS_UPDATE, "Api key access was changed for the User to " + access,
user.getId(), ApiCommandResourceType.User.toString()); user.getId(), ApiCommandResourceType.User.toString());
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
throw new InvalidParameterValueException("ApiKeyAccess value can only be Enabled/Disabled/Inherit"); throw new InvalidParameterValueException("ApiKeyAccess value can only be Enabled/Disabled/Inherit");
@ -1747,7 +1751,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
Long callingUserId = CallContext.current().getCallingUserId(); Long callingUserId = CallContext.current().getCallingUserId();
Account callingAccount = CallContext.current().getCallingAccount(); Account callingAccount = CallContext.current().getCallingAccount();
ActionEventUtils.onActionEvent(callingUserId, callingAccount.getAccountId(), callingAccount.getDomainId(), ActionEventUtils.onActionEvent(callingUserId, callingAccount.getAccountId(), callingAccount.getDomainId(),
EventTypes.API_KEY_ACCESS_UPDATE, "Api key access was changed for the Account to " + access.toString(), EventTypes.API_KEY_ACCESS_UPDATE, "Api key access was changed for the Account to " + access,
account.getId(), ApiCommandResourceType.Account.toString()); account.getId(), ApiCommandResourceType.Account.toString());
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
throw new InvalidParameterValueException("ApiKeyAccess value can only be Enabled/Disabled/Inherit"); throw new InvalidParameterValueException("ApiKeyAccess value can only be Enabled/Disabled/Inherit");
@ -1837,7 +1841,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
checkAccess(caller, AccessType.OperateEntry, true, account); checkAccess(caller, AccessType.OperateEntry, true, account);
boolean success = Transaction.execute(new TransactionCallback<Boolean>() { boolean success = Transaction.execute(new TransactionCallback<>() {
@Override @Override
public Boolean doInTransaction(TransactionStatus status) { public Boolean doInTransaction(TransactionStatus status) {
boolean success = doSetUserStatus(userId, State.ENABLED); boolean success = doSetUserStatus(userId, State.ENABLED);
@ -1892,7 +1896,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
// make sure the account is enabled too // make sure the account is enabled too
// if the user is either locked already or disabled already, don't change state...only lock currently enabled // if the user is either locked already or disabled already, don't change state...only lock currently enabled
// users // users
boolean success = true; boolean success;
if (user.getState().equals(State.LOCKED)) { if (user.getState().equals(State.LOCKED)) {
// already locked...no-op // already locked...no-op
return _userAccountDao.findById(userId); return _userAccountDao.findById(userId);
@ -1995,7 +1999,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
public AccountVO enableAccount(String accountName, Long domainId, Long accountId) { public AccountVO enableAccount(String accountName, Long domainId, Long accountId) {
// Check if account exists // Check if account exists
Account account = null; Account account;
if (accountId != null) { if (accountId != null) {
account = _accountDao.findById(accountId); account = _accountDao.findById(accountId);
} else { } else {
@ -2021,7 +2025,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return _accountDao.findById(account.getId()); return _accountDao.findById(account.getId());
} else { } else {
throw new CloudRuntimeException(String.format("Unable to enable account %s in domain %s", account, accountName, _domainMgr.getDomain(domainId))); throw new CloudRuntimeException(String.format("Unable to enable account %s[%s] in domain %s", accountName, account.getUuid(), _domainMgr.getDomain(domainId)));
} }
} }
@ -2030,7 +2034,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
public AccountVO lockAccount(String accountName, Long domainId, Long accountId) { public AccountVO lockAccount(String accountName, Long domainId, Long accountId) {
Account caller = getCurrentCallingAccount(); Account caller = getCurrentCallingAccount();
Account account = null; Account account;
if (accountId != null) { if (accountId != null) {
account = _accountDao.findById(accountId); account = _accountDao.findById(accountId);
} else { } else {
@ -2051,7 +2055,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
CallContext.current().putContextParameter(Account.class, account.getUuid()); CallContext.current().putContextParameter(Account.class, account.getUuid());
return _accountDao.findById(account.getId()); return _accountDao.findById(account.getId());
} else { } else {
throw new CloudRuntimeException(String.format("Unable to lock account %s by accountId: %d OR by name: %s in domain %d", account, accountId, accountName, _domainMgr.getDomain(domainId))); throw new CloudRuntimeException(String.format("Unable to lock account %s by accountId: %d OR by name: %s in domain %s", account, accountId, accountName, _domainMgr.getDomain(domainId)));
} }
} }
@ -2060,7 +2064,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
public AccountVO disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException { public AccountVO disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException {
Account caller = getCurrentCallingAccount(); Account caller = getCurrentCallingAccount();
Account account = null; Account account;
if (accountId != null) { if (accountId != null) {
account = _accountDao.findById(accountId); account = _accountDao.findById(accountId);
} else { } else {
@ -2097,8 +2101,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
String networkDomain = cmd.getNetworkDomain(); String networkDomain = cmd.getNetworkDomain();
final Map<String, String> details = cmd.getDetails(); final Map<String, String> details = cmd.getDetails();
boolean success = false; boolean success;
Account account = null; Account account;
if (accountId != null) { if (accountId != null) {
account = _accountDao.findById(accountId); account = _accountDao.findById(accountId);
} else { } else {
@ -2159,7 +2163,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (roleNotFound) { if (roleNotFound) {
throw new InvalidParameterValueException(String.format("Role with ID '%s' is not " + throw new InvalidParameterValueException(String.format("Role with ID '%s' is not " +
"found or not available for the account '%s' in the domain '%s'.", "found or not available for the account '%s' in the domain '%s'.",
roleId.toString(), account, _domainMgr.getDomain(domainId))); roleId, account, _domainMgr.getDomain(domainId)));
} }
Role role = roleService.findRole(roleId); Role role = roleService.findRole(roleId);
@ -2244,7 +2248,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return true; // no need to create a new user object for this user return true; // no need to create a new user object for this user
} }
return Transaction.execute(new TransactionCallback<Boolean>() { return Transaction.execute(new TransactionCallback<>() {
@Override @Override
public Boolean doInTransaction(TransactionStatus status) { public Boolean doInTransaction(TransactionStatus status) {
UserVO newUser = new UserVO(user); UserVO newUser = new UserVO(user);
@ -2560,7 +2564,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
// Create the account // Create the account
return Transaction.execute(new TransactionCallback<AccountVO>() { return Transaction.execute(new TransactionCallback<>() {
@Override @Override
public AccountVO doInTransaction(TransactionStatus status) { public AccountVO doInTransaction(TransactionStatus status) {
AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid)); AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid));
@ -2650,12 +2654,12 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
long tolerance = Long.parseLong(singleSignOnTolerance); long tolerance = Long.parseLong(singleSignOnTolerance);
String signature = null; String signature = null;
long timestamp = 0L; long timestamp = 0L;
String unsignedRequest = null; String unsignedRequest;
StringBuffer unsignedRequestBuffer = new StringBuffer(); StringBuffer unsignedRequestBuffer = new StringBuffer();
// - build a request string with sorted params, make sure it's all lowercase // - build a request string with sorted params, make sure it's all lowercase
// - sign the request, verify the signature is the same // - sign the request, verify the signature is the same
List<String> parameterNames = new ArrayList<String>(); List<String> parameterNames = new ArrayList<>();
for (Object paramNameObj : requestParameters.keySet()) { for (Object paramNameObj : requestParameters.keySet()) {
parameterNames.add((String)paramNameObj); // put the name in a list that we'll sort later parameterNames.add((String)paramNameObj); // put the name in a list that we'll sort later
@ -2780,7 +2784,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
UserAccount userAccount = _userAccountDao.getUserAccount(username, domainId); UserAccount userAccount = _userAccountDao.getUserAccount(username, domainId);
boolean authenticated = false; boolean authenticated = false;
HashSet<ActionOnFailedAuthentication> actionsOnFailedAuthenticaion = new HashSet<ActionOnFailedAuthentication>(); HashSet<ActionOnFailedAuthentication> actionsOnFailedAuthenticaion = new HashSet<>();
User.Source userSource = userAccount != null ? userAccount.getSource() : User.Source.UNKNOWN; User.Source userSource = userAccount != null ? userAccount.getSource() : User.Source.UNKNOWN;
for (UserAuthenticator authenticator : _userAuthenticators) { for (UserAuthenticator authenticator : _userAuthenticators) {
final String[] secretCodeArray = (String[])requestParameters.get(ApiConstants.SECRET_CODE); final String[] secretCodeArray = (String[])requestParameters.get(ApiConstants.SECRET_CODE);
@ -2886,7 +2890,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
preventRootDomainAdminAccessToRootAdminKeys(caller, account); preventRootDomainAdminAccessToRootAdminKeys(caller, account);
checkAccess(caller, account); checkAccess(caller, account);
Map<String, String> keys = new HashMap<String, String>(); Map<String, String> keys = new HashMap<>();
keys.put("apikey", user.getApiKey()); keys.put("apikey", user.getApiKey());
keys.put("secretkey", user.getSecretKey()); keys.put("secretkey", user.getSecretKey());
@ -2898,7 +2902,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
} }
return new Pair<Boolean, Map<String, String>>(apiKeyAccess, keys); return new Pair<>(apiKeyAccess, keys);
} }
protected void preventRootDomainAdminAccessToRootAdminKeys(User caller, ControlledEntity account) { protected void preventRootDomainAdminAccessToRootAdminKeys(User caller, ControlledEntity account) {
@ -2999,8 +3003,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
try { try {
UserVO updatedUser = _userDao.createForUpdate(); UserVO updatedUser = _userDao.createForUpdate();
String encodedKey = null; String encodedKey;
Pair<User, Account> userAcct = null; Pair<User, Account> userAcct;
int retryLimit = 10; int retryLimit = 10;
do { do {
// FIXME: what algorithm should we use for API keys? // FIXME: what algorithm should we use for API keys?
@ -3026,9 +3030,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
private String createUserSecretKey(long userId) { private String createUserSecretKey(long userId) {
try { try {
UserVO updatedUser = _userDao.createForUpdate(); UserVO updatedUser = _userDao.createForUpdate();
String encodedKey = null; String encodedKey;
int retryLimit = 10; int retryLimit = 10;
UserVO userBySecretKey = null; UserVO userBySecretKey;
do { do {
KeyGenerator generator = KeyGenerator.getInstance("HmacSHA1"); KeyGenerator generator = KeyGenerator.getInstance("HmacSHA1");
SecretKey key = generator.generateKey(); SecretKey key = generator.generateKey();
@ -3136,8 +3140,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
throw new InvalidParameterValueException("Account and projectId can't be specified together"); throw new InvalidParameterValueException("Account and projectId can't be specified together");
} }
Account userAccount = null; Account userAccount;
Domain domain = null; Domain domain;
if (domainId != null) { if (domainId != null) {
userAccount = _accountDao.findActiveAccount(accountName, domainId); userAccount = _accountDao.findActiveAccount(accountName, domainId);
domain = _domainDao.findById(domainId); domain = _domainDao.findById(domainId);
@ -3262,7 +3266,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
public List<String> listAclGroupsByAccount(Long accountId) { public List<String> listAclGroupsByAccount(Long accountId) {
if (_querySelectors == null || _querySelectors.size() == 0) { if (_querySelectors == null || _querySelectors.size() == 0) {
return new ArrayList<String>(); return new ArrayList<>();
} }
QuerySelector qs = _querySelectors.get(0); QuerySelector qs = _querySelectors.get(0);
@ -3522,7 +3526,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
protected UserTwoFactorAuthenticationSetupResponse disableTwoFactorAuthentication(Long userId, Account caller, Account owner) { protected UserTwoFactorAuthenticationSetupResponse disableTwoFactorAuthentication(Long userId, Account caller, Account owner) {
UserVO userVO = null; UserVO userVO;
if (userId != null) { if (userId != null) {
userVO = validateUser(userId); userVO = validateUser(userId);
owner = _accountService.getActiveAccountById(userVO.getAccountId()); owner = _accountService.getActiveAccountById(userVO.getAccountId());

View File

@ -134,8 +134,8 @@ import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.userdata.UserDataManager; import org.apache.cloudstack.userdata.UserDataManager;
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
import org.apache.cloudstack.utils.security.ParserUtils; import org.apache.cloudstack.utils.security.ParserUtils;
import org.apache.cloudstack.vm.UnmanagedVMsManager;
import org.apache.cloudstack.vm.schedule.VMScheduleManager; import org.apache.cloudstack.vm.schedule.VMScheduleManager;
import org.apache.cloudstack.vm.UnmanagedVMsManager;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.math.NumberUtils;
@ -2140,7 +2140,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Unable to Scale VM, since disk offering strictness flag is not same for new service offering and old service offering"); throw new InvalidParameterValueException("Unable to Scale VM, since disk offering strictness flag is not same for new service offering and old service offering");
} }
if (currentServiceOffering.getDiskOfferingStrictness() && currentServiceOffering.getDiskOfferingId() != newServiceOffering.getDiskOfferingId()) { if (currentServiceOffering.getDiskOfferingStrictness() && !currentServiceOffering.getDiskOfferingId().equals(newServiceOffering.getDiskOfferingId())) {
throw new InvalidParameterValueException("Unable to Scale VM, since disk offering id associated with the old service offering is not same for new service offering"); throw new InvalidParameterValueException("Unable to Scale VM, since disk offering id associated with the old service offering is not same for new service offering");
} }
@ -4526,7 +4526,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} }
if (customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) { if (customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) {
Long rootDiskSize = rootDiskSizeCustomParam * GiB_TO_BYTES; Long rootDiskSize = NumbersUtil.parseLong(customParameters.get(VmDetailConstants.ROOT_DISK_SIZE), -1);
if (rootDiskSize <= 0) {
throw new InvalidParameterValueException("Root disk size should be a positive number.");
}
rootDiskSize = rootDiskSizeCustomParam * GiB_TO_BYTES;
_volumeService.validateVolumeSizeInBytes(rootDiskSize); _volumeService.validateVolumeSizeInBytes(rootDiskSize);
return rootDiskSize; return rootDiskSize;
} else { } else {

View File

@ -27,6 +27,7 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.storage.snapshot.SnapshotManager;
import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
@ -377,9 +378,14 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme
//StorageVMSnapshotStrategy - allows volume snapshots without memory; VM has to be in Running state; No limitation of the image format if the storage plugin supports volume snapshots; "kvm.vmstoragesnapshot.enabled" has to be enabled //StorageVMSnapshotStrategy - allows volume snapshots without memory; VM has to be in Running state; No limitation of the image format if the storage plugin supports volume snapshots; "kvm.vmstoragesnapshot.enabled" has to be enabled
//Other Storage volume plugins could integrate this with their own functionality for group snapshots //Other Storage volume plugins could integrate this with their own functionality for group snapshots
VMSnapshotStrategy snapshotStrategy = storageStrategyFactory.getVmSnapshotStrategy(userVmVo.getId(), rootVolumePool.getId(), snapshotMemory); VMSnapshotStrategy snapshotStrategy = storageStrategyFactory.getVmSnapshotStrategy(userVmVo.getId(), rootVolumePool.getId(), snapshotMemory);
if (snapshotStrategy == null) { if (snapshotStrategy == null) {
String message = "KVM does not support the type of snapshot requested"; String message;
if (!SnapshotManager.VmStorageSnapshotKvm.value() && !snapshotMemory) {
message = "Creating a snapshot of a running KVM instance without memory is not supported";
} else {
message = "KVM does not support the type of snapshot requested";
}
logger.debug(message); logger.debug(message);
throw new CloudRuntimeException(message); throw new CloudRuntimeException(message);
} }

View File

@ -0,0 +1,109 @@
// 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.api.query.dao;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.api.query.vo.SnapshotJoinVO;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@RunWith(MockitoJUnitRunner.class)
public class SnapshotJoinDaoImplTest {
@Spy
@InjectMocks
SnapshotJoinDaoImpl snapshotJoinDao = new SnapshotJoinDaoImpl();
@Mock
SearchCriteria<SnapshotJoinVO> mockSearchCriteria;
@Before
public void setUp() {
SnapshotJoinVO mockSnap = mock(SnapshotJoinVO.class);
SearchBuilder<SnapshotJoinVO> mockSearchBuilder = mock(SearchBuilder.class);
when(mockSearchBuilder.entity()).thenReturn(mockSnap);
doReturn(mockSearchBuilder).when(snapshotJoinDao).createSearchBuilder();
when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
}
@Test
public void testFindById_WithNullZoneId_EmptyResult() {
Long zoneId = null;
long id = 1L;
doReturn(Collections.emptyList()).when(snapshotJoinDao).search(mockSearchCriteria, null);
List<SnapshotJoinVO> result = snapshotJoinDao.findById(zoneId, id);
assertNull(result);
verify(mockSearchCriteria).setParameters("id", id);
verify(mockSearchCriteria, never()).setParameters("zoneId", zoneId);
}
@Test
public void testFindById_WithValidZoneId_EmptyResult() {
Long zoneId = 1L;
long id = 1L;
doReturn(Collections.emptyList()).when(snapshotJoinDao).search(mockSearchCriteria, null);
List<SnapshotJoinVO> result = snapshotJoinDao.findById(zoneId, id);
assertNull(result);
verify(mockSearchCriteria).setParameters("id", id);
verify(mockSearchCriteria).setParameters("zoneId", zoneId);
}
@Test
public void testFindById_WithValidResults() {
Long zoneId = 1L;
long id = 1L;
SnapshotJoinVO snapshot1 = mock(SnapshotJoinVO.class);
when(snapshot1.getSnapshotStorePair()).thenReturn("Primary_1");
SnapshotJoinVO snapshot2 = mock(SnapshotJoinVO.class);
when(snapshot2.getSnapshotStorePair()).thenReturn("Image_1");
doReturn(Arrays.asList(snapshot1, snapshot2)).when(snapshotJoinDao).search(mockSearchCriteria, null);
List<SnapshotJoinVO> result = snapshotJoinDao.findById(zoneId, id);
assertNotNull(result);
assertEquals(1, result.size());
assertEquals("Image_1", result.get(0).getSnapshotStorePair());
verify(mockSearchCriteria).setParameters("id", id);
verify(mockSearchCriteria).setParameters("zoneId", zoneId);
}
@Test
public void testFindById_WithNullResults() {
long id = 1L;
doReturn(null).when(snapshotJoinDao).search(mockSearchCriteria, null);
List<SnapshotJoinVO> result = snapshotJoinDao.findById(null, id);
assertNull(result);
}
}

View File

@ -2038,13 +2038,13 @@ public class VolumeApiServiceImplTest {
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L); when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet()))) when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet())))
.thenReturn(pool); .thenReturn(pool);
StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); StoragePool result = volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
Assert.assertNotNull(result); Assert.assertNotNull(result);
Assert.assertEquals(pool, result); Assert.assertEquals(pool, result);
} }
@Test(expected = CloudRuntimeException.class) @Test
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoPoolFound_ThrowsException() { public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoSuitablePoolFound_ReturnsNull() {
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
UserVmVO vm = Mockito.mock(UserVmVO.class); UserVmVO vm = Mockito.mock(UserVmVO.class);
DataCenterVO zone = mockZone(); DataCenterVO zone = mockZone();
@ -2059,11 +2059,11 @@ public class VolumeApiServiceImplTest {
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L); when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet()))) when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet())))
.thenReturn(null); .thenReturn(null);
volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); Assert.assertNull(volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm));
} }
@Test @Test
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoCluster() { public void testGetSuitablePoolForAllocatedOrUploadedVolumeForAttach_NoCluster() {
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class); VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
UserVmVO vm = Mockito.mock(UserVmVO.class); UserVmVO vm = Mockito.mock(UserVmVO.class);
DataCenterVO zone = mockZone(); DataCenterVO zone = mockZone();
@ -2077,7 +2077,7 @@ public class VolumeApiServiceImplTest {
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L); when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(null), eq(2L), eq(vm), eq(Collections.emptySet()))) when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(null), eq(2L), eq(vm), eq(Collections.emptySet())))
.thenReturn(pool); .thenReturn(pool);
StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); StoragePool result = volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
Assert.assertNotNull(result); Assert.assertNotNull(result);
Assert.assertEquals(pool, result); Assert.assertEquals(pool, result);
} }
@ -2123,7 +2123,7 @@ public class VolumeApiServiceImplTest {
UserVmVO vm = Mockito.mock(UserVmVO.class); UserVmVO vm = Mockito.mock(UserVmVO.class);
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class); StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl) Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); .getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class); VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class);
try { try {
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage( Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(
@ -2134,7 +2134,7 @@ public class VolumeApiServiceImplTest {
} }
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null); VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
Assert.assertSame(newVolumeOnPrimaryStorage, result); Assert.assertSame(newVolumeOnPrimaryStorage, result);
verify(volumeApiServiceImpl).getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); verify(volumeApiServiceImpl).getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
} }
@Test(expected = InvalidParameterValueException.class) @Test(expected = InvalidParameterValueException.class)
@ -2145,7 +2145,7 @@ public class VolumeApiServiceImplTest {
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class); StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex); when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl) Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); .getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null); volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
} }
@ -2157,7 +2157,7 @@ public class VolumeApiServiceImplTest {
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class); StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem); Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl) Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm); .getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
try { try {
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage)) Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage))
.thenThrow(new NoTransitionException("Mocked exception")); .thenThrow(new NoTransitionException("Mocked exception"));
@ -2169,4 +2169,35 @@ public class VolumeApiServiceImplTest {
); );
Assert.assertTrue(exception.getMessage().contains("Failed to create volume on primary storage")); Assert.assertTrue(exception.getMessage().contains("Failed to create volume on primary storage"));
} }
@Test
public void testCreateVolumeOnSecondaryForAttachIfNeeded_NoSuitablePool_ThrowsException() {
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded);
UserVmVO vm = Mockito.mock(UserVmVO.class);
Mockito.doReturn(null).when(volumeApiServiceImpl)
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class, () ->
volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null)
);
Assert.assertTrue(exception.getMessage().startsWith("Failed to find a primary storage for volume"));
}
@Test
public void testCreateVolumeOnSecondaryForAttachIfNeeded_NoSuitablePool_ReturnSameVolumeInfo() {
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Allocated);
UserVmVO vm = Mockito.mock(UserVmVO.class);
Mockito.when(vm.getState()).thenReturn(State.Stopped);
Mockito.doReturn(null).when(volumeApiServiceImpl)
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
Assert.assertSame(volumeToAttach, result);
try {
Mockito.verify(volumeOrchestrationService, Mockito.never()).createVolumeOnPrimaryStorage(Mockito.any(),
Mockito.any(), Mockito.any(), Mockito.any());
} catch (NoTransitionException e) {
Assert.fail();
}
}
} }

View File

@ -40,11 +40,6 @@ public class LocalNfsSecondaryStorageResource extends NfsSecondaryStorageResourc
this._inSystemVM = false; this._inSystemVM = false;
} }
@Override
public void setParentPath(String path) {
this._parent = path;
}
@Override @Override
public Answer executeRequest(Command cmd) { public Answer executeRequest(Command cmd) {
return super.executeRequest(cmd); return super.executeRequest(cmd);
@ -57,7 +52,7 @@ public class LocalNfsSecondaryStorageResource extends NfsSecondaryStorageResourc
String dir = mountUri(uri, nfsVersion); String dir = mountUri(uri, nfsVersion);
return _parent + "/" + dir; return _parent + "/" + dir;
} catch (Exception e) { } catch (Exception e) {
String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); String msg = "GetRootDir for " + secUrl + " failed due to " + e;
logger.error(msg, e); logger.error(msg, e);
throw new CloudRuntimeException(msg); throw new CloudRuntimeException(msg);
} }
@ -75,14 +70,14 @@ public class LocalNfsSecondaryStorageResource extends NfsSecondaryStorageResourc
// Change permissions for the mountpoint - seems to bypass authentication // Change permissions for the mountpoint - seems to bypass authentication
Script script = new Script(true, "chmod", _timeout, logger); Script script = new Script(true, "chmod", _timeout, logger);
script.add("777", localRootPath); script.add("1777", localRootPath);
String result = script.execute(); String result = script.execute();
if (result != null) { if (result != null) {
String errMsg = "Unable to set permissions for " + localRootPath + " due to " + result; String errMsg = "Unable to set permissions for " + localRootPath + " due to " + result;
logger.error(errMsg); logger.error(errMsg);
throw new CloudRuntimeException(errMsg); throw new CloudRuntimeException(errMsg);
} }
logger.debug("Successfully set 777 permission for " + localRootPath); logger.debug("Successfully set 1777 permission for " + localRootPath);
// XXX: Adding the check for creation of snapshots dir here. Might have // XXX: Adding the check for creation of snapshots dir here. Might have
// to move it somewhere more logical later. // to move it somewhere more logical later.

View File

@ -19,15 +19,16 @@ import logging
from netaddr import IPAddress, IPNetwork from netaddr import IPAddress, IPNetwork
import subprocess import subprocess
import time import time
from . import CsHelper from . import CsHelper
from .CsDatabag import CsDataBag from .CsDatabag import CsDataBag
from .CsApp import CsApache, CsDnsmasq, CsPasswdSvc from .CsApp import CsApache, CsDnsmasq, CsPasswdSvc
from .CsRoute import CsRoute from .CsRoute import CsRoute
from .CsRule import CsRule from .CsRule import CsRule
from .CsStaticRoutes import CsStaticRoutes
VRRP_TYPES = ['guest'] VRRP_TYPES = ['guest']
class CsAddress(CsDataBag): class CsAddress(CsDataBag):
def compare(self): def compare(self):
@ -556,8 +557,10 @@ class CsIP:
(self.dev, guestNetworkCidr, self.address['gateway'], self.dev)]) (self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
if self.is_private_gateway(): if self.is_private_gateway():
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" % self.fw.append(["filter", "front", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
(self.address['network'], self.dev, self.dev)]) (self.address['network'], self.dev, self.dev)])
self.fw.append(["filter", "front", "-A FORWARD -d %s -o %s -m state --state RELATED,ESTABLISHED -j ACCEPT" %
(self.address['network'], self.dev)])
self.fw.append(["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev]) self.fw.append(["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev])
self.fw.append(["mangle", "", self.fw.append(["mangle", "",
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" % "-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
@ -565,6 +568,23 @@ class CsIP:
self.fw.append(["mangle", "front", self.fw.append(["mangle", "front",
"-A PREROUTING -s %s -d %s -m state --state NEW -j MARK --set-xmark %s/0xffffffff" % "-A PREROUTING -s %s -d %s -m state --state NEW -j MARK --set-xmark %s/0xffffffff" %
(self.cl.get_vpccidr(), self.address['network'], hex(100 + int(self.dev[3:])))]) (self.cl.get_vpccidr(), self.address['network'], hex(100 + int(self.dev[3:])))])
static_routes = CsStaticRoutes("staticroutes", self.config)
if static_routes:
for item in static_routes.get_bag():
if item == "id":
continue
static_route = static_routes.get_bag()[item]
if static_route['ip_address'] == self.address['public_ip'] and not static_route['revoke']:
self.fw.append(["mangle", "",
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
(self.dev, static_route['network'], static_route['ip_address'], self.dev)])
self.fw.append(["filter", "front", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
(static_route['network'], self.dev, self.dev)])
self.fw.append(["filter", "front",
"-A FORWARD -d %s -o %s -m state --state RELATED,ESTABLISHED -j ACCEPT" %
(static_route['network'], self.dev)])
if self.address["source_nat"]: if self.address["source_nat"]:
self.fw.append(["nat", "front", self.fw.append(["nat", "front",
"-A POSTROUTING -o %s -j SNAT --to-source %s" % "-A POSTROUTING -o %s -j SNAT --to-source %s" %

View File

@ -139,7 +139,6 @@ class CsDhcp(CsDataBag):
# Listen Address # Listen Address
if self.cl.is_redundant(): if self.cl.is_redundant():
listen_address.append(gateway) listen_address.append(gateway)
else:
listen_address.append(ip) listen_address.append(ip)
# Add localized "data-server" records in /etc/hosts for VPC routers # Add localized "data-server" records in /etc/hosts for VPC routers
if self.config.is_vpc() or self.config.is_router(): if self.config.is_vpc() or self.config.is_router():

View File

@ -74,6 +74,7 @@ class TestData(object):
"listApis": "allow", "listApis": "allow",
"listAccounts": "allow", "listAccounts": "allow",
"listClusters": "deny", "listClusters": "deny",
"*VmwareDc*": "allow",
"*VM*": "allow", "*VM*": "allow",
"*Host*": "deny" "*Host*": "deny"
} }

View File

@ -1265,7 +1265,6 @@
"label.save.new.rule": "Neue Regel Speichern", "label.save.new.rule": "Neue Regel Speichern",
"label.schedule": "Zeitplan", "label.schedule": "Zeitplan",
"label.scheduled.backups": "geplante Backups", "label.scheduled.backups": "geplante Backups",
"label.scheduled.snapshots": "geplante Schnappschüsse",
"label.scope": "Geltungsbereich", "label.scope": "Geltungsbereich",
"label.search": "Suche", "label.search": "Suche",
"label.secondary.isolated.vlan.type.isolated": "Isoliert", "label.secondary.isolated.vlan.type.isolated": "Isoliert",

View File

@ -1517,7 +1517,6 @@
"label.scale.vm": "Κλίμακα εικονικής μηχανής", "label.scale.vm": "Κλίμακα εικονικής μηχανής",
"label.schedule": "Πρόγραμμα", "label.schedule": "Πρόγραμμα",
"label.scheduled.backups": "Προγραμματισμένα αντίγραφα ασφαλείας", "label.scheduled.backups": "Προγραμματισμένα αντίγραφα ασφαλείας",
"label.scheduled.snapshots": "Προγραμματισμένα στιγμιότυπα",
"label.scope": "Πεδίο εφαρμογής", "label.scope": "Πεδίο εφαρμογής",
"label.search": "Αναζήτηση", "label.search": "Αναζήτηση",
"label.secondary.isolated.vlan.type.isolated": "Απομονωμένες", "label.secondary.isolated.vlan.type.isolated": "Απομονωμένες",

View File

@ -54,6 +54,7 @@
"label.action": "Action", "label.action": "Action",
"label.action.attach.disk": "Attach disk", "label.action.attach.disk": "Attach disk",
"label.action.attach.iso": "Attach ISO", "label.action.attach.iso": "Attach ISO",
"label.action.attach.to.instance": "Attach to Instance",
"label.action.bulk.delete.egress.firewall.rules": "Bulk delete egress firewall rules", "label.action.bulk.delete.egress.firewall.rules": "Bulk delete egress firewall rules",
"label.action.bulk.delete.firewall.rules": "Bulk delete firewall rules", "label.action.bulk.delete.firewall.rules": "Bulk delete firewall rules",
"label.action.bulk.delete.ip.v6.firewall.rules": "Bulk remove IPv6 firewall rules", "label.action.bulk.delete.ip.v6.firewall.rules": "Bulk remove IPv6 firewall rules",
@ -400,9 +401,11 @@
"label.associatednetworkid": "Associated Network ID", "label.associatednetworkid": "Associated Network ID",
"label.associatednetworkname": "Network name", "label.associatednetworkname": "Network name",
"label.asyncbackup": "Async backup", "label.asyncbackup": "Async backup",
"label.attach.vol.to.instance": "Attach the created Volume to an existing Instance",
"label.attaching": "Attaching", "label.attaching": "Attaching",
"label.authentication.method": "Authentication Method", "label.authentication.method": "Authentication Method",
"label.authentication.sshkey": "System SSH Key", "label.authentication.sshkey": "System SSH Key",
"label.use.existing.vcenter.credentials.from.zone": "Use existing vCenter credentials from the Zone",
"label.autoscale": "AutoScale", "label.autoscale": "AutoScale",
"label.autoscalevmgroupname": "AutoScaling Group", "label.autoscalevmgroupname": "AutoScaling Group",
"label.author.email": "Author e-mail", "label.author.email": "Author e-mail",
@ -1079,7 +1082,7 @@
"label.hastate": "HA state", "label.hastate": "HA state",
"label.headers": "Headers", "label.headers": "Headers",
"label.header.backup.schedule": "You can set up recurring backup schedules by selecting from the available options below and applying your policy preference.", "label.header.backup.schedule": "You can set up recurring backup schedules by selecting from the available options below and applying your policy preference.",
"label.header.volume.snapshot": "You can set up recurring Snapshot schedules by selecting from the available options below and applying your policy preference.", "label.header.volume.snapshot": "You can set up recurring Snapshots by selecting from the available options below and applying your policy preference.",
"label.header.volume.take.snapshot": "Please confirm that you want to take a Snapshot of this volume.", "label.header.volume.take.snapshot": "Please confirm that you want to take a Snapshot of this volume.",
"label.health.check": "Health check", "label.health.check": "Health check",
"label.heapmemoryused": "Heap-memory used", "label.heapmemoryused": "Heap-memory used",
@ -2019,7 +2022,6 @@
"label.schedule": "Schedule", "label.schedule": "Schedule",
"label.schedule.add": "Add schedule", "label.schedule.add": "Add schedule",
"label.scheduled.backups": "Scheduled backups", "label.scheduled.backups": "Scheduled backups",
"label.scheduled.snapshots": "Scheduled Snapshots",
"label.schedules": "Schedules", "label.schedules": "Schedules",
"label.scope": "Scope", "label.scope": "Scope",
"label.scope.tooltip": "Primary Storage Pool Scope", "label.scope.tooltip": "Primary Storage Pool Scope",
@ -3283,6 +3285,7 @@
"message.license.agreements.not.accepted": "License agreements not accepted.", "message.license.agreements.not.accepted": "License agreements not accepted.",
"message.linstor.resourcegroup.description": "Linstor resource group to use for primary storage.", "message.linstor.resourcegroup.description": "Linstor resource group to use for primary storage.",
"message.list.zone.vmware.datacenter.empty": "No VMware Datacenter exists in the selected Zone", "message.list.zone.vmware.datacenter.empty": "No VMware Datacenter exists in the selected Zone",
"message.list.zone.vmware.hosts.empty": "No VMware hosts were found in the selected Datacenter",
"message.listnsp.not.return.providerid": "error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID.", "message.listnsp.not.return.providerid": "error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID.",
"message.load.host.failed": "Failed to load hosts.", "message.load.host.failed": "Failed to load hosts.",
"message.loadbalancer.stickypolicy.configuration": "Customize the load balancer stickiness policy:", "message.loadbalancer.stickypolicy.configuration": "Customize the load balancer stickiness policy:",

View File

@ -1969,7 +1969,6 @@
"label.scaleup.policy": "スケールアップポリシー", "label.scaleup.policy": "スケールアップポリシー",
"label.schedule": "スケジュール", "label.schedule": "スケジュール",
"label.scheduled.backups": "スケジュールされたバックアップ", "label.scheduled.backups": "スケジュールされたバックアップ",
"label.scheduled.snapshots": "スケジュールされたスナップショット",
"label.scope": "スコープ", "label.scope": "スコープ",
"label.search": "検索", "label.search": "検索",
"label.secondary.isolated.vlan.type.isolated": "隔離", "label.secondary.isolated.vlan.type.isolated": "隔離",

View File

@ -1322,7 +1322,6 @@
"label.scale.vm": "VM \ud655\uc7a5", "label.scale.vm": "VM \ud655\uc7a5",
"label.schedule": "\uc2a4\ucf00\uc904", "label.schedule": "\uc2a4\ucf00\uc904",
"label.scheduled.backups": "\uc608\uc57d\ub41c \ubc31\uc5c5", "label.scheduled.backups": "\uc608\uc57d\ub41c \ubc31\uc5c5",
"label.scheduled.snapshots": "\uc608\uc57d\ub41c \uc2a4\ub0c5\uc0f7",
"label.scope": "\ubc94\uc704", "label.scope": "\ubc94\uc704",
"label.search": "\uac80\uc0c9", "label.search": "\uac80\uc0c9",
"label.secondary.isolated.vlan.type.isolated": "isolated", "label.secondary.isolated.vlan.type.isolated": "isolated",

View File

@ -1430,7 +1430,6 @@
"label.scale.vm": "Escalar VM", "label.scale.vm": "Escalar VM",
"label.schedule": "Programar", "label.schedule": "Programar",
"label.scheduled.backups": "Backups programados", "label.scheduled.backups": "Backups programados",
"label.scheduled.snapshots": "Snapshots programados",
"label.scope": "Escopo", "label.scope": "Escopo",
"label.search": "Pesquisar", "label.search": "Pesquisar",
"label.secondary.isolated.vlan.type.isolated": "Isolada", "label.secondary.isolated.vlan.type.isolated": "Isolada",

View File

@ -2248,7 +2248,6 @@
"label.schedule": "\u65E5\u7A0B", "label.schedule": "\u65E5\u7A0B",
"label.scheduled.backups": "\u5B9A\u65F6\u5907\u4EFD", "label.scheduled.backups": "\u5B9A\u65F6\u5907\u4EFD",
"label.scheduled.snapshots": "\u8BA1\u5212\u5FEB\u7167",
"label.scope": "\u8303\u56F4", "label.scope": "\u8303\u56F4",
"label.search": "\u641C\u7D22", "label.search": "\u641C\u7D22",

View File

@ -259,6 +259,9 @@
<template v-if="column.key === 'vmstate'"> <template v-if="column.key === 'vmstate'">
<status :text="text ? text : ''" displayText vmState/> <status :text="text ? text : ''" displayText vmState/>
</template> </template>
<template v-if="column.key === 'offerha'">
{{ text ? $t('state.enabled') : $t('state.disabled')}}
</template>
<template v-if="column.key === 'vlan'"> <template v-if="column.key === 'vlan'">
<a href="javascript:;"> <a href="javascript:;">
<router-link v-if="$route.path === '/guestvlans'" :to="{ path: '/guestvlans/' + record.id }">{{ text }}</router-link> <router-link v-if="$route.path === '/guestvlans'" :to="{ path: '/guestvlans/' + record.id }">{{ text }}</router-link>

View File

@ -17,6 +17,7 @@
import { shallowRef, defineAsyncComponent } from 'vue' import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store' import store from '@/store'
import { isZoneCreated } from '@/utils/zone'
export default { export default {
name: 'compute', name: 'compute',
@ -100,6 +101,7 @@ export default {
label: 'label.vm.add', label: 'label.vm.add',
docHelp: 'adminguide/virtual_machines.html#creating-vms', docHelp: 'adminguide/virtual_machines.html#creating-vms',
listView: true, listView: true,
show: isZoneCreated,
component: () => import('@/views/compute/DeployVM.vue') component: () => import('@/views/compute/DeployVM.vue')
}, },
{ {
@ -207,9 +209,10 @@ export default {
docHelp: 'adminguide/virtual_machines.html#virtual-machine-snapshots', docHelp: 'adminguide/virtual_machines.html#virtual-machine-snapshots',
dataView: true, dataView: true,
popup: true, popup: true,
show: (record) => { show: (record, store) => {
return ((['Running'].includes(record.state) && record.hypervisor !== 'LXC') || return (record.hypervisor !== 'KVM') ||
(['Stopped'].includes(record.state) && !['KVM', 'LXC'].includes(record.hypervisor))) ['Stopped', 'Destroyed'].includes(record.state) ||
store.features.kvmsnapshotenabled
}, },
disabled: (record) => { return record.hostcontrolstate === 'Offline' && record.hypervisor === 'KVM' }, disabled: (record) => { return record.hostcontrolstate === 'Offline' && record.hypervisor === 'KVM' },
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateSnapshotWizard.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateSnapshotWizard.vue')))
@ -224,6 +227,10 @@ export default {
args: ['virtualmachineid', 'backupofferingid'], args: ['virtualmachineid', 'backupofferingid'],
show: (record) => { return !record.backupofferingid }, show: (record) => { return !record.backupofferingid },
mapping: { mapping: {
backupofferingid: {
api: 'listBackupOfferings',
params: (record) => { return { zoneid: record.zoneid } }
},
virtualmachineid: { virtualmachineid: {
value: (record, params) => { return record.id } value: (record, params) => { return record.id }
} }
@ -568,6 +575,7 @@ export default {
docHelp: 'plugins/cloudstack-kubernetes-service.html#creating-a-new-kubernetes-cluster', docHelp: 'plugins/cloudstack-kubernetes-service.html#creating-a-new-kubernetes-cluster',
listView: true, listView: true,
popup: true, popup: true,
show: isZoneCreated,
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateKubernetesCluster.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateKubernetesCluster.vue')))
}, },
{ {
@ -696,6 +704,7 @@ export default {
icon: 'plus-outlined', icon: 'plus-outlined',
label: 'label.new.autoscale.vmgroup', label: 'label.new.autoscale.vmgroup',
listView: true, listView: true,
show: isZoneCreated,
component: () => import('@/views/compute/CreateAutoScaleVmGroup.vue') component: () => import('@/views/compute/CreateAutoScaleVmGroup.vue')
}, },
{ {
@ -786,6 +795,7 @@ export default {
icon: 'plus-outlined', icon: 'plus-outlined',
label: 'label.new.instance.group', label: 'label.new.instance.group',
listView: true, listView: true,
show: isZoneCreated,
args: ['name'] args: ['name']
}, },
{ {

View File

@ -17,6 +17,7 @@
import { shallowRef, defineAsyncComponent } from 'vue' import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store' import store from '@/store'
import { isZoneCreated } from '@/utils/zone'
export default { export default {
name: 'image', name: 'image',
@ -110,16 +111,17 @@ export default {
docHelp: 'adminguide/templates.html#uploading-templates-from-a-remote-http-server', docHelp: 'adminguide/templates.html#uploading-templates-from-a-remote-http-server',
listView: true, listView: true,
popup: true, popup: true,
show: isZoneCreated,
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadTemplate.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadTemplate.vue')))
}, },
{ {
api: 'registerTemplate', api: 'registerTemplate',
icon: 'cloud-upload-outlined', icon: 'cloud-upload-outlined',
label: 'label.upload.template.from.local', label: 'label.upload.template.from.local',
show: () => { return 'getUploadParamsForTemplate' in store.getters.apis },
docHelp: 'adminguide/templates.html#uploading-templates-and-isos-from-a-local-computer', docHelp: 'adminguide/templates.html#uploading-templates-and-isos-from-a-local-computer',
listView: true, listView: true,
popup: true, popup: true,
show: () => { return isZoneCreated() && 'getUploadParamsForTemplate' in store.getters.apis },
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadTemplate.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadTemplate.vue')))
}, },
{ {
@ -270,13 +272,14 @@ export default {
docHelp: 'adminguide/templates.html#id10', docHelp: 'adminguide/templates.html#id10',
listView: true, listView: true,
popup: true, popup: true,
show: isZoneCreated,
component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadIso.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/image/RegisterOrUploadIso.vue')))
}, },
{ {
api: 'registerIso', api: 'registerIso',
icon: 'cloud-upload-outlined', icon: 'cloud-upload-outlined',
label: 'label.upload.iso.from.local', label: 'label.upload.iso.from.local',
show: () => { return 'getUploadParamsForIso' in store.getters.apis }, show: () => { return isZoneCreated() && 'getUploadParamsForIso' in store.getters.apis },
docHelp: 'adminguide/templates.html#id10', docHelp: 'adminguide/templates.html#id10',
listView: true, listView: true,
popup: true, popup: true,
@ -389,6 +392,7 @@ export default {
label: 'label.kubernetes.version.add', label: 'label.kubernetes.version.add',
listView: true, listView: true,
popup: true, popup: true,
show: isZoneCreated,
component: shallowRef(defineAsyncComponent(() => import('@/views/image/AddKubernetesSupportedVersion.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/image/AddKubernetesSupportedVersion.vue')))
}, },
{ {

View File

@ -26,14 +26,14 @@ export default {
permission: ['listManagementServersMetrics'], permission: ['listManagementServersMetrics'],
resourceType: 'ManagementServer', resourceType: 'ManagementServer',
columns: () => { columns: () => {
const fields = ['name', 'state', 'serviceip', 'version', 'osdistribution', 'pendingjobscount', 'agentscount'] const fields = ['name', 'state', 'ipaddress', 'version', 'osdistribution', 'pendingjobscount', 'agentscount']
const metricsFields = ['collectiontime', 'availableprocessors', 'cpuload', 'heapmemoryused'] const metricsFields = ['collectiontime', 'availableprocessors', 'cpuload', 'heapmemoryused']
if (store.getters.metrics) { if (store.getters.metrics) {
fields.push(...metricsFields) fields.push(...metricsFields)
} }
return fields return fields
}, },
details: ['collectiontime', 'usageislocal', 'dbislocal', 'lastserverstart', 'lastserverstop', 'lastboottime', 'version', 'loginfo', 'systemtotalcpucycles', 'systemloadaverages', 'systemcycleusage', 'systemmemorytotal', 'systemmemoryfree', 'systemmemoryvirtualsize', 'availableprocessors', 'javadistribution', 'javaversion', 'osdistribution', 'kernelversion', 'pendingjobscount', 'agentscount', 'sessions', 'heapmemoryused', 'heapmemorytotal', 'threadsblockedcount', 'threadsdeamoncount', 'threadsnewcount', 'threadsrunnablecount', 'threadsterminatedcount', 'threadstotalcount', 'threadswaitingcount'], details: ['ipaddress', 'collectiontime', 'usageislocal', 'dbislocal', 'lastserverstart', 'lastserverstop', 'lastboottime', 'version', 'loginfo', 'systemtotalcpucycles', 'systemloadaverages', 'systemcycleusage', 'systemmemorytotal', 'systemmemoryfree', 'systemmemoryvirtualsize', 'availableprocessors', 'javadistribution', 'javaversion', 'osdistribution', 'kernelversion', 'pendingjobscount', 'agentscount', 'sessions', 'heapmemoryused', 'heapmemorytotal', 'threadsblockedcount', 'threadsdeamoncount', 'threadsnewcount', 'threadsrunnablecount', 'threadsterminatedcount', 'threadstotalcount', 'threadswaitingcount'],
tabs: [ tabs: [
{ {
name: 'details', name: 'details',

View File

@ -19,6 +19,7 @@ import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store' import store from '@/store'
import tungsten from '@/assets/icons/tungsten.svg?inline' import tungsten from '@/assets/icons/tungsten.svg?inline'
import { isAdmin } from '@/role' import { isAdmin } from '@/role'
import { isZoneCreated } from '@/utils/zone'
export default { export default {
name: 'network', name: 'network',
@ -123,7 +124,7 @@ export default {
listView: true, listView: true,
popup: true, popup: true,
show: () => { show: () => {
if (!store.getters.zones || store.getters.zones.length === 0) { if (!isZoneCreated()) {
return false return false
} }
const AdvancedZones = store.getters.zones.filter(zone => zone.networktype === 'Advanced') const AdvancedZones = store.getters.zones.filter(zone => zone.networktype === 'Advanced')
@ -245,6 +246,7 @@ export default {
icon: 'plus-outlined', icon: 'plus-outlined',
label: 'label.add.vpc', label: 'label.add.vpc',
docHelp: 'adminguide/networking_and_traffic.html#adding-a-virtual-private-cloud', docHelp: 'adminguide/networking_and_traffic.html#adding-a-virtual-private-cloud',
show: isZoneCreated,
listView: true, listView: true,
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateVpc.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateVpc.vue')))
@ -306,7 +308,7 @@ export default {
component: shallowRef(defineAsyncComponent(() => import('@/views/network/IngressEgressRuleConfigure.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/network/IngressEgressRuleConfigure.vue')))
}], }],
show: () => { show: () => {
if (!store.getters.zones || store.getters.zones.length === 0) { if (!isZoneCreated()) {
return false return false
} }
const listZoneHaveSGEnabled = store.getters.zones.filter(zone => zone.securitygroupsenabled === true) const listZoneHaveSGEnabled = store.getters.zones.filter(zone => zone.securitygroupsenabled === true)
@ -394,6 +396,7 @@ export default {
label: 'label.vnf.appliance.add', label: 'label.vnf.appliance.add',
docHelp: 'adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances', docHelp: 'adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances',
listView: true, listView: true,
show: isZoneCreated,
component: () => import('@/views/compute/DeployVnfAppliance.vue') component: () => import('@/views/compute/DeployVnfAppliance.vue')
}, },
{ {
@ -941,6 +944,7 @@ export default {
label: 'label.add.vpn.gateway', label: 'label.add.vpn.gateway',
docHelp: 'adminguide/networking_and_traffic.html#creating-a-vpn-gateway-for-the-vpc', docHelp: 'adminguide/networking_and_traffic.html#creating-a-vpn-gateway-for-the-vpc',
listView: true, listView: true,
show: isZoneCreated,
args: ['vpcid'] args: ['vpcid']
}, },
{ {
@ -1116,6 +1120,7 @@ export default {
icon: 'plus-outlined', icon: 'plus-outlined',
label: 'label.add.vpn.user', label: 'label.add.vpn.user',
listView: true, listView: true,
show: isZoneCreated,
args: (record, store) => { args: (record, store) => {
if (store.userInfo.roletype === 'User') { if (store.userInfo.roletype === 'User') {
return ['username', 'password'] return ['username', 'password']
@ -1195,6 +1200,7 @@ export default {
docHelp: 'adminguide/networking_and_traffic.html#creating-and-updating-a-vpn-customer-gateway', docHelp: 'adminguide/networking_and_traffic.html#creating-and-updating-a-vpn-customer-gateway',
listView: true, listView: true,
popup: true, popup: true,
show: isZoneCreated,
component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateVpnCustomerGateway.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/network/CreateVpnCustomerGateway.vue')))
}, },
{ {
@ -1384,12 +1390,7 @@ export default {
component: shallowRef(defineAsyncComponent(() => import('@/views/network/GuestVlanNetworksTab.vue'))), component: shallowRef(defineAsyncComponent(() => import('@/views/network/GuestVlanNetworksTab.vue'))),
show: (record) => { return (record.allocationstate === 'Allocated') } show: (record) => { return (record.allocationstate === 'Allocated') }
}], }],
show: () => { show: isZoneCreated
if (!store.getters.zones || store.getters.zones.length === 0) {
return false
}
return true
}
} }
] ]
} }

View File

@ -142,7 +142,7 @@ export default {
permission: ['listServiceOfferings', 'listInfrastructure'], permission: ['listServiceOfferings', 'listInfrastructure'],
searchFilters: ['name', 'zoneid', 'domainid', 'cpunumber', 'cpuspeed', 'memory'], searchFilters: ['name', 'zoneid', 'domainid', 'cpunumber', 'cpuspeed', 'memory'],
params: { issystem: 'true', isrecursive: 'true' }, params: { issystem: 'true', isrecursive: 'true' },
columns: ['name', 'state', 'systemvmtype', 'cpunumber', 'cpuspeed', 'memory', 'storagetype', 'order'], columns: ['name', 'state', 'systemvmtype', 'cpunumber', 'cpuspeed', 'memory', 'storagetype', 'offerha', 'order'],
filters: ['active', 'inactive'], filters: ['active', 'inactive'],
details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'storagetags', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness'], details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'storagetags', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness'],
resourceType: 'ServiceOffering', resourceType: 'ServiceOffering',

View File

@ -17,6 +17,7 @@
import { shallowRef, defineAsyncComponent } from 'vue' import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store' import store from '@/store'
import { isZoneCreated } from '@/utils/zone'
export default { export default {
name: 'storage', name: 'storage',
@ -103,6 +104,7 @@ export default {
icon: 'plus-outlined', icon: 'plus-outlined',
docHelp: 'adminguide/storage.html#creating-a-new-volume', docHelp: 'adminguide/storage.html#creating-a-new-volume',
label: 'label.action.create.volume', label: 'label.action.create.volume',
show: isZoneCreated,
listView: true, listView: true,
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/CreateVolume.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/storage/CreateVolume.vue')))
@ -112,7 +114,7 @@ export default {
icon: 'cloud-upload-outlined', icon: 'cloud-upload-outlined',
docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine', docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
label: 'label.upload.volume.from.local', label: 'label.upload.volume.from.local',
show: () => { return 'getUploadParamsForVolume' in store.getters.apis }, show: () => { return isZoneCreated() && 'getUploadParamsForVolume' in store.getters.apis },
listView: true, listView: true,
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadLocalVolume.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadLocalVolume.vue')))
@ -122,6 +124,7 @@ export default {
icon: 'link-outlined', icon: 'link-outlined',
docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine', docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
label: 'label.upload.volume.from.url', label: 'label.upload.volume.from.url',
show: isZoneCreated,
listView: true, listView: true,
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadVolume.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadVolume.vue')))
@ -165,9 +168,10 @@ export default {
label: 'label.action.take.snapshot', label: 'label.action.take.snapshot',
dataView: true, dataView: true,
show: (record, store) => { show: (record, store) => {
return record.state === 'Ready' && (record.hypervisor !== 'KVM' || return record.state === 'Ready' &&
record.hypervisor === 'KVM' && record.vmstate === 'Running' && store.features.kvmsnapshotenabled || (record.hypervisor !== 'KVM' ||
record.hypervisor === 'KVM' && record.vmstate !== 'Running') ['Stopped', 'Destroyed'].includes(record.vmstate) ||
store.features.kvmsnapshotenabled)
}, },
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/TakeSnapshot.vue'))) component: shallowRef(defineAsyncComponent(() => import('@/views/storage/TakeSnapshot.vue')))
@ -179,9 +183,10 @@ export default {
label: 'label.action.recurring.snapshot', label: 'label.action.recurring.snapshot',
dataView: true, dataView: true,
show: (record, store) => { show: (record, store) => {
return record.state === 'Ready' && (record.hypervisor !== 'KVM' || return record.state === 'Ready' &&
record.hypervisor === 'KVM' && record.vmstate === 'Running' && store.features.kvmsnapshotenabled || (record.hypervisor !== 'KVM' ||
record.hypervisor === 'KVM' && record.vmstate !== 'Running') (['Stopped', 'Destroyed'].includes(record.vmstate)) ||
(store.features.kvmsnapshotenabled))
}, },
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/RecurringSnapshotVolume.vue'))), component: shallowRef(defineAsyncComponent(() => import('@/views/storage/RecurringSnapshotVolume.vue'))),

25
ui/src/utils/zone.js Normal file
View File

@ -0,0 +1,25 @@
// 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.
import store from '@/store'
export function isZoneCreated () {
if (!store.getters.zones || store.getters.zones.length === 0) {
return false
}
return true
}

View File

@ -47,7 +47,7 @@
<div class="form__label">{{ $t('label.hypervisor') }}</div> <div class="form__label">{{ $t('label.hypervisor') }}</div>
<a-select <a-select
v-model:value="hypervisor" v-model:value="hypervisor"
@change="resetAllFields" @change="hypervisor => onChangeHypervisor(hypervisor)"
showSearch showSearch
optionFilterProp="value" optionFilterProp="value"
:filterOption="(input, option) => { :filterOption="(input, option) => {
@ -109,19 +109,28 @@
</div> </div>
<div class="form__item"> <div class="form__item">
<div class="form__label">{{ $t('label.vcenterusername') }}</div> <div class="form__label">{{ $t('label.vcenterdatacenter') }}</div>
<a-input v-model:value="dataCenter"></a-input>
</div>
<div class="form__item" name="useDefaultVMwareCred">
<div class="form__label">{{ $t('label.use.existing.vcenter.credentials.from.zone') }}</div>
<a-switch v-model="useDefaultVMwareCred" :checked="useDefaultVMwareCred" @change="onChangeUseDefaultVMwareCred()" />
</div>
<template v-if="useDefaultVMwareCred === false">
<div class="form__item">
<div class="form__label"><span class="required">* </span>{{ $t('label.vcenterusername') }}</div>
<span class="required required-label" ref="requiredUsername">{{ $t('label.required') }}</span>
<a-input v-model:value="username"></a-input> <a-input v-model:value="username"></a-input>
</div> </div>
<div class="form__item"> <div class="form__item">
<div class="form__label">{{ $t('label.vcenterpassword') }}</div> <div class="form__label"><span class="required">* </span>{{ $t('label.vcenterpassword') }}</div>
<span class="required required-label" ref="requiredPassword">{{ $t('label.required') }}</span>
<a-input type="password" v-model:value="password"></a-input> <a-input type="password" v-model:value="password"></a-input>
</div> </div>
</template>
<div class="form__item">
<div class="form__label">{{ $t('label.vcenterdatacenter') }}</div>
<a-input v-model:value="dataCenter"></a-input>
</div>
</template> </template>
<div class="form__item"> <div class="form__item">
@ -176,6 +185,7 @@ export default {
username: null, username: null,
password: null, password: null,
url: null, url: null,
useDefaultVMwareCred: true,
host: null, host: null,
dataCenter: null, dataCenter: null,
ovm3pool: null, ovm3pool: null,
@ -257,6 +267,27 @@ export default {
this.loading = false this.loading = false
}) })
}, },
fetchVMwareCred () {
this.loading = true
this.clustertype = 'ExternalManaged'
api('listVmwareDcs', {
zoneid: this.zoneId
}).then(response => {
var vmwaredcs = response.listvmwaredcsresponse.VMwareDC
if (vmwaredcs !== null) {
this.host = vmwaredcs[0].vcenter
this.dataCenter = vmwaredcs[0].name
}
}).catch(error => {
this.$notification.error({
message: `${this.$t('label.error')} ${error.response.status}`,
description: error.response.data.listvmwaredcsresponse.errortext,
duration: 0
})
}).finally(() => {
this.loading = false
})
},
toggleDedicated () { toggleDedicated () {
this.dedicatedDomainId = null this.dedicatedDomainId = null
this.dedicatedAccount = null this.dedicatedAccount = null
@ -270,35 +301,24 @@ export default {
} }
this.$refs.requiredCluster.classList.remove('required-label--visible') this.$refs.requiredCluster.classList.remove('required-label--visible')
if (this.hypervisor === 'VMware' && this.useDefaultVMwareCred === false) {
if (!this.username) {
this.$refs.requiredUsername.classList.add('required-label--visible')
return
}
if (!this.password) {
this.$refs.requiredPassword.classList.add('required-label--visible')
return
}
this.$refs.requiredUsername.classList.remove('required-label--visible')
this.$refs.requiredPassword.classList.remove('required-label--visible')
}
if (this.hypervisor === 'Ovm3') { if (this.hypervisor === 'Ovm3') {
this.ovm3pool = 'on' this.ovm3pool = 'on'
this.ovm3cluster = 'undefined' this.ovm3cluster = 'undefined'
this.ovm3vip = '' this.ovm3vip = ''
} }
if (this.hypervisor === 'VMware') {
this.clustertype = 'ExternalManaged'
if ((this.host === null || this.host.length === 0) &&
(this.dataCenter === null || this.dataCenter.length === 0)) {
api('listVmwareDcs', {
zoneid: this.zoneId
}).then(response => {
var vmwaredcs = response.listvmwaredcsresponse.VMwareDC
if (vmwaredcs !== null) {
this.host = vmwaredcs[0].vcenter
this.dataCenter = vmwaredcs[0].name
}
this.addCluster()
}).catch(error => {
this.$notification.error({
message: `${this.$t('label.error')} ${error.response.status}`,
description: error.response.data.listvmwaredcsresponse.errortext,
duration: 0
})
})
return
}
}
this.addCluster() this.addCluster()
}, },
addCluster () { addCluster () {
@ -387,7 +407,7 @@ export default {
this.loading = false this.loading = false
}) })
}, },
resetAllFields () { onChangeHypervisor (hypervisor) {
this.clustertype = 'CloudManaged' this.clustertype = 'CloudManaged'
this.username = null this.username = null
this.password = null this.password = null
@ -397,6 +417,16 @@ export default {
this.ovm3pool = null this.ovm3pool = null
this.ovm3cluster = null this.ovm3cluster = null
this.ovm3vip = null this.ovm3vip = null
if (hypervisor === 'VMware') {
this.fetchVMwareCred()
}
},
onChangeUseDefaultVMwareCred () {
this.useDefaultVMwareCred = !this.useDefaultVMwareCred
if (this.useDefaultVMwareCred) {
this.username = null
this.password = null
}
}, },
returnPlaceholder (field) { returnPlaceholder (field) {
this.params.find(i => { this.params.find(i => {

View File

@ -793,6 +793,10 @@ export default {
if (this.scopeType === 'domain') { if (this.scopeType === 'domain') {
params.domainid = this.selectedDomain.id params.domainid = this.selectedDomain.id
} }
console.log(params?.tags?.length === 0)
if (!params?.tags || params.tags.length === 0) {
params.istagged = false
}
this.handleNetworkOfferingChange(null) this.handleNetworkOfferingChange(null)
this.networkOfferings = [] this.networkOfferings = []
api('listNetworkOfferings', params).then(json => { api('listNetworkOfferings', params).then(json => {

View File

@ -727,8 +727,7 @@ export default {
break break
case 'networkAcl': case 'networkAcl':
this.rules = { this.rules = {
name: [{ required: true, message: this.$t('label.required') }], name: [{ required: true, message: this.$t('label.required') }]
description: [{ required: true, message: this.$t('label.required') }]
} }
this.modals.networkAcl = true this.modals.networkAcl = true
break break

Some files were not shown because too many files have changed in this diff Show More