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 {
private static final long serialVersionUID = SerialVersionUID.StorageAccessException;
public StorageAccessException(String message) {
super(message);
public StorageAccessException(String message, Exception causer) {
super(message, causer);
}
}

View File

@ -16,14 +16,10 @@
// under the License.
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.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class Storage {
public static enum ImageFormat {
@ -139,6 +135,21 @@ public class Storage {
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
* 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
* package available on both management server and agent plugin jars.
*/
public static class StoragePoolType {
private static final Map<String, StoragePoolType> map = new LinkedHashMap<>();
public static enum StoragePoolType {
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 overProvisioning;
private final boolean encryption;
private final 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;
StoragePoolType(boolean shared, boolean overProvisioning, EncryptionSupport encryption) {
this.shared = shared;
this.overProvisioning = overProvisioning;
this.encryption = encryption;
addStoragePoolType(this);
}
public boolean isShared() {
@ -216,50 +203,12 @@ public class Storage {
}
public boolean supportsEncryption() {
return encryption == EncryptionSupport.Hypervisor || encryption == EncryptionSupport.Storage;
}
public EncryptionSupport encryptionSupportMode() {
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() {

View File

@ -63,6 +63,7 @@ public class ApiConstants {
public static final String BASE64_IMAGE = "base64image";
public static final String BGP_PEERS = "bgppeers";
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 BOOTABLE = "bootable";
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_BYTES = "sentbytes";
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 SESSIONKEY = "sessionkey";
public static final String SHOW_CAPACITIES = "showcapacities";
@ -485,11 +485,12 @@ public class ApiConstants {
public static final String STATE = "state";
public static final String STATS = "stats";
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_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 OWNER = "owner";
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 BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
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 GSLB_PROVIDER = "gslbprovider";
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 " +
"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.";
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 " +
"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 " +
"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.
* 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
@SerializedName("memoryallocated")
@Param(description = "the amount of the host's memory currently allocated")
private long memoryAllocated;
private Long memoryAllocated;
@SerializedName("memoryallocatedpercentage")
@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;
}
public void setMemoryAllocated(long memoryAllocated) {
public void setMemoryAllocated(Long memoryAllocated) {
this.memoryAllocated = memoryAllocated;
}
@ -703,8 +703,8 @@ public class HostResponse extends BaseResponseWithAnnotations {
return memoryTotal;
}
public long getMemoryAllocated() {
return memoryAllocated;
public Long getMemoryAllocated() {
return memoryAllocated == null ? 0 : memoryAllocated;
}
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")
private String kernelVersion;
@SerializedName(ApiConstants.SERVICE_IP)
@SerializedName(ApiConstants.IP_ADDRESS)
@Param(description = "the IP Address for this Management Server")
private String serviceIp;
private String ipAddress;
@SerializedName(ApiConstants.PEERS)
@Param(description = "the Management Server Peers")
@ -130,8 +130,8 @@ public class ManagementServerResponse extends BaseResponse {
return lastBoot;
}
public String getServiceIp() {
return serviceIp;
public String getIpAddress() {
return ipAddress;
}
public Long getAgentsCount() {
@ -186,8 +186,8 @@ public class ManagementServerResponse extends BaseResponse {
this.kernelVersion = kernelVersion;
}
public void setServiceIp(String serviceIp) {
this.serviceIp = serviceIp;
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
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 {
volService.grantAccess(volFactory.getVolume(newVol.getId()), host, destPool);
} 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 {
volService.grantAccess(volFactory.getVolume(volumeId), host, volumeStore);
} 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 {
volService.grantAccess(volFactory.getVolume(vol.getId()), host, store);
} 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 {
grantVolumeAccessToHostIfNeeded(store, vol.getId(), host, volToString);

View File

@ -20,8 +20,9 @@ import java.util.Collection;
import java.util.Map;
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);
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 com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
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> DetailSearch;
@ -44,11 +45,11 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long
protected ClusterDetailsDaoImpl() {
ClusterSearch = createSearchBuilder();
ClusterSearch.and("clusterId", ClusterSearch.entity().getClusterId(), SearchCriteria.Op.EQ);
ClusterSearch.and("clusterId", ClusterSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
ClusterSearch.done();
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.done();
}
@ -68,6 +69,11 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long
return detail;
}
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new ClusterDetailsVO(resourceId, key, value));
}
@Override
public Map<String, String> findDetails(long clusterId) {
SearchCriteria<ClusterDetailsVO> sc = ClusterSearch.create();
@ -91,7 +97,7 @@ public class ClusterDetailsDaoImpl extends GenericDaoBase<ClusterDetailsVO, Long
return new HashMap<>();
}
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.done();
SearchCriteria<ClusterDetailsVO> sc = sb.create();

View File

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

View File

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

View File

@ -20,8 +20,9 @@ import java.util.Map;
import com.cloud.domain.DomainDetailVO;
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);
void persist(long domainId, Map<String, String> details);
@ -31,6 +32,4 @@ public interface DomainDetailsDao extends GenericDao<DomainDetailVO, Long> {
void deleteDetails(long domainId);
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.ScopedConfigStorage;
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.DomainVO;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
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;
@Inject
@ -47,14 +45,14 @@ public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> i
protected DomainDetailsDaoImpl() {
domainSearch = createSearchBuilder();
domainSearch.and("domainId", domainSearch.entity().getDomainId(), Op.EQ);
domainSearch.and("domainId", domainSearch.entity().getResourceId(), Op.EQ);
domainSearch.done();
}
@Override
public Map<String, String> findDetails(long domainId) {
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();
Map<String, String> details = new HashMap<String, String>(results.size());
for (DomainDetailVO r : results) {
@ -80,11 +78,16 @@ public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> i
@Override
public DomainDetailVO findDetail(long domainId, String name) {
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);
return sc.find();
}
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new DomainDetailVO(resourceId, key, value));
}
@Override
public void deleteDetails(long domainId) {
SearchCriteria<DomainDetailVO> sc = domainSearch.create();
@ -129,13 +132,4 @@ public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> i
}
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
public String getConfigValue(long id, String key) {
StoragePoolDetailVO vo = findDetail(id, key);
return vo == null ? null : vo.getValue();
return vo == null ? null : getActualValue(vo);
}
@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;
try {
filePath = Files.createTempDirectory(TEMPORARY_SECONDARY_STORE).toString();
@ -347,6 +347,9 @@ public class SystemVmTemplateRegistration {
String templatePath = filePath + File.separator + partialDirPath;
File templateProps = new File(templatePath + "/template.properties");
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");
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) {
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);
Long size = null;
Long physicalSize = 0L;
@ -574,8 +592,13 @@ public class SystemVmTemplateRegistration {
} catch (IOException ex) {
LOGGER.warn("Failed to read from template.properties", ex);
}
details.setSize(size);
details.setPhysicalSize(physicalSize);
return new Pair<>(size, 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) {
@ -799,7 +822,7 @@ public class SystemVmTemplateRegistration {
TemplateDataStoreVO templateDataStoreVO = templateDataStoreDao.findByStoreTemplate(storeUrlAndId.second(), templateId);
if (templateDataStoreVO != null) {
String installPath = templateDataStoreVO.getInstallPath();
if (validateIfSeeded(storeUrlAndId.first(), installPath, nfsVersion)) {
if (validateIfSeeded(templateDataStoreVO, storeUrlAndId.first(), installPath, nfsVersion)) {
continue;
}
}

View File

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

View File

@ -19,8 +19,9 @@ package com.cloud.user;
import java.util.Map;
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);
void persist(long accountId, Map<String, String> details);
@ -34,6 +35,4 @@ public interface AccountDetailsDao extends GenericDao<AccountDetailVO, Long> {
* they will get created
*/
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.ScopedConfigStorage;
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.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.domain.dao.DomainDetailsDao;
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.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
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;
@Inject
@ -56,16 +54,16 @@ public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long>
protected AccountDetailsDaoImpl() {
accountSearch = createSearchBuilder();
accountSearch.and("accountId", accountSearch.entity().getAccountId(), Op.EQ);
accountSearch.and("accountId", accountSearch.entity().getResourceId(), Op.EQ);
accountSearch.done();
}
@Override
public Map<String, String> findDetails(long accountId) {
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();
Map<String, String> details = new HashMap<String, String>(results.size());
Map<String, String> details = new HashMap<>(results.size());
for (AccountDetailVO r : results) {
details.put(r.getName(), r.getValue());
}
@ -89,11 +87,16 @@ public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long>
@Override
public AccountDetailVO findDetail(long accountId, String name) {
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);
return sc.find();
}
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new AccountDetailVO(resourceId, key, value));
}
@Override
public void deleteDetails(long accountId) {
SearchCriteria<AccountDetailVO> sc = accountSearch.create();
@ -153,13 +156,4 @@ public class AccountDetailsDaoImpl extends GenericDaoBase<AccountDetailVO, Long>
}
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
* @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
* @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
@ -84,21 +84,23 @@ public interface ResourceDetailsDao<R extends ResourceDetail> extends GenericDao
* @param forDisplay
* @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);
public Map<String, String> listDetailsKeyPairs(long resourceId, boolean forDisplay);
Map<String, String> listDetailsKeyPairs(long resourceId, boolean forDisplay);
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.stream.Collectors;
import org.apache.cloudstack.api.ResourceDetail;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
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.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> {
@Inject
private ConfigurationDao configDao;
private SearchBuilder<R> AllFieldsSearch;
public ResourceDetailsDaoBase() {
@ -76,8 +86,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("value", value);
}
List<R> results = search(sc, null);
return results;
return search(sc, null);
}
public Map<String, String> listDetailsKeyPairs(long resourceId) {
@ -85,7 +94,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("resourceId", resourceId);
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) {
details.put(result.getName(), result.getValue());
}
@ -122,8 +131,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
SearchCriteria<R> sc = AllFieldsSearch.create();
sc.setParameters("resourceId", resourceId);
List<R> results = search(sc, null);
return results;
return search(sc, null);
}
public void removeDetails(long resourceId) {
@ -185,7 +193,7 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("display", forDisplay);
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) {
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("display", forDisplay);
List<R> results = search(sc, null);
return results;
return search(sc, null);
}
@Override
@ -230,4 +237,13 @@ public abstract class ResourceDetailsDaoBase<R extends ResourceDetail> extends G
sc.setParameters("ids", ids.toArray());
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
public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreDetailVO> implements ImageStoreDetailsDao, ScopedConfigStorage {
protected final SearchBuilder<ImageStoreDetailVO> storeSearch;
public ImageStoreDetailsDaoImpl() {
@ -67,7 +66,7 @@ public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreD
sc.setParameters("store", storeId);
List<ImageStoreDetailVO> details = listBy(sc);
Map<String, String> detailsMap = new HashMap<String, String>();
Map<String, String> detailsMap = new HashMap<>();
for (ImageStoreDetailVO detail : details) {
String name = detail.getName();
String value = detail.getValue();
@ -110,9 +109,14 @@ public class ImageStoreDetailsDaoImpl extends ResourceDetailsDaoBase<ImageStoreD
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
public void addDetail(long resourceId, String key, String value, boolean 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) {
SearchCriteria<StoragePoolVO> ssc = createSearchCriteria();
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);
}

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_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
DELETE FROM `cloud`.`mshost_peer`;
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.DataStore;
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.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
@ -1534,6 +1535,16 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
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;
final boolean computeClusterSupportsVolumeClone;
@ -1641,7 +1652,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
errMsg = "Create volume from template failed: " + ex.getMessage();
}
throw new CloudRuntimeException(errMsg);
throw new CloudRuntimeException(errMsg, ex);
}
finally {
if (copyCmdAnswer == null) {
@ -2634,7 +2645,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
catch (Exception ex) {
errMsg = ex.getMessage();
throw new CloudRuntimeException(errMsg);
throw new CloudRuntimeException(errMsg, ex);
}
finally {
if (copyCmdAnswer == null) {

View File

@ -622,7 +622,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
Thread.sleep(sleepTime * 1000);
} catch (InterruptedException e) {
logger.debug("waiting for template download been interrupted: " + e.toString());
logger.debug("waiting for template download been interrupted: " + e);
}
tries--;
}
@ -691,7 +691,6 @@ public class VolumeServiceImpl implements VolumeService {
}
_tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
}
return;
}
protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, ManagedCreateBaseImageContext<VolumeApiResult> context) {
@ -1039,7 +1038,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
grantAccess(templateOnPrimary, destHost, destPrimaryDataStore);
} 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);
@ -1161,7 +1160,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
grantAccess(srcTemplateOnPrimary, destHost, destPrimaryDataStore);
} 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);
@ -1408,7 +1407,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
grantAccess(templateOnPrimary, destHost, destPrimaryDataStore);
} 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);

View File

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

View File

@ -48,7 +48,7 @@ public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, App
* can use this.
*/
String registryBeanName;
Set<Object> beans = new HashSet<Object>();
Set<Object> beans = new HashSet<>();
Class<?> typeClass;
ApplicationContext applicationContext;
Set<String> excludes = null;
@ -79,7 +79,7 @@ public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, App
protected synchronized void loadExcluded() {
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*")) {
if (StringUtils.hasText(exclude)) {
excludes.add(exclude);
@ -109,11 +109,16 @@ public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, App
while (iter.hasNext()) {
Object next = iter.next();
try {
if (registry.register(next)) {
logger.debug("Registered " + next);
} else {
logger.warn("Bean registration failed for " + next.toString());
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 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, Pair<Role, List<RolePermission>>> rolePermissionsCache;
@ -56,7 +56,7 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API
protected DynamicRoleBasedAPIAccessChecker() {
super();
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.setPhysicalBlockIOSize(pool.getSupportedPhysicalBlockSize());
if (diskBusType == DiskDef.DiskBus.SCSI ) {
if (diskBusType == DiskDef.DiskBus.SCSI || diskBusType == DiskDef.DiskBus.VIRTIOBLK) {
disk.setQemuDriver(true);
disk.setDiscard(DiscardType.UNMAP);
}
@ -3226,7 +3226,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
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());
DiskDef.LibvirtDiskEncryptDetails encryptDetails = new DiskDef.LibvirtDiskEncryptDetails(secretUuid, QemuObject.EncryptFormat.enumValue(volumeObjectTO.getEncryptFormat()));
disk.setLibvirtDiskEncryptDetails(encryptDetails);

View File

@ -248,7 +248,7 @@ public class LibvirtVMDef {
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("</os>\n");
@ -680,7 +680,7 @@ public class LibvirtVMDef {
}
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;
DiskBus(String bus) {

View File

@ -122,7 +122,10 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
instance.setName(domain.getName());
instance.setCpuCores((int) LibvirtComputingResource.countDomainRunningVcpus(domain));
if (parser.getCpuTuneDef() != null && instance.getCpuCores() != null) {
instance.setCpuSpeed(parser.getCpuTuneDef().getShares()/instance.getCpuCores());
}
if (parser.getCpuModeDef() != null) {
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.MigrationOptions;
import com.cloud.storage.ScopeType;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageLayer;
@ -161,7 +162,7 @@ public class KVMStorageProcessor implements StorageProcessor {
/**
* Time interval before rechecking virsh commands
*/
private long waitDelayForVirshCommands = 1000l;
private final long waitDelayForVirshCommands = 1000L;
public KVMStorageProcessor(final KVMStoragePoolManager storagePoolMgr, final LibvirtComputingResource resource) {
this.storagePoolMgr = storagePoolMgr;
@ -258,7 +259,7 @@ public class KVMStorageProcessor implements StorageProcessor {
logger.debug("Copying template to primary storage, template format is " + tmplVol.getFormat() );
final KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
KVMPhysicalDisk primaryVol = null;
KVMPhysicalDisk primaryVol;
if (destData instanceof VolumeObjectTO) {
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
@ -277,8 +278,13 @@ public class KVMStorageProcessor implements StorageProcessor {
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());
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());
@ -336,12 +342,13 @@ public class KVMStorageProcessor implements StorageProcessor {
}
private String derivePath(PrimaryDataStoreTO primaryStore, DataTO destData, Map<String, String> details) {
String path = null;
String path;
if (primaryStore.getPoolType() == StoragePoolType.FiberChannel) {
path = destData.getPath();
} else {
path = details != null ? details.get("managedStoreTarget") : null;
}
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));
}
final KVMPhysicalDisk primaryVol = storagePoolMgr.copyPhysicalDisk(templateVol, volUuid, primaryPool, timeout);
return primaryVol;
return storagePoolMgr.copyPhysicalDisk(templateVol, volUuid, primaryPool, timeout);
} catch (final CloudRuntimeException e) {
logger.error("Failed to download template to primary storage", e);
return null;
@ -410,9 +416,9 @@ public class KVMStorageProcessor implements StorageProcessor {
final DataStoreTO imageStore = template.getDataStore();
final VolumeObjectTO volume = (VolumeObjectTO)destData;
final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
KVMPhysicalDisk BaseVol = null;
KVMStoragePool primaryPool = null;
KVMPhysicalDisk vol = null;
KVMPhysicalDisk BaseVol;
KVMStoragePool primaryPool;
KVMPhysicalDisk vol;
try {
primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
@ -420,7 +426,7 @@ public class KVMStorageProcessor implements StorageProcessor {
String templatePath = template.getPath();
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());
} if (storagePoolMgr.supportsPhysicalDiskCopy(primaryPool.getType())) {
Map<String, String> details = primaryStore.getDetails();
@ -778,17 +784,21 @@ public class KVMStorageProcessor implements StorageProcessor {
KVMStoragePool secondaryStorage = null;
String path = null;
try {
// 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
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) {
path = details != null ? details.get(DiskTO.IQN) : null;
if (path == null) {
path = srcData.getPath();
if (path == null) {
new CloudRuntimeException("The 'path' or 'iqn' field must be specified.");
}
}
}
storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details);
@ -849,8 +859,6 @@ public class KVMStorageProcessor implements StorageProcessor {
loc.addFormat(info);
loc.save();
storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path);
TemplateObjectTO newTemplate = new TemplateObjectTO();
newTemplate.setPath(templateFolder + File.separator + templateName + ".qcow2");
@ -870,6 +878,10 @@ public class KVMStorageProcessor implements StorageProcessor {
return new CopyCmdAnswer(ex.toString());
} finally {
if (path != null) {
storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path);
}
if (secondaryStorage != null) {
secondaryStorage.delete();
}
@ -1045,7 +1057,9 @@ public class KVMStorageProcessor implements StorageProcessor {
command.add(NAME_OPTION, snapshotName);
command.add("-p", snapshotDestPath);
if (isCreatedFromVmSnapshot) {
descName = UUID.randomUUID().toString();
}
command.add("-t", descName);
final String result = command.execute();
@ -1415,12 +1429,14 @@ public class KVMStorageProcessor implements StorageProcessor {
if (disk.getDeviceType() == DeviceType.DISK) {
if (disk.getBusType() == DiskDef.DiskBus.SCSI) {
busT = DiskDef.DiskBus.SCSI;
} else if (disk.getBusType() == DiskDef.DiskBus.VIRTIOBLK) {
busT = DiskDef.DiskBus.VIRTIOBLK;
}
break;
}
}
diskdef = new DiskDef();
if (busT == DiskDef.DiskBus.SCSI) {
if (busT == DiskDef.DiskBus.SCSI || busT == DiskDef.DiskBus.VIRTIOBLK) {
diskdef.setQemuDriver(true);
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);
}

View File

@ -162,6 +162,13 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor {
KVMPhysicalDisk disk = new KVMPhysicalDisk(address.getPath(), address.toString(), pool);
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());
disk.setSize(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
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
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");
@ -510,6 +521,18 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor {
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) {
if (StringUtils.isEmpty(diskPath)) {
return 0;

View File

@ -6531,4 +6531,14 @@ public class LibvirtComputingResourceTest {
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.UUID;
import com.cloud.agent.api.CleanupVMCommand;
import javax.inject.Inject;
import com.cloud.agent.api.to.NfsTO;
@ -370,6 +371,13 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
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) {
List<Command> commands = new ArrayList<Command>();
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.exception.DiscoveryException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.storage.StoragePool;
import com.cloud.utils.Pair;
import com.cloud.utils.component.PluggableService;
import com.cloud.utils.exception.CloudRuntimeException;
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.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.ListVsphereStoragePoliciesCmd;
import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd;
@ -53,5 +56,7 @@ public interface VmwareDatacenterService extends PluggableService {
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.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.rmi.RemoteException;
import java.time.Duration;
import java.time.Instant;
@ -43,10 +45,11 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
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.ImportVsphereStoragePoliciesCmd;
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.ListVsphereStoragePoliciesCmd;
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.ClusterVSMMapVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.VmwareDatacenter;
import com.cloud.dc.VsphereStoragePolicy;
import com.cloud.dc.VsphereStoragePolicyVO;
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.vmware.LegacyZoneVO;
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.dc.VmwareDatacenterVO;
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.dao.UserVmCloneSettingDao;
import com.cloud.vm.dao.VMInstanceDao;
// TODO move these items upstream?
import com.vmware.pbm.PbmProfile;
import com.vmware.vim25.AboutInfo;
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 {
@ -245,11 +257,11 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private StorageLayer _storage;
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 _instanceNameFlag;
private String _serviceConsoleName;
private String _managemetPortGroupName;
private String _managementPortGroupName;
private String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString();
private String _recycleHungWorker = "false";
private int _additionalPortRangeStart;
@ -263,7 +275,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
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 GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op");
@ -347,9 +359,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
_serviceConsoleName = "Service Console";
}
_managemetPortGroupName = _configDao.getValue(Config.VmwareManagementPortGroup.key());
if (_managemetPortGroupName == null) {
_managemetPortGroupName = "Management Network";
_managementPortGroupName = _configDao.getValue(Config.VmwareManagementPortGroup.key());
if (_managementPortGroupName == null) {
_managementPortGroupName = "Management Network";
}
_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);
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) {
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();
if (about != null) {
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;
}
}
@ -480,7 +492,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
}
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) {
return null;
}
@ -496,19 +508,18 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
throw new CloudRuntimeException("Invalid serviceContext");
}
ManagedObjectReference mor = serviceContext.getHostMorByPath(hostInventoryPath);
String privateTrafficLabel = null;
String privateTrafficLabel;
privateTrafficLabel = serviceContext.getStockObject("privateTrafficLabel");
if (privateTrafficLabel == null) {
privateTrafficLabel = _privateNetworkVSwitchName;
}
if (mor != null) {
List<ManagedObjectReference> returnedHostList = new ArrayList<ManagedObjectReference>();
List<ManagedObjectReference> returnedHostList = new ArrayList<>();
if (mor.getType().equals("ComputeResource")) {
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
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");
assert (hosts != null);
if (hosts.size() > 0) {
AboutInfo about = (AboutInfo)(serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product"));
if (!hosts.isEmpty()) {
AboutInfo about = serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product");
String version = about.getApiVersion();
int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster(HypervisorType.VMware, version);
if (hosts.size() > maxHostsPerCluster) {
@ -549,7 +560,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
returnedHostList.add(mor);
return returnedHostList;
} 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;
}
}
@ -614,13 +625,13 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override
public String getManagementPortGroupName() {
return _managemetPortGroupName;
return _managementPortGroupName;
}
@Override
public String getManagementPortGroupByHost(HostMO hostMo) throws Exception {
if (hostMo.getHostType() == VmwareHostType.ESXi) {
return _managemetPortGroupName;
return _managementPortGroupName;
}
return _serviceConsoleName;
}
@ -630,7 +641,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
params.put("vmware.create.full.clone", _fullCloneFlag);
params.put("vm.instancename.flag", _instanceNameFlag);
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.data.disk.controller", _dataDiskController);
params.put("vmware.recycle.hung.wokervm", _recycleHungWorker);
@ -657,23 +668,23 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return false;
}
String tokens[] = workerTag.split("-");
String[] tokens = workerTag.split("-");
if (tokens.length != 3) {
logger.error("Invalid worker VM tag " + workerTag);
return false;
}
long startTick = Long.parseLong(tokens[0]);
long msid = Long.parseLong(tokens[1]);
long runid = Long.parseLong(tokens[2]);
long msId = Long.parseLong(tokens[1]);
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())
logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it");
return true;
}
if (runid != clusterManager.getManagementRunId(msid)) {
if (runId != clusterManager.getManagementRunId(msId)) {
if (logger.isInfoEnabled())
logger.info("Worker VM's owner management server has changed runid, recycle it");
return true;
@ -710,7 +721,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
File patchFolder = new File(mountPoint + "/systemvm");
if (!patchFolder.exists()) {
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);
throw new CloudRuntimeException(msg);
}
@ -729,7 +740,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
} catch (IOException 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);
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");
}
assert (isoFile != null);
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;
}
@ -788,16 +798,16 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if (keyFile == null || !keyFile.exists()) {
keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud");
}
assert (keyFile != null);
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;
}
@Override
public String getMountPoint(String storageUrl, String nfsVersion) {
String mountPoint = null;
String mountPoint;
synchronized (_storageMounts) {
mountPoint = _storageMounts.get(storageUrl);
if (mountPoint != null) {
@ -827,7 +837,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String mountPoint = null;
long mshostId = ManagementServerNode.getManagementServerId();
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);
if (!file.exists()) {
if (_storage.mkdir(mntPt)) {
@ -852,10 +862,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
for (String mountPoint : mounts) {
logger.info("umount NFS mount from previous session: " + mountPoint);
String result = null;
Script command = new Script(true, "umount", _timeout, logger);
command.add(mountPoint);
result = command.execute();
String result = command.execute();
if (result != null) {
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()) {
logger.info("umount NFS mount: " + mountPoint);
String result = null;
Script command = new Script(true, "umount", _timeout, logger);
command.add(mountPoint);
result = command.execute();
String result = command.execute();
if (result != null) {
logger.warn("Unable to umount " + mountPoint + " due to " + result);
}
@ -894,8 +902,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return null;
}
Script script = null;
String result = null;
Script script;
String result;
Script command = new Script(true, "mount", _timeout, logger);
command.add("-t", "nfs");
if (nfsVersion != null){
@ -982,11 +990,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
if (cmd instanceof StartupCommand) {
if (cmd != null) {
if (host.getHypervisorType() == HypervisorType.VMware) {
updateClusterNativeHAState(host, cmd);
} else {
return;
}
}
}
@ -1056,16 +1062,16 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override
public Pair<Integer, Integer> getAddiionalVncPortRange() {
return new Pair<Integer, Integer>(_additionalPortRangeStart, _additionalPortRangeSize);
return new Pair<>(_additionalPortRangeStart, _additionalPortRangeSize);
}
@Override
public Map<String, String> getNexusVSMCredentialsByClusterId(Long clusterId) {
CiscoNexusVSMDeviceVO nexusVSM = null;
ClusterVSMMapVO vsmMapVO = null;
CiscoNexusVSMDeviceVO nexusVSM;
ClusterVSMMapVO vsmMapVO;
vsmMapVO = _vsmMapDao.findByClusterId(clusterId);
long vsmId = 0;
long vsmId;
if (vsmMapVO != null) {
vsmId = vsmMapVO.getVsmId();
logger.info("vsmId is " + vsmId);
@ -1076,7 +1082,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
return null;
}
Map<String, String> nexusVSMCredentials = new HashMap<String, String>();
Map<String, String> nexusVSMCredentials = new HashMap<>();
if (nexusVSM != null) {
nexusVSMCredentials.put("vsmip", nexusVSM.getipaddr());
nexusVSMCredentials.put("vsmusername", nexusVSM.getUserName());
@ -1103,7 +1109,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<Class<?>>();
List<Class<?>> cmdList = new ArrayList<>();
cmdList.add(AddVmwareDcCmd.class);
cmdList.add(UpdateVmwareDcCmd.class);
cmdList.add(RemoveVmwareDcCmd.class);
@ -1112,13 +1118,14 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
cmdList.add(ListVsphereStoragePoliciesCmd.class);
cmdList.add(ListVsphereStoragePolicyCompatiblePoolsCmd.class);
cmdList.add(ListVmwareDcVmsCmd.class);
cmdList.add(ListVmwareDcHostsCmd.class);
return cmdList;
}
@Override
@DB
public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws ResourceInUseException {
VmwareDatacenterVO vmwareDc = null;
VmwareDatacenterVO vmwareDc;
Long zoneId = cmd.getZoneId();
String userName = cmd.getUsername();
String password = cmd.getPassword();
@ -1174,10 +1181,10 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
checkIfDcIsUsed(vCenterHost, vmwareDcName, zoneId);
VmwareContext context = null;
DatacenterMO dcMo = null;
DatacenterMO dcMo;
String dcCustomFieldValue;
boolean addDcCustomFieldDef = false;
boolean dcInUse = false;
boolean dcInUse;
String guid;
ManagedObjectReference dcMor;
try {
@ -1210,7 +1217,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
// Map zone with vmware datacenter
vmwareDcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDc.getId());
vmwareDcZoneMap = vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap);
vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap);
// Set custom field for this DC
if (addDcCustomFieldDef) {
@ -1230,7 +1237,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if (context != null) {
context.close();
}
context = null;
}
importVsphereStoragePoliciesInternal(zoneId, vmwareDc.getId());
return vmwareDc;
@ -1255,9 +1261,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
* 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
*
* @param vCenterHost
* @param vmwareDcName
* @param zoneId
* @param vCenterHost the vcenter appliance hostname
* @param vmwareDcName the name of the vmware DC
* @param zoneId zone that the DC should be connected to
* @throws ResourceInUseException if the DC can not be used.
*/
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);
if (vmwareDc != null) {
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));
}
}
@ -1274,7 +1280,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
@Override
@ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "updating VMware datacenter")
public VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd cmd) {
final Long zoneId = cmd.getZoneId();
final long zoneId = cmd.getZoneId();
final String userName = cmd.getUsername();
final String password = cmd.getPassword();
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()));
return Transaction.execute(new TransactionCallback<VmwareDatacenter>() {
return Transaction.execute(new TransactionCallback<>() {
@Override
public VmwareDatacenter doInTransaction(TransactionStatus status) {
if (vmwareDcDao.update(vmwareDc.getId(), vmwareDc)) {
@ -1351,7 +1357,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String vCenterHost;
String userName;
String password;
DatacenterMO dcMo = null;
DatacenterMO dcMo;
final VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId);
// Check if zone is associated with VMware DC
if (vmwareDcZoneMap == null) {
@ -1388,11 +1394,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
throw new DiscoveryException(msg);
}
assert (dcMo != null);
// Reset custom field property cloud.zone over this DC
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) {
String msg = "Unable to reset custom field property cloud.zone over DC " + vmwareDcName + " due to : " + VmwareHelper.getExceptionMessage(e);
logger.error(msg);
@ -1401,7 +1405,6 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
if (context != null) {
context.close();
}
context = null;
}
return true;
}
@ -1422,7 +1425,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
private void validateZoneWithResources(Long zoneId, String errStr) throws ResourceInUseException {
// Check if zone has resources? - For now look for clusters
List<ClusterVO> clusters = clusterDao.listByZoneId(zoneId);
if (clusters != null && clusters.size() > 0) {
if (!CollectionUtils.isNullOrEmpty(clusters)) {
// Look for VMware hypervisor.
for (ClusterVO cluster : clusters) {
if (cluster.getHypervisorType().equals(HypervisorType.VMware)) {
@ -1443,9 +1446,9 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
}
@Override
public List<? extends VmwareDatacenter> listVmwareDatacenters(ListVmwareDcsCmd cmd) throws CloudRuntimeException, InvalidParameterValueException {
public List<? extends VmwareDatacenter> listVmwareDatacenters(ListVmwareDcsCmd cmd) throws CloudRuntimeException {
Long zoneId = cmd.getZoneId();
List<VmwareDatacenterVO> vmwareDcList = new ArrayList<VmwareDatacenterVO>();
List<VmwareDatacenterVO> vmwareDcList = new ArrayList<>();
VmwareDatacenterZoneMapVO vmwareDcZoneMap;
VmwareDatacenterVO vmwareDatacenter;
long vmwareDcId;
@ -1503,7 +1506,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
String vCenterHost = vmwareDatacenter.getVcenterHost();
String userName = vmwareDatacenter.getUser();
String password = vmwareDatacenter.getPassword();
List<PbmProfile> storageProfiles = null;
List<PbmProfile> storageProfiles;
try {
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);
@ -1531,16 +1534,15 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
List<VsphereStoragePolicyVO> allStoragePolicies = vsphereStoragePolicyDao.listAll();
List<PbmProfile> finalStorageProfiles = storageProfiles;
List<VsphereStoragePolicyVO> needToMarkRemoved = allStoragePolicies.stream()
.filter(existingPolicy -> !finalStorageProfiles.stream()
.anyMatch(storageProfile -> storageProfile.getProfileId().getUniqueId().equals(existingPolicy.getPolicyId())))
.filter(existingPolicy -> finalStorageProfiles.stream()
.noneMatch(storageProfile -> storageProfile.getProfileId().getUniqueId().equals(existingPolicy.getPolicyId())))
.collect(Collectors.toList());
for (VsphereStoragePolicyVO storagePolicy : needToMarkRemoved) {
vsphereStoragePolicyDao.remove(storagePolicy.getId());
}
List<VsphereStoragePolicyVO> storagePolicies = vsphereStoragePolicyDao.listAll();
return storagePolicies;
return vsphereStoragePolicyDao.listAll();
}
@Override
@ -1586,13 +1588,87 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
}
@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 datacenterName = cmd.getDatacenterName();
String username = cmd.getUsername();
String password = cmd.getPassword();
Long existingVcenterId = cmd.getExistingVcenterId();
String keyword = cmd.getKeyword();
if ((existingVcenterId == null && StringUtils.isBlank(vcenter)) ||
(existingVcenterId != null && StringUtils.isNotBlank(vcenter))) {
@ -1613,37 +1689,27 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw
username = vmwareDc.getUser();
password = vmwareDc.getPassword();
}
try {
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);
VcenterData vmwaredc = new VcenterData(vcenter, datacenterName, username, password);
return vmwaredc;
}
List<UnmanagedInstanceTO> instances = dcMo.getAllVmsOnDatacenter();
return StringUtils.isBlank(keyword) ? instances :
instances.stream().filter(x -> x.getName().toLowerCase().contains(keyword.toLowerCase())).collect(Collectors.toList());
} catch (Exception e) {
String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s",
vcenter, datacenterName, e.getMessage());
logger.error(errorMsg, e);
throw new CloudRuntimeException(errorMsg);
private static class VcenterData {
public final String vcenter;
public final String datacenterName;
public final String username;
public final String password;
public VcenterData(String vcenter, String datacenterName, String username, String password) {
this.vcenter = vcenter;
this.datacenterName = datacenterName;
this.username = username;
this.password = password;
}
}
@Override
public boolean hasNexusVSM(Long clusterId) {
ClusterVSMMapVO vsmMapVo = null;
ClusterVSMMapVO vsmMapVo;
vsmMapVo = _vsmMapDao.findByClusterId(clusterId);
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 collect all templates that
* - are deleted from cloudstack

View File

@ -45,6 +45,7 @@ import java.util.TimeZone;
import java.util.UUID;
import java.util.stream.Collectors;
import com.cloud.agent.api.CleanupVMCommand;
import javax.naming.ConfigurationException;
import javax.xml.datatype.XMLGregorianCalendar;
@ -583,6 +584,8 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
return execute((ResizeVolumeCommand) cmd);
} else if (clz == UnregisterVMCommand.class) {
return execute((UnregisterVMCommand) cmd);
} else if (clz == CleanupVMCommand.class) {
return execute((CleanupVMCommand) cmd);
} else if (cmd instanceof StorageSubSystemCommand) {
checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand) cmd);
return storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd);
@ -5796,6 +5799,26 @@ public class VmwareResource extends ServerResourceBase implements StoragePoolRes
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) {
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);

View File

@ -36,8 +36,8 @@ import com.cloud.dc.VmwareDatacenterVO;
import com.cloud.user.Account;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = "addVmwareDc", description = "Adds a VMware datacenter to specified zone", responseObject = VmwareDatacenterResponse.class,
requestHasSensitiveInfo = true, responseHasSensitiveInfo = false)
@APICommand(name = "addVmwareDc", description = "Adds a Vmware datacenter to specified zone",
responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false)
public class AddVmwareDcCmd extends BaseCmd {
@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;
@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.")
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;
@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;
@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.setObjectName("vmwaredc");
} 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);
} catch (DiscoveryException ex) {

View File

@ -48,8 +48,6 @@ import java.util.List;
authorized = {RoleType.Admin})
public class ImportVsphereStoragePoliciesCmd extends BaseCmd {
@Inject
public VmwareDatacenterService _vmwareDatacenterService;
@ -74,6 +72,13 @@ public class ImportVsphereStoragePoliciesCmd extends BaseCmd {
List<? extends VsphereStoragePolicy> storagePolicies = _vmwareDatacenterService.importVsphereStoragePolicies(this);
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<>();
for (VsphereStoragePolicy storagePolicy : storagePolicies) {
final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse();
@ -86,9 +91,7 @@ public class ImportVsphereStoragePoliciesCmd extends BaseCmd {
storagePoliciesResponseList.add(storagePoliciesResponse);
}
responseList.setResponses(storagePoliciesResponseList);
responseList.setResponseName(getCommandName());
setResponseObject(responseList);
return storagePoliciesResponseList;
}
@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.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
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.Parameter;
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.VmwareDatacenterResponse;
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
@ -42,10 +42,10 @@ import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
@APICommand(name = "listVmwareDcVms", responseObject = UnmanagedInstanceResponse.class,
description = "Lists the VMs in a VMware Datacenter",
@APICommand(name = "listVmwareDcVms", responseObject = VmwareRequestResponse.class,
description = "Lists the VMs in a Vmware Datacenter",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListVmwareDcVmsCmd extends BaseListCmd {
public class ListVmwareDcVmsCmd extends BaseCmd implements ListVmwareDcItems {
@Inject
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.")
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;
@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.")
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() {
return vcenter;
}
@ -82,6 +94,18 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
return password;
}
public Integer getBatchSize() {
return batchSize;
}
public String getHost() {
return host;
}
public String getToken() {
return token;
}
public String getDatacenterName() {
return datacenterName;
}
@ -94,7 +118,8 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
checkParameters();
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<>();
if (CollectionUtils.isNotEmpty(vms)) {
for (UnmanagedInstanceTO vmwareVm : vms) {
@ -102,16 +127,13 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
baseResponseList.add(resp);
}
}
List<BaseResponse> pagingList = com.cloud.utils.StringUtils.applyPagination(baseResponseList, this.getStartIndex(), this.getPageSizeVal());
if (CollectionUtils.isEmpty(pagingList)) {
pagingList = baseResponseList;
}
ListResponse<BaseResponse> response = new ListResponse<>();
response.setResponses(pagingList, baseResponseList.size());
VmwareRequestResponse<BaseResponse> response = new VmwareRequestResponse<>();
response.setResponses(baseResponseList, baseResponseList.size());
response.setResponseName(getCommandName());
response.setToken(results.first());
setResponseObject(response);
} 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);
}
}
@ -134,6 +156,6 @@ public class ListVmwareDcVmsCmd extends BaseListCmd {
@Override
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.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)
public class ListVmwareDcsCmd extends BaseListCmd {
@ -50,7 +50,6 @@ public class ListVmwareDcsCmd extends BaseListCmd {
public VmwareDatacenterService _vmwareDatacenterService;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@ -73,20 +72,27 @@ public class ListVmwareDcsCmd extends BaseListCmd {
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException {
List<? extends VmwareDatacenter> vmwareDcList = null;
List<? extends VmwareDatacenter> vmwareDcList;
try {
vmwareDcList = _vmwareDatacenterService.listVmwareDatacenters(this);
} catch (InvalidParameterValueException ie) {
throw new InvalidParameterValueException("Invalid zone id " + getZoneId());
} 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>();
List<VmwareDatacenterResponse> vmwareDcResponses = new ArrayList<VmwareDatacenterResponse>();
ListResponse<VmwareDatacenterResponse> response = new ListResponse<>();
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) {
VmwareDatacenterResponse vmwareDcResponse = new VmwareDatacenterResponse();
@ -94,14 +100,12 @@ public class ListVmwareDcsCmd extends BaseListCmd {
vmwareDcResponse.setVcenter(vmwareDc.getVcenterHost());
vmwareDcResponse.setName(vmwareDc.getVmwareDatacenterName());
vmwareDcResponse.setZoneId(getZoneId());
vmwareDcResponse.setObjectName("VMwareDC");
vmwareDcResponse.setObjectName(ApiConstants.VMWARE_DC);
vmwareDcResponses.add(vmwareDcResponse);
}
}
response.setResponses(vmwareDcResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
return vmwareDcResponses;
}
@Override

View File

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

View File

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

View File

@ -34,7 +34,7 @@ import com.cloud.hypervisor.vmware.VmwareDatacenterService;
import com.cloud.user.Account;
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)
public class RemoveVmwareDcCmd extends BaseCmd {
@ -47,7 +47,7 @@ public class RemoveVmwareDcCmd extends BaseCmd {
type = CommandType.UUID,
entityType = ZoneResponse.class,
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;
public Long getZoneId() {
@ -63,7 +63,7 @@ public class RemoveVmwareDcCmd extends BaseCmd {
response.setResponseName(getCommandName());
setResponseObject(response);
} 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) {
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.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,
since = "4.12.0", authorized = {RoleType.Admin})
public class UpdateVmwareDcCmd extends BaseCmd {
@Inject
public VmwareDatacenterService vmwareDatacenterService;
@ -51,7 +50,7 @@ public class UpdateVmwareDcCmd extends BaseCmd {
private Long zoneId;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING,
description = "VMware datacenter name.")
description = "Vmware datacenter name.")
private String name;
@Parameter(name = ApiConstants.VCENTER, type = CommandType.STRING,
@ -106,13 +105,13 @@ public class UpdateVmwareDcCmd extends BaseCmd {
public void execute() {
final VmwareDatacenter vmwareDatacenter = vmwareDatacenterService.updateVmwareDatacenter(this);
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();
response.setId(vmwareDatacenter.getUuid());
response.setName(vmwareDatacenter.getVmwareDatacenterName());
response.setResponseName(getCommandName());
response.setObjectName("vmwaredc");
response.setObjectName(ApiConstants.VMWARE_DC);
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.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
@ -206,14 +204,12 @@ public class KubernetesClusterActionWorker {
protected String getControlNodeLoginUser() {
List<KubernetesClusterVmMapVO> vmMapVOList = getKubernetesClusterVMMaps();
if (vmMapVOList.size() > 0) {
if (!vmMapVOList.isEmpty()) {
long vmId = vmMapVOList.get(0).getVmId();
UserVmVO userVM = userVmDao.findById(vmId);
if (userVM == null) {
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);
if (vmDetail != null && !org.apache.commons.lang3.StringUtils.isEmpty(vmDetail.getValue())) {
return vmDetail.getValue();
@ -309,7 +305,7 @@ public class KubernetesClusterActionWorker {
}
protected KubernetesClusterVmMapVO addKubernetesClusterVm(final long kubernetesClusterId, final long vmId, boolean isControlNode) {
return Transaction.execute(new TransactionCallback<KubernetesClusterVmMapVO>() {
return Transaction.execute(new TransactionCallback<>() {
@Override
public KubernetesClusterVmMapVO doInTransaction(TransactionStatus status) {
KubernetesClusterVmMapVO newClusterVmMap = new KubernetesClusterVmMapVO(kubernetesClusterId, vmId, isControlNode);
@ -361,7 +357,12 @@ public class KubernetesClusterActionWorker {
}
IpAddress address = ipAddressDao.findByUuid(detailsVO.getValue());
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 address;
@ -517,8 +518,7 @@ public class KubernetesClusterActionWorker {
}
protected List<KubernetesClusterVmMapVO> getKubernetesClusterVMMaps() {
List<KubernetesClusterVmMapVO> clusterVMs = kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId());
return clusterVMs;
return kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId());
}
protected List<KubernetesClusterVmMapVO> getKubernetesClusterVMMapsForNodes(List<Long> nodeIds) {

View File

@ -193,7 +193,7 @@ public class KubernetesClusterUtil {
while (System.currentTimeMillis() < timeoutTime) {
try {
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);
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/),
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]
### Fixed
- Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev
## [2024-12-19]
### Added
- Native CloudStack encryption support
## [2024-12-13]
### Fixed

View File

@ -97,18 +97,23 @@ public final class LinstorBackupSnapshotCommandWrapper
// NOTE: the qemu img will also contain the drbd metadata at the end
final QemuImg qemu = new QemuImg(waitMilliSeconds);
qemu.convert(srcFile, dstFile);
LOGGER.info("Backup snapshot " + srcFile + " to " + dstPath);
LOGGER.info("Backup snapshot '{}' to '{}'", srcPath, dstPath);
return dstPath;
}
private SnapshotObjectTO setCorrectSnapshotSize(final SnapshotObjectTO dst, final String 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();
snapshot.setPath(dst.getPath() + File.separator + dst.getName());
snapshot.setPhysicalSize(size);
return snapshot;
dst.setPath(dst.getPath() + File.separator + dst.getName());
dst.setPhysicalSize(size);
return dst;
}
@Override
@ -158,6 +163,7 @@ public final class LinstorBackupSnapshotCommandWrapper
LOGGER.info("Backup shrunk " + dstPath + " to actual size " + src.getVolume().getSize());
SnapshotObjectTO snapshot = setCorrectSnapshotSize(dst, dstPath);
LOGGER.info("Actual file size for '{}' is {}", dstPath, snapshot.getPhysicalSize());
return new CopyCmdAnswer(snapshot);
} catch (final Exception e) {
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 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 {
protected Logger logger = LogManager.getLogger(getClass());
@ -202,10 +207,10 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
final DevelopersApi api = getLinstorAPI(pool);
try {
List<ResourceDefinition> definitionList = api.resourceDefinitionList(
Collections.singletonList(rscName), null, null, null);
ResourceDefinition resourceDefinition = LinstorUtil.findResourceDefinition(
api, rscName, lpool.getResourceGroup());
if (definitionList.isEmpty()) {
if (resourceDefinition == null) {
ResourceGroupSpawn rgSpawn = new ResourceGroupSpawn();
rgSpawn.setResourceDefinitionName(rscName);
rgSpawn.addVolumeSizesItem(size / 1024); // linstor uses KiB
@ -215,22 +220,28 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
handleLinstorApiAnswers(answers, "Linstor: Unable to spawn resource.");
}
String foundRscName = resourceDefinition != null ? resourceDefinition.getName() : rscName;
// query linstor for the device path
List<ResourceWithVolumes> resources = api.viewResources(
Collections.emptyList(),
Collections.singletonList(rscName),
Collections.singletonList(foundRscName),
Collections.emptyList(),
null,
null,
null);
makeResourceAvailable(api, rscName, false);
makeResourceAvailable(api, foundRscName, false);
if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) {
final String devPath = resources.get(0).getVolumes().get(0).getDevicePath();
logger.info("Linstor: Created drbd device: " + devPath);
final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool);
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;
} else {
logger.error("Linstor: viewResources didn't return resources or volumes.");
@ -410,7 +421,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
if (rsc.getFlags() != null &&
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) &&
!rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) {
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName);
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName, true);
logLinstorAnswers(delAnswers);
}
} catch (ApiException apiEx) {
@ -473,21 +484,56 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
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
public boolean deletePhysicalDisk(String name, KVMStoragePool pool, Storage.ImageFormat format)
{
logger.debug("Linstor: deletePhysicalDisk " + name);
final DevelopersApi api = getLinstorAPI(pool);
final String rscName = getLinstorRscName(name);
final LinstorStoragePool linstorPool = (LinstorStoragePool) pool;
String rscGrpName = linstorPool.getResourceGroup();
try {
final String rscName = getLinstorRscName(name);
logger.debug("Linstor: delete resource definition " + rscName);
ApiCallRcList answers = api.resourceDefinitionDelete(rscName);
handleLinstorApiAnswers(answers, "Linstor: Unable to delete resource definition " + rscName);
return deRefOrDeleteResource(api, rscName, rscGrpName);
} catch (ApiException apiEx) {
logger.error("Linstor: ApiEx - " + apiEx.getMessage());
throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx);
}
return true;
}
@Override
@ -561,6 +607,56 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
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
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);
final DevelopersApi api = getLinstorAPI(destPools);
applyAuxProps(api, name, disk.getDispName(), disk.getVmName());
setRscDfnAuxProperties(api, disk, destPools, name);
logger.debug("Linstor.copyPhysicalDisk: dstPath: {}", dstDisk.getPath());
final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath());
destFile.setFormat(dstDisk.getFormat());
destFile.setSize(disk.getVirtualSize());
boolean zeroedDevice = resourceSupportZeroBlocks(destPools, LinstorUtil.RSC_PREFIX + name);
boolean zeroedDevice = resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
try {
final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true);
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.model.ApiCallRc;
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.ResourceDefinition;
import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest;
import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted;
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.ResourceMakeAvailable;
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.Arrays;
@ -43,6 +49,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import com.cloud.agent.api.Answer;
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.StoragePool;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeDetailVO;
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.DataStore;
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.SnapshotInfo;
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.storage.RemoteHostEndPoint;
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.CreateObjectAnswer;
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.VolumeObjectTO;
import org.apache.cloudstack.storage.volume.VolumeObject;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.commons.collections.CollectionUtils;
import java.nio.charset.StandardCharsets;
public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver {
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);
}
logger.info(String.format("Linstor: Deleted resource %s", rscDefName));
logger.info("Linstor: Deleted resource {}", rscDefName);
} catch (ApiException apiEx)
{
logger.error("Linstor: ApiEx - " + apiEx.getMessage());
@ -394,22 +408,166 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
storagePoolVO.getUserInfo() : "DfltRscGrp";
}
private String createResourceBase(
String rscName, long sizeInBytes, String volName, String vmName, DevelopersApi api, String rscGrp) {
ResourceGroupSpawn rscGrpSpawn = new ResourceGroupSpawn();
rscGrpSpawn.setResourceDefinitionName(rscName);
rscGrpSpawn.addVolumeSizesItem(sizeInBytes / 1024);
/**
* Returns the layerlist of the resourceGroup with encryption(LUKS) added above STORAGE.
* If the resourceGroup layer list already contains LUKS this layer list will be returned.
* @param api Linstor developers API
* @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
{
logger.info("Linstor: Spawn resource " + rscName);
ApiCallRcList answers = api.resourceGroupSpawn(rscGrp, rscGrpSpawn);
checkLinstorAnswersThrow(answers);
logger.debug("createRscBase: {} :: {} :: {}", rscName, rscGrp, isTemplate);
List<Pair<ResourceDefinition, ResourceGroup>> existingRDs = LinstorUtil.getRDAndRGListStartingWith(api, rscName);
answers = LinstorUtil.applyAuxProps(api, rscName, volName, vmName);
checkLinstorAnswersThrow(answers);
return LinstorUtil.getDevicePath(api, rscName);
String fullRscName = String.format("%s-%d", rscName, poolId);
boolean alreadyCreated = existingRDs.stream()
.anyMatch(p -> p.first().getName().equalsIgnoreCase(fullRscName)) ||
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)
{
logger.error("Linstor: ApiEx - " + apiEx.getMessage());
@ -422,8 +580,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
final String rscGrp = getRscGrp(storagePoolVO);
final String rscName = LinstorUtil.RSC_PREFIX + vol.getUuid();
String deviceName = createResourceBase(
rscName, vol.getSize(), vol.getName(), vol.getAttachedVmName(), linstorApi, rscGrp);
createResourceBase(
rscName, vol.getSize(), vol.getName(), vol.getAttachedVmName(), vol.getPassphraseId(), vol.getPassphrase(),
linstorApi, rscGrp, storagePoolVO.getId(), false);
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) {
// get the cached template on this storage
VMTemplateStoragePoolVO tmplPoolRef = _vmTemplatePoolDao.findByPoolTemplate(
storagePoolVO.getId(), csCloneId, 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 DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress());
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();
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(
cloneRes, cloneRequest);
@ -479,6 +701,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
resizeResource(linstorApi, rscName, volumeInfo.getSize());
}
updateRscGrpIfNecessary(linstorApi, rscName, getRscGrp(storagePoolVO));
deleteTemplateForProps(linstorApi, rscName);
LinstorUtil.applyAuxProps(linstorApi, rscName, volumeInfo.getName(), volumeInfo.getAttachedVmName());
applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeInfo.getMaxIops());
@ -906,19 +1131,50 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
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) {
TemplateInfo tInfo = (TemplateInfo) dstData;
final StoragePoolVO pool = _storagePoolDao.findById(dstData.getDataStore().getId());
final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress());
final String rscName = LinstorUtil.RSC_PREFIX + dstData.getUuid();
createResourceBase(
boolean newCreated = createResourceBase(
LinstorUtil.RSC_PREFIX + dstData.getUuid(),
tInfo.getSize(),
tInfo.getName(),
"",
null,
null,
api,
getRscGrp(pool));
getRscGrp(pool),
pool.getId(),
true);
Answer answer;
if (newCreated) {
int nMaxExecutionMinutes = NumbersUtil.parseInt(
_configDao.getValue(Config.SecStorageCmdExecutionTimeMax.key()), 30);
CopyCommand cmd = new CopyCommand(
@ -926,14 +1182,12 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
dstData.getTO(),
nMaxExecutionMinutes * 60 * 1000,
VirtualMachineManager.ExecuteInSequence.value());
Answer answer;
try {
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
if (optEP.isPresent()) {
answer = optEP.get().sendMessage(cmd);
}
else {
} else {
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
deleteResourceDefinition(pool, rscName);
}
@ -942,6 +1196,10 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
deleteResourceDefinition(pool, rscName);
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;
}

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.ProviderKind;
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.ResourceGroup;
import com.linbit.linstor.api.model.ResourceWithVolumes;
@ -37,8 +38,11 @@ import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
@ -49,6 +53,7 @@ public class LinstorUtil {
public final static String PROVIDER_NAME = "Linstor";
public static final String RSC_PREFIX = "cs-";
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";
@ -288,4 +293,114 @@ public class LinstorUtil {
}
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
// THIN: tpvv=true, reduce=false
// SPARSE: tpvv=true, reduce=true
// THICK: tpvv=false, tpZeroFill=true (not supported)
// tpvv -- thin provisioned virtual volume (no deduplication)
// reduce -- thin provisioned virtual volume (with duplication and compression, also known as DECO)
// 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.getType() == ProvisioningType.THIN) {
request.setTpvv(true);
request.setReduce(false);
} else if (diskOffering.getType() == ProvisioningType.SPARSE) {
request.setTpvv(false);
request.setReduce(true);
} else if (diskOffering.getType() == ProvisioningType.SPARSE) {
request.setTpvv(true);
request.setReduce(false);
} else if (diskOffering.getType() == ProvisioningType.FAT) {
throw new RuntimeException("This storage provider does not support FAT provisioned volumes");
}
@ -166,8 +168,16 @@ public class PrimeraAdapter implements ProviderAdapter {
}
} else {
// default to deduplicated volume
request.setReduce(true);
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));
@ -185,8 +195,11 @@ public class PrimeraAdapter implements ProviderAdapter {
if (host == null) {
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.setAutoLun(true);
// 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) {
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) {
// hostString can be a hostname OR "set:<hostsetname>". It is stored this way
// 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.opensaml.version>2.6.6</cs.opensaml.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.servicemix.version>3.4.4_1</cs.servicemix.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)
for WWID in $(multipathd list maps status | awk '{ if ($4 == 0) { print substr($1,2); }}'); do
./removeVolume.sh ${WWID}
./disconnectVolume.sh ${WWID}
done
exit 0

View File

@ -66,6 +66,9 @@ fi
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"
exit 0

View File

@ -356,263 +356,263 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
private static final String ID_FIELD = "id";
@Inject
private AccountManager accountMgr;
AccountManager accountMgr;
@Inject
private ProjectManager _projectMgr;
ProjectManager _projectMgr;
@Inject
private DomainDao _domainDao;
DomainDao _domainDao;
@Inject
private DomainJoinDao _domainJoinDao;
DomainJoinDao _domainJoinDao;
@Inject
private UserAccountJoinDao _userAccountJoinDao;
UserAccountJoinDao _userAccountJoinDao;
@Inject
private EventDao eventDao;
EventDao eventDao;
@Inject
private EventJoinDao _eventJoinDao;
EventJoinDao _eventJoinDao;
@Inject
private ResourceTagJoinDao _resourceTagJoinDao;
ResourceTagJoinDao _resourceTagJoinDao;
@Inject
private InstanceGroupJoinDao _vmGroupJoinDao;
InstanceGroupJoinDao _vmGroupJoinDao;
@Inject
private UserVmJoinDao _userVmJoinDao;
UserVmJoinDao _userVmJoinDao;
@Inject
private UserVmDao userVmDao;
UserVmDao userVmDao;
@Inject
private VMInstanceDao _vmInstanceDao;
VMInstanceDao _vmInstanceDao;
@Inject
private SecurityGroupJoinDao _securityGroupJoinDao;
SecurityGroupJoinDao _securityGroupJoinDao;
@Inject
private SecurityGroupVMMapDao securityGroupVMMapDao;
SecurityGroupVMMapDao securityGroupVMMapDao;
@Inject
private DomainRouterJoinDao _routerJoinDao;
DomainRouterJoinDao _routerJoinDao;
@Inject
private ProjectInvitationJoinDao _projectInvitationJoinDao;
ProjectInvitationJoinDao _projectInvitationJoinDao;
@Inject
private ProjectJoinDao _projectJoinDao;
ProjectJoinDao _projectJoinDao;
@Inject
private ProjectDao _projectDao;
ProjectDao _projectDao;
@Inject
private ProjectAccountDao _projectAccountDao;
ProjectAccountDao _projectAccountDao;
@Inject
private ProjectAccountJoinDao _projectAccountJoinDao;
ProjectAccountJoinDao _projectAccountJoinDao;
@Inject
private HostJoinDao hostJoinDao;
HostJoinDao hostJoinDao;
@Inject
private VolumeJoinDao _volumeJoinDao;
VolumeJoinDao _volumeJoinDao;
@Inject
private AccountDao _accountDao;
AccountDao _accountDao;
@Inject
private AccountJoinDao _accountJoinDao;
AccountJoinDao _accountJoinDao;
@Inject
private AsyncJobJoinDao _jobJoinDao;
AsyncJobJoinDao _jobJoinDao;
@Inject
private StoragePoolJoinDao _poolJoinDao;
StoragePoolJoinDao _poolJoinDao;
@Inject
private StoragePoolTagsDao _storageTagDao;
StoragePoolTagsDao _storageTagDao;
@Inject
private HostTagsDao _hostTagDao;
HostTagsDao _hostTagDao;
@Inject
private ImageStoreJoinDao _imageStoreJoinDao;
ImageStoreJoinDao _imageStoreJoinDao;
@Inject
private DiskOfferingJoinDao _diskOfferingJoinDao;
DiskOfferingJoinDao _diskOfferingJoinDao;
@Inject
private DiskOfferingDetailsDao _diskOfferingDetailsDao;
DiskOfferingDetailsDao _diskOfferingDetailsDao;
@Inject
private ServiceOfferingJoinDao _srvOfferingJoinDao;
ServiceOfferingJoinDao _srvOfferingJoinDao;
@Inject
private ServiceOfferingDao _srvOfferingDao;
ServiceOfferingDao _srvOfferingDao;
@Inject
private ServiceOfferingDetailsDao _srvOfferingDetailsDao;
ServiceOfferingDetailsDao _srvOfferingDetailsDao;
@Inject
private DiskOfferingDao _diskOfferingDao;
DiskOfferingDao _diskOfferingDao;
@Inject
private DataCenterJoinDao _dcJoinDao;
DataCenterJoinDao _dcJoinDao;
@Inject
private DomainRouterDao _routerDao;
DomainRouterDao _routerDao;
@Inject
private HighAvailabilityManager _haMgr;
HighAvailabilityManager _haMgr;
@Inject
private VMTemplateDao _templateDao;
VMTemplateDao _templateDao;
@Inject
private TemplateJoinDao _templateJoinDao;
TemplateJoinDao _templateJoinDao;
@Inject
private ResourceManager _resourceMgr;
ResourceManager _resourceMgr;
@Inject
private ResourceMetaDataService _resourceMetaDataMgr;
ResourceMetaDataService _resourceMetaDataMgr;
@Inject
private ResourceManagerUtil resourceManagerUtil;
ResourceManagerUtil resourceManagerUtil;
@Inject
private AffinityGroupVMMapDao _affinityGroupVMMapDao;
AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Inject
private AffinityGroupJoinDao _affinityGroupJoinDao;
AffinityGroupJoinDao _affinityGroupJoinDao;
@Inject
private DedicatedResourceDao _dedicatedDao;
DedicatedResourceDao _dedicatedDao;
@Inject
private DomainManager _domainMgr;
DomainManager _domainMgr;
@Inject
private AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
@Inject
private ResourceTagDao resourceTagDao;
ResourceTagDao resourceTagDao;
@Inject
private DataStoreManager dataStoreManager;
DataStoreManager dataStoreManager;
@Inject
ManagementServerJoinDao managementServerJoinDao;
@Inject
public VpcVirtualNetworkApplianceService routerService;
VpcVirtualNetworkApplianceService routerService;
@Inject
private ResponseGenerator responseGenerator;
ResponseGenerator responseGenerator;
@Inject
private RouterHealthCheckResultDao routerHealthCheckResultDao;
RouterHealthCheckResultDao routerHealthCheckResultDao;
@Inject
private PrimaryDataStoreDao storagePoolDao;
PrimaryDataStoreDao storagePoolDao;
@Inject
private StoragePoolDetailsDao _storagePoolDetailsDao;
StoragePoolDetailsDao _storagePoolDetailsDao;
@Inject
private ProjectInvitationDao projectInvitationDao;
ProjectInvitationDao projectInvitationDao;
@Inject
private TemplateDataStoreDao templateDataStoreDao;
TemplateDataStoreDao templateDataStoreDao;
@Inject
private VMTemplatePoolDao templatePoolDao;
VMTemplatePoolDao templatePoolDao;
@Inject
private SnapshotDataStoreDao snapshotDataStoreDao;
SnapshotDataStoreDao snapshotDataStoreDao;
@Inject
private UserDao userDao;
UserDao userDao;
@Inject
private VirtualMachineManager virtualMachineManager;
VirtualMachineManager virtualMachineManager;
@Inject
private VolumeDao volumeDao;
VolumeDao volumeDao;
@Inject
private ResourceIconDao resourceIconDao;
ResourceIconDao resourceIconDao;
@Inject
StorageManager storageManager;
@Inject
private ManagementServerHostDao msHostDao;
ManagementServerHostDao msHostDao;
@Inject
private SecondaryStorageHeuristicDao secondaryStorageHeuristicDao;
SecondaryStorageHeuristicDao secondaryStorageHeuristicDao;
@Inject
private NetworkDao networkDao;
NetworkDao networkDao;
@Inject
private IPAddressDao ipAddressDao;
IPAddressDao ipAddressDao;
@Inject
private NicDao nicDao;
NicDao nicDao;
@Inject
private HostDao hostDao;
HostDao hostDao;
@Inject
private OutOfBandManagementDao outOfBandManagementDao;
OutOfBandManagementDao outOfBandManagementDao;
@Inject
private InstanceGroupVMMapDao instanceGroupVMMapDao;
InstanceGroupVMMapDao instanceGroupVMMapDao;
@Inject
private AffinityGroupVMMapDao affinityGroupVMMapDao;
AffinityGroupVMMapDao affinityGroupVMMapDao;
@Inject
private UserVmDetailsDao userVmDetailsDao;
UserVmDetailsDao userVmDetailsDao;
@Inject
private SSHKeyPairDao sshKeyPairDao;
SSHKeyPairDao sshKeyPairDao;
@Inject
private BackupOfferingDao backupOfferingDao;
BackupOfferingDao backupOfferingDao;
@Inject
private AutoScaleVmGroupDao autoScaleVmGroupDao;
AutoScaleVmGroupDao autoScaleVmGroupDao;
@Inject
private AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDao;
AutoScaleVmGroupVmMapDao autoScaleVmGroupVmMapDao;
@Inject
private SnapshotJoinDao snapshotJoinDao;
SnapshotJoinDao snapshotJoinDao;
@Inject
private ObjectStoreDao objectStoreDao;
ObjectStoreDao objectStoreDao;
@Inject
private BucketDao bucketDao;
BucketDao bucketDao;
@Inject
EntityManager entityManager;
@Inject
private PublicIpQuarantineDao publicIpQuarantineDao;
PublicIpQuarantineDao publicIpQuarantineDao;
@Inject
private StoragePoolHostDao storagePoolHostDao;
StoragePoolHostDao storagePoolHostDao;
@Inject
private ClusterDao clusterDao;
ClusterDao clusterDao;
@Inject
private ManagementServerHostPeerJoinDao mshostPeerJoinDao;
ManagementServerHostPeerJoinDao mshostPeerJoinDao;
@Inject
private AsyncJobManager jobManager;
@ -666,7 +666,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<UserResponse> searchForUsers(ResponseView responseView, ListUsersCmd cmd) throws PermissionDeniedException {
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) {
responseView = ResponseView.Full;
}
@ -842,7 +842,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<EventResponse> searchForEvents(ListEventsCmd 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()]));
response.setResponses(eventResponses, result.second());
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);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1005,7 +1005,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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
// searchAndCount should be good enough.
if ((entryTime != null) && (duration != null)) {
@ -1042,7 +1042,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<ResourceTagResponse> listTags(ListTagsCmd 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()]));
response.setResponses(tagResponses, tags.second());
return response;
@ -1050,7 +1050,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
private Pair<List<ResourceTagJoinVO>, Integer> listTagsInternal(ListTagsCmd cmd) {
Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>();
List<Long> permittedAccounts = new ArrayList<>();
String key = cmd.getKey();
String value = cmd.getValue();
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);
Long domainId = domainIdRecursiveListProject.first();
@ -1122,14 +1122,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.setParameters("customer", customerName);
}
Pair<List<ResourceTagJoinVO>, Integer> result = _resourceTagJoinDao.searchAndCount(sc, searchFilter);
return result;
return _resourceTagJoinDao.searchAndCount(sc, searchFilter);
}
@Override
public ListResponse<InstanceGroupResponse> searchForVmGroups(ListVMGroupsCmd 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()]));
response.setResponses(grpResponses, groups.second());
return response;
@ -1141,9 +1140,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
String keyword = cmd.getKeyword();
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);
Long domainId = domainIdRecursiveListProject.first();
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());
List<Long> ids = null;
List<Long> ids;
if (cmd.getId() != null) {
if (cmd.getIds() != null && !cmd.getIds().isEmpty()) {
throw new InvalidParameterValueException("Specify either id or ids but not both parameters");
@ -1703,7 +1702,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<SecurityGroupResponse> searchForSecurityGroups(ListSecurityGroupsCmd 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());
response.setResponses(routerResponses, result.second());
return response;
@ -1715,7 +1714,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
String securityGroup = cmd.getSecurityGroupName();
Long id = cmd.getId();
Object keyword = cmd.getKeyword();
List<Long> permittedAccounts = new ArrayList<Long>();
List<Long> permittedAccounts = new ArrayList<>();
Map<String, String> tags = cmd.getTags();
if (instanceId != null) {
@ -1727,7 +1726,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1786,7 +1785,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sgIds[i++] = v.getId();
}
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) {
@ -1795,7 +1794,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = sgVmMappingPair.second();
if (count.intValue() == 0) {
// 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();
Long[] sgIds = new Long[sgVmMappings.size()];
@ -1804,14 +1803,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sgIds[i++] = sgVm.getSecurityGroupId();
}
List<SecurityGroupJoinVO> sgs = _securityGroupJoinDao.searchByIds(sgIds);
return new Pair<List<SecurityGroupJoinVO>, Integer>(sgs, count);
return new Pair<>(sgs, count);
}
@Override
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(),
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()]));
if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) {
for (DomainRouterResponse res : routerResponses) {
@ -1831,7 +1830,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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(),
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()]));
if (VirtualNetworkApplianceManager.RouterHealthChecksEnabled.value()) {
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) {
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);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
@ -1910,7 +1909,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sb.and("routerId", sb.entity().getId(), SearchCriteria.Op.NIN);
}
} 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();
}
List<DomainRouterJoinVO> vrs = _routerJoinDao.searchByIds(vrIds);
return new Pair<List<DomainRouterJoinVO>, Integer>(vrs, count);
return new Pair<>(vrs, count);
}
@Override
public ListResponse<ProjectResponse> listProjects(ListProjectsCmd 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()]));
response.setResponses(projectResponses, projects.second());
return response;
@ -2164,13 +2163,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
prjIds[i++] = v.getId();
}
List<ProjectJoinVO> prjs = _projectJoinDao.searchByIds(prjIds);
return new Pair<List<ProjectJoinVO>, Integer>(prjs, count);
return new Pair<>(prjs, count);
}
@Override
public ListResponse<ProjectInvitationResponse> listProjectInvitations(ListProjectInvitationsCmd 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()]));
response.setResponses(projectInvitationResponses, invites.second());
@ -2192,9 +2191,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Account caller = CallContext.current().getCallingAccount();
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);
domainId = domainIdRecursiveListProject.first();
isRecursive = domainIdRecursiveListProject.second();
@ -2246,7 +2245,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<ProjectAccountResponse> listProjectAccounts(ListProjectAccountsCmd 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()]));
response.setResponses(projectResponses, projectAccounts.second());
return response;
@ -2320,7 +2319,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// Right now it is handled separately outside this QueryService
logger.debug(">>>Searching for hosts>>>");
Pair<List<HostJoinVO>, Integer> hosts = searchForServersInternal(cmd);
ListResponse<HostResponse> response = new ListResponse<HostResponse>();
ListResponse<HostResponse> response = new ListResponse<>();
logger.debug(">>>Generating Response>>>");
List<HostResponse> hostResponses = ViewResponseHelper.createHostResponse(cmd.getDetails(), hosts.first().toArray(new HostJoinVO[hosts.first().size()]));
response.setResponses(hostResponses, hosts.second());
@ -2741,7 +2740,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<DomainResponse> searchForDomains(ListDomainsCmd cmd) {
Pair<List<DomainJoinVO>, Integer> result = searchForDomainsInternal(cmd);
ListResponse<DomainResponse> response = new ListResponse<DomainResponse>();
ListResponse<DomainResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListDomainsCmdByAdmin) {
@ -2843,7 +2842,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<AccountResponse> searchForAccounts(ListAccountsCmd cmd) {
Pair<List<AccountJoinVO>, Integer> result = searchForAccountsInternal(cmd);
ListResponse<AccountResponse> response = new ListResponse<AccountResponse>();
ListResponse<AccountResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListAccountsCmdByAdmin) {
@ -3029,7 +3028,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<AsyncJobResponse> searchForAsyncJobs(ListAsyncJobsCmd 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()]));
response.setResponses(jobResponses, result.second());
return response;
@ -3039,9 +3038,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
@ -3201,7 +3200,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<StorageTagResponse> searchForStorageTags(ListStorageTagsCmd 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()]));
response.setResponses(tagResponses, result.second());
@ -3236,13 +3235,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<StoragePoolTagVO> vrs = _storageTagDao.searchByIds(vrIds);
return new Pair<List<StoragePoolTagVO>, Integer>(vrs, count);
return new Pair<>(vrs, count);
}
@Override
public ListResponse<HostTagResponse> searchForHostTags(ListHostTagsCmd 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()]));
response.setResponses(tagResponses, result.second());
@ -3277,7 +3276,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<HostTagVO> vrs = _hostTagDao.searchByIds(vrIds);
return new Pair<List<HostTagVO>, Integer>(vrs, count);
return new Pair<>(vrs, count);
}
@Override
@ -3360,14 +3359,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
vrIds[i++] = v.getId();
}
List<ImageStoreJoinVO> vrs = _imageStoreJoinDao.searchByIds(vrIds);
return new Pair<List<ImageStoreJoinVO>, Integer>(vrs, count);
return new Pair<>(vrs, count);
}
@Override
public ListResponse<ImageStoreResponse> searchForSecondaryStagingStores(ListSecondaryStagingStoresCmd 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()]));
response.setResponses(poolResponses, result.second());
@ -3439,7 +3438,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
vrIds[i++] = v.getId();
}
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
public ListResponse<ZoneResponse> listDataCenters(ListZonesCmd cmd) {
Pair<List<DataCenterJoinVO>, Integer> result = listDataCentersInternal(cmd);
ListResponse<ZoneResponse> response = new ListResponse<ZoneResponse>();
ListResponse<ZoneResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListZonesCmdByAdmin || CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN) {
@ -4350,7 +4349,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// list
// 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());
if (domainRecord == null) {
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
// everything above till root, as well as zones till the domain
// leaf
List<Long> domainIds = new ArrayList<Long>();
List<Long> domainIds = new ArrayList<>();
DomainVO domainRecord = _domainDao.findById(account.getDomainId());
if (domainRecord == null) {
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
Boolean available = cmd.isAvailable();
if (account != null) {
if ((available != null) && Boolean.FALSE.equals(available)) {
Set<Long> dcIds = new HashSet<Long>(); // data centers with
if (Boolean.FALSE.equals(available)) {
Set<Long> dcIds = new HashSet<>(); // data centers with
// at least one VM
// running
List<DomainRouterVO> routers = _routerDao.listBy(account.getId());
@ -4439,7 +4438,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
dcIds.add(router.getDataCenterId());
}
if (dcIds.size() == 0) {
return new Pair<List<DataCenterJoinVO>, Integer>(new ArrayList<DataCenterJoinVO>(), 0);
return new Pair<>(new ArrayList<>(), 0);
} else {
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) {
// remove dedicated zone of other domain
List<Long> dedicatedZoneIds = new ArrayList<Long>();
List<Long> dedicatedZoneIds = new ArrayList<>();
List<DedicatedResourceVO> dedicatedResources = _dedicatedDao.listZonesNotInDomainIds(domainIds);
for (DedicatedResourceVO dr : dedicatedResources) {
if (dr != null) {
@ -4504,7 +4503,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Override
public ListResponse<TemplateResponse> listTemplates(ListTemplatesCmd cmd) {
Pair<List<TemplateJoinVO>, Integer> result = searchForTemplatesInternal(cmd);
ListResponse<TemplateResponse> response = new ListResponse<TemplateResponse>();
ListResponse<TemplateResponse> response = new ListResponse<>();
ResponseView respView = ResponseView.Restricted;
if (cmd instanceof ListTemplatesCmdByAdmin) {
@ -4532,14 +4531,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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);
accountMgr.buildACLSearchParameters(
caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccountIds,
domainIdRecursiveListProject, listAll, false
);
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
List<Account> permittedAccounts = new ArrayList<Account>();
List<Account> permittedAccounts = new ArrayList<>();
for (Long accountId : permittedAccountIds) {
permittedAccounts.add(accountMgr.getAccount(accountId));
}
@ -4577,11 +4576,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (!isIso) {
hypers = _resourceMgr.listAvailHypervisorInZone(null);
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);
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);
} else {
DomainVO domain = null;
DomainVO domain;
if (!permittedAccounts.isEmpty()) {
domain = _domainDao.findById(permittedAccounts.get(0).getDomainId());
} else {
@ -4674,15 +4673,15 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domain.getPath() + "%");
}
List<Long> relatedDomainIds = new ArrayList<Long>();
List<Long> permittedAccountIds = new ArrayList<Long>();
List<Long> relatedDomainIds = new ArrayList<>();
List<Long> permittedAccountIds = new ArrayList<>();
if (!permittedAccounts.isEmpty()) {
for (Account account : permittedAccounts) {
permittedAccountIds.add(account.getId());
boolean publicTemplates = (templateFilter == TemplateFilter.featured || templateFilter == TemplateFilter.community);
// 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 (publicTemplates) {
domainTreeNode = _domainDao.findById(Domain.ROOT_DOMAIN);
@ -4913,7 +4912,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
// sc.addAnd("removed", SearchCriteria.Op.NULL);
// search unique templates and find details by Ids
Pair<List<TemplateJoinVO>, Integer> uniqueTmplPair = null;
Pair<List<TemplateJoinVO>, Integer> uniqueTmplPair;
if (showRemovedTmpl) {
uniqueTmplPair = _templateJoinDao.searchIncludingRemovedAndCount(sc, searchFilter);
} else {
@ -4944,7 +4943,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
return templateDataPair;
}
List<TemplateJoinVO> templateData = templateDataPair.first();
List<TemplateJoinVO> templates = null;
List<TemplateJoinVO> templates;
if (showUnique) {
Long[] templateIds = templateData.stream().map(template -> template.getId()).toArray(Long[]::new);
templates = _templateJoinDao.findByDistinctIds(templateIds);
@ -4953,7 +4952,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
templates = _templateJoinDao.searchByTemplateZonePair(showRemoved, templateZonePairs);
}
return new Pair<List<TemplateJoinVO>, Integer>(templates, count);
return new Pair<>(templates, count);
}
@Override
@ -5074,7 +5073,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (HypervisorType.KVM.equals(hypervisorType)) {
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.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_RAM, Collections.emptyList());
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);
}
List<Long> permittedAccounts = new ArrayList<Long>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> ternary = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive, null);
List<Long> permittedAccounts = new ArrayList<>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> ternary = new Ternary<>(domainId, isRecursive, null);
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);
// search group details by ids
List<AffinityGroupJoinVO> affinityGroups = new ArrayList<AffinityGroupJoinVO>();
List<AffinityGroupJoinVO> affinityGroups = new ArrayList<>();
Integer count = uniqueGroupsPair.second();
if (count.intValue() != 0) {
@ -5161,7 +5160,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
if (!permittedAccounts.isEmpty()) {
// add domain level affinity groups
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);
Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, domainId);
affinityGroups.addAll(groupsPair.first());
@ -5170,7 +5169,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
for (Long permAcctId : permittedAccounts) {
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);
Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, permittedAcct.getDomainId());
affinityGroups.addAll(groupsPair.first());
@ -5179,14 +5178,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
}
} else if (((permittedAccounts.isEmpty()) && (domainId != null) && isRecursive)) {
// 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);
Pair<List<AffinityGroupJoinVO>, Integer> groupsPair = listDomainLevelAffinityGroups(scDomain, searchFilter, domainId);
affinityGroups.addAll(groupsPair.first());
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();
if (count.intValue() == 0) {
// 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();
Long[] agIds = new Long[agVmMappings.size()];
@ -5281,11 +5280,11 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
agIds[i++] = agVm.getAffinityGroupId();
}
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) {
List<Long> affinityGroupIds = new ArrayList<Long>();
List<Long> affinityGroupIds = new ArrayList<>();
Set<Long> allowedDomains = _domainMgr.getDomainParentIds(domainId);
List<AffinityGroupDomainMapVO> maps = _affinityGroupDomainMapDao.listByDomain(allowedDomains.toArray());
@ -5308,7 +5307,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = uniqueGroupsPair.second();
if (count.intValue() == 0) {
// empty result
return new Pair<>(new ArrayList<AffinityGroupJoinVO>(), 0);
return new Pair<>(new ArrayList<>(), 0);
}
List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
Long[] vrIds = new Long[uniqueGroups.size()];
@ -5319,7 +5318,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
List<AffinityGroupJoinVO> vrs = _affinityGroupJoinDao.searchByIds(vrIds);
return new Pair<>(vrs, count);
} 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;
if (key == null) {
@ -5364,7 +5363,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
detailList = _resourceMetaDataMgr.getDetails(resourceType, key, value, forDisplay);
}
List<ResourceDetailResponse> responseList = new ArrayList<ResourceDetailResponse>();
List<ResourceDetailResponse> responseList = new ArrayList<>();
if (requestedDetail != null) {
ResourceDetailResponse detailResponse = createResourceDetailsResponse(requestedDetail, resourceType);
responseList.add(detailResponse);
@ -5431,7 +5430,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
mgmtResponse.setLastServerStart(mgmt.getLastJvmStart());
mgmtResponse.setLastServerStop(mgmt.getLastJvmStop());
mgmtResponse.setLastBoot(mgmt.getLastSystemBoot());
mgmtResponse.setServiceIp(mgmt.getServiceIP());
if (listPeers) {
List<ManagementServerHostPeerJoinVO> peers = mshostPeerJoinDao.listByOwnerMshostId(mgmt.getId());
for (ManagementServerHostPeerJoinVO peer: peers) {
@ -5440,6 +5438,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
}
mgmtResponse.setAgentsCount((long) hostDao.countByMs(mgmt.getMsid()));
mgmtResponse.setPendingJobsCount(jobManager.countPendingNonPseudoJobs(mgmt.getMsid()));
mgmtResponse.setIpAddress(mgmt.getServiceIP());
mgmtResponse.setObjectName("managementserver");
return mgmtResponse;
}
@ -5616,7 +5615,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Filter searchFilter = new Filter(SnapshotJoinVO.class, "snapshotStorePair", SortKeyAscending.value(), startIndex, pageSize);
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);
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
domainId = domainIdRecursiveListProject.first();
@ -5749,7 +5748,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Integer count = snapshotDataPair.second();
if (count == 0) {
// empty result
return snapshotDataPair;
}
List<SnapshotJoinVO> snapshotData = snapshotDataPair.first();
@ -5759,13 +5757,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
} else {
snapshots = snapshotJoinDao.searchBySnapshotStorePair(snapshotData.stream().map(SnapshotJoinVO::getSnapshotStorePair).toArray(String[]::new));
}
return new Pair<>(snapshots, count);
}
public ListResponse<ObjectStoreResponse> searchForObjectStores(ListObjectStoragePoolsCmd 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()]));
response.setResponses(poolResponses, result.second());
@ -5850,7 +5847,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
Long startIndex = cmd.getStartIndex();
Long pageSize = cmd.getPageSizeVal();
Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>();
List<Long> permittedAccounts = new ArrayList<>();
// Verify parameters
if (id != null) {
@ -5862,7 +5859,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();

View File

@ -23,10 +23,7 @@ import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.response.SnapshotResponse;
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.SearchCriteria;
public interface SnapshotJoinDao extends GenericDao<SnapshotJoinVO, Long> {
@ -34,8 +31,7 @@ public interface SnapshotJoinDao extends GenericDao<SnapshotJoinVO, Long> {
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> findByDistinctIds(Long zoneId, Long... ids);
}

View File

@ -18,6 +18,8 @@
package com.cloud.api.query.dao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
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.query.QueryService;
import org.apache.commons.collections.CollectionUtils;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.ApiResponseHelper;
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.user.Account;
import com.cloud.user.AccountService;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@ -53,11 +56,11 @@ import com.cloud.vm.VMInstanceVO;
public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<SnapshotJoinVO, SnapshotResponse> implements SnapshotJoinDao {
@Inject
private AccountService accountService;
AccountService accountService;
@Inject
private AnnotationDao annotationDao;
AnnotationDao annotationDao;
@Inject
private ConfigurationDao configDao;
ConfigurationDao configDao;
@Inject
SnapshotDataFactory snapshotDataFactory;
@ -85,7 +88,7 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
if (snapshot.getDataCenterId() == null) {
return;
}
SnapshotInfo snapshotInfo = null;
SnapshotInfo snapshotInfo;
snapshotInfo = snapshotDataFactory.getSnapshotWithRoleAndZone(snapshot.getId(), snapshot.getStoreRole(), snapshot.getDataCenterId());
if (snapshotInfo == null) {
logger.debug("Unable to find info for image store snapshot {}", snapshot);
@ -192,13 +195,6 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
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
public List<SnapshotJoinVO> searchBySnapshotStorePair(String... pairs) {
// set detail batch query size
@ -243,14 +239,33 @@ public class SnapshotJoinDaoImpl extends GenericDaoBaseWithTagInformation<Snapsh
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
public List<SnapshotJoinVO> findByDistinctIds(Long zoneId, Long... ids) {
if (ids == null || ids.length == 0) {
return new ArrayList<>();
}
if (ids.length == 1) {
return findById(zoneId, ids[0]);
}
Filter searchFilter = new Filter(SnapshotJoinVO.class, "snapshotStorePair", QueryService.SortKeyAscending.value(), null, null);
SearchCriteria<SnapshotJoinVO> sc = snapshotIdsSearch.create();
if (zoneId != null) {
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.",
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
EventPurgeInterval(
@ -665,8 +665,8 @@ public enum Config {
ManagementServer.class,
String.class,
"hypervisor.list",
HypervisorType.Hyperv + "," + HypervisorType.KVM + "," + HypervisorType.XenServer + "," + HypervisorType.VMware + "," + HypervisorType.BareMetal + "," +
HypervisorType.Ovm + "," + HypervisorType.LXC + "," + HypervisorType.Ovm3,
HypervisorType.KVM + "," + HypervisorType.VMware + "," + HypervisorType.XenServer + "," + HypervisorType.Hyperv + "," +
HypervisorType.BareMetal + "," + HypervisorType.Ovm + "," + HypervisorType.LXC + "," + HypervisorType.Ovm3,
"The list of hypervisors that this deployment will use.",
"hypervisorList",
ConfigKey.Kind.CSV,

View File

@ -7225,10 +7225,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
sc.addAnd("id", SearchCriteria.Op.EQ, id);
}
if (tags != null) {
sc.addAnd("tags", SearchCriteria.Op.EQ, tags);
}
if (isTagged != null) {
if (isTagged) {
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) {
SearchBuilder<NetworkOfferingJoinVO> sb = networkOfferingJoinDao.createSearchBuilder();
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.FIND_IN_SET);
@ -7297,7 +7304,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
boolean addOffering = true;
List<Service> checkForProviders = new ArrayList<Service>();
if (checkForTags && ! checkNetworkOfferingTags(pNtwkTags, allowNullTag, offering.getTags())) {
if (checkForTags && !checkNetworkOfferingTags(pNtwkTags, allowNullTag, offering.getTags())) {
continue;
}

View File

@ -934,8 +934,12 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
@Override
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) {
logger.debug("Network " + network + " doesn't support service " + Service.UserData.getName());
return null;

View File

@ -325,8 +325,12 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
try {
final Network network = _networkMgr.getNetwork(nic.getNetworkId());
final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
if (userDataUpdateProvider == null) {
logger.warn("Failed to get user data provider");
return false;
}
final Provider provider = userDataUpdateProvider.getProvider();
if (provider.equals(Provider.ConfigDrive)) {
if (Provider.ConfigDrive.equals(provider)) {
try {
return deleteConfigDriveIso(vm);
} catch (ResourceUnavailableException e) {
@ -341,8 +345,13 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
@Override
public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) {
if (_networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.ConfigDrive)) {
logger.trace(String.format("[prepareMigration] for vm: %s", vm));
final UserDataServiceProvider userDataUpdateProvider = _networkModel.getUserDataUpdateProvider(network);
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 {
if (isConfigDriveIsoOnHostCache(vm.getId())) {
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 {
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;
for (DiskTO disk : vm.getDisks()) {
if (disk.getType() == Volume.Type.ISO && disk.getPath() != null && disk.getPath().contains("configdrive")) {

View File

@ -769,7 +769,12 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
@Override
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();
UserVmVO destVm = _userVmDao.findById(uvm.getId());
VirtualMachineProfile profile = null;

View File

@ -343,7 +343,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
private void validatePrerequisiteVpnGateway(Site2SiteVpnGateway vpnGateway) {
// check if gateway has been defined on the VPC
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 {
Site2SiteVpnConnectionVO conn = _vpnConnectionDao.acquireInLockTable(id);
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 {
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);
if (templateVO != null) {
try {
if (SystemVmTemplateRegistration.validateIfSeeded(
url, templateVO.getInstallPath(), nfsVersion)) {
if (systemVmTemplateRegistration.validateIfSeeded(
templateVO, url, templateVO.getInstallPath(), nfsVersion)) {
continue;
}
} catch (Exception e) {

View File

@ -2484,10 +2484,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
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());
Pair<Long, Long> clusterHostId = virtualMachineManager.findClusterAndHostIdForVm(vm, false);
long podId = vm.getPodIdToDeployIn();
Long podId = vm.getPodIdToDeployIn();
if (clusterHostId.first() != null) {
Cluster cluster = clusterDao.findById(clusterHostId.first());
podId = cluster.getPodId();
@ -2499,12 +2499,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
offering.isUseLocalStorage(), offering.isRecreatable(),
volumeToAttach.getTemplateId());
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());
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) {
@ -2522,7 +2518,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
}
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 {
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) {
long startTime = System.nanoTime();
apiNameList = new ArrayList<String>();
Set<Class<?>> cmdClasses = new LinkedHashSet<Class<?>>();
apiNameList = new ArrayList<>();
Set<Class<?>> cmdClasses = new LinkedHashSet<>();
for (PluggableService service : services) {
logger.debug(String.format("getting api commands of service: %s", service.getClass().getName()));
cmdClasses.addAll(service.getCommands());
@ -513,7 +513,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
}
protected List<String> createApiNameList(Set<Class<?>> cmdClasses) {
List<String> apiNameList = new ArrayList<String>();
List<String> apiNameList = new ArrayList<>();
for (Class<?> cmdClass : cmdClasses) {
APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class);
@ -698,7 +698,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return;
}
HashMap<Long, List<ControlledEntity>> domains = new HashMap<Long, List<ControlledEntity>>();
HashMap<Long, List<ControlledEntity>> domains = new HashMap<>();
for (ControlledEntity entity : entities) {
long domainId = entity.getDomainId();
@ -713,7 +713,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId());
// for templates, we don't have to do cross domains check
if (toBeChecked == null) {
toBeChecked = new ArrayList<ControlledEntity>();
toBeChecked = new ArrayList<>();
domains.put(domainId, toBeChecked);
}
toBeChecked.add(entity);
@ -722,7 +722,11 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(caller, entity, accessType, apiName)) {
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;
break;
@ -1023,12 +1027,12 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
logger.debug("Deleting networks for account {}", account);
List<NetworkVO> networks = _networkDao.listByOwner(accountId);
if (networks != null) {
Collections.sort(networks, new Comparator<NetworkVO>() {
Collections.sort(networks, new Comparator<>() {
@Override
public int compare(NetworkVO network1, NetworkVO network2) {
if (network1.getGuestType() != network2.getGuestType() && Network.GuestType.Isolated.equals(network2.getGuestType())) {
return -1;
};
}
return 1;
}
});
@ -1300,7 +1304,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
final String accountNameFinal = accountName;
final Long domainIdFinal = domainId;
final String accountUUIDFinal = accountUUID;
Pair<Long, Account> pair = Transaction.execute(new TransactionCallback<Pair<Long, Account>>() {
Pair<Long, Account> pair = Transaction.execute(new TransactionCallback<>() {
@Override
public Pair<Long, Account> doInTransaction(TransactionStatus status) {
// create account
@ -1323,7 +1327,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
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
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));
_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)) {
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);
return user;
}
@ -1731,7 +1735,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
Long callingUserId = CallContext.current().getCallingUserId();
Account callingAccount = CallContext.current().getCallingAccount();
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());
} catch (IllegalArgumentException ex) {
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();
Account callingAccount = CallContext.current().getCallingAccount();
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());
} catch (IllegalArgumentException ex) {
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);
boolean success = Transaction.execute(new TransactionCallback<Boolean>() {
boolean success = Transaction.execute(new TransactionCallback<>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
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
// if the user is either locked already or disabled already, don't change state...only lock currently enabled
// users
boolean success = true;
boolean success;
if (user.getState().equals(State.LOCKED)) {
// already locked...no-op
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) {
// Check if account exists
Account account = null;
Account account;
if (accountId != null) {
account = _accountDao.findById(accountId);
} else {
@ -2021,7 +2025,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return _accountDao.findById(account.getId());
} 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) {
Account caller = getCurrentCallingAccount();
Account account = null;
Account account;
if (accountId != null) {
account = _accountDao.findById(accountId);
} else {
@ -2051,7 +2055,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
CallContext.current().putContextParameter(Account.class, account.getUuid());
return _accountDao.findById(account.getId());
} 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 {
Account caller = getCurrentCallingAccount();
Account account = null;
Account account;
if (accountId != null) {
account = _accountDao.findById(accountId);
} else {
@ -2097,8 +2101,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
String networkDomain = cmd.getNetworkDomain();
final Map<String, String> details = cmd.getDetails();
boolean success = false;
Account account = null;
boolean success;
Account account;
if (accountId != null) {
account = _accountDao.findById(accountId);
} else {
@ -2159,7 +2163,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (roleNotFound) {
throw new InvalidParameterValueException(String.format("Role with ID '%s' is not " +
"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);
@ -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 Transaction.execute(new TransactionCallback<Boolean>() {
return Transaction.execute(new TransactionCallback<>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
UserVO newUser = new UserVO(user);
@ -2560,7 +2564,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
}
// Create the account
return Transaction.execute(new TransactionCallback<AccountVO>() {
return Transaction.execute(new TransactionCallback<>() {
@Override
public AccountVO doInTransaction(TransactionStatus status) {
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);
String signature = null;
long timestamp = 0L;
String unsignedRequest = null;
String unsignedRequest;
StringBuffer unsignedRequestBuffer = new StringBuffer();
// - build a request string with sorted params, make sure it's all lowercase
// - 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()) {
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);
boolean authenticated = false;
HashSet<ActionOnFailedAuthentication> actionsOnFailedAuthenticaion = new HashSet<ActionOnFailedAuthentication>();
HashSet<ActionOnFailedAuthentication> actionsOnFailedAuthenticaion = new HashSet<>();
User.Source userSource = userAccount != null ? userAccount.getSource() : User.Source.UNKNOWN;
for (UserAuthenticator authenticator : _userAuthenticators) {
final String[] secretCodeArray = (String[])requestParameters.get(ApiConstants.SECRET_CODE);
@ -2886,7 +2890,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
preventRootDomainAdminAccessToRootAdminKeys(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("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) {
@ -2999,8 +3003,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
try {
UserVO updatedUser = _userDao.createForUpdate();
String encodedKey = null;
Pair<User, Account> userAcct = null;
String encodedKey;
Pair<User, Account> userAcct;
int retryLimit = 10;
do {
// 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) {
try {
UserVO updatedUser = _userDao.createForUpdate();
String encodedKey = null;
String encodedKey;
int retryLimit = 10;
UserVO userBySecretKey = null;
UserVO userBySecretKey;
do {
KeyGenerator generator = KeyGenerator.getInstance("HmacSHA1");
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");
}
Account userAccount = null;
Domain domain = null;
Account userAccount;
Domain domain;
if (domainId != null) {
userAccount = _accountDao.findActiveAccount(accountName, domainId);
domain = _domainDao.findById(domainId);
@ -3262,7 +3266,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override
public List<String> listAclGroupsByAccount(Long accountId) {
if (_querySelectors == null || _querySelectors.size() == 0) {
return new ArrayList<String>();
return new ArrayList<>();
}
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) {
UserVO userVO = null;
UserVO userVO;
if (userId != null) {
userVO = validateUser(userId);
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.utils.bytescale.ByteScaleUtils;
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.UnmanagedVMsManager;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
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");
}
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");
}
@ -4526,7 +4526,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
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);
return rootDiskSize;
} else {

View File

@ -27,6 +27,7 @@ import java.util.Map;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.storage.snapshot.SnapshotManager;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
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
//Other Storage volume plugins could integrate this with their own functionality for group snapshots
VMSnapshotStrategy snapshotStrategy = storageStrategyFactory.getVmSnapshotStrategy(userVmVo.getId(), rootVolumePool.getId(), snapshotMemory);
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);
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(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet())))
.thenReturn(pool);
StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
StoragePool result = volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
Assert.assertNotNull(result);
Assert.assertEquals(pool, result);
}
@Test(expected = CloudRuntimeException.class)
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoPoolFound_ThrowsException() {
@Test
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoSuitablePoolFound_ReturnsNull() {
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
UserVmVO vm = Mockito.mock(UserVmVO.class);
DataCenterVO zone = mockZone();
@ -2059,11 +2059,11 @@ public class VolumeApiServiceImplTest {
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet())))
.thenReturn(null);
volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
Assert.assertNull(volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm));
}
@Test
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoCluster() {
public void testGetSuitablePoolForAllocatedOrUploadedVolumeForAttach_NoCluster() {
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
UserVmVO vm = Mockito.mock(UserVmVO.class);
DataCenterVO zone = mockZone();
@ -2077,7 +2077,7 @@ public class VolumeApiServiceImplTest {
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(null), eq(2L), eq(vm), eq(Collections.emptySet())))
.thenReturn(pool);
StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
StoragePool result = volumeApiServiceImpl.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
Assert.assertNotNull(result);
Assert.assertEquals(pool, result);
}
@ -2123,7 +2123,7 @@ public class VolumeApiServiceImplTest {
UserVmVO vm = Mockito.mock(UserVmVO.class);
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class);
try {
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(
@ -2134,7 +2134,7 @@ public class VolumeApiServiceImplTest {
}
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
Assert.assertSame(newVolumeOnPrimaryStorage, result);
verify(volumeApiServiceImpl).getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
verify(volumeApiServiceImpl).getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
}
@Test(expected = InvalidParameterValueException.class)
@ -2145,7 +2145,7 @@ public class VolumeApiServiceImplTest {
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
}
@ -2157,7 +2157,7 @@ public class VolumeApiServiceImplTest {
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
.getSuitablePoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
try {
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage))
.thenThrow(new NoTransitionException("Mocked exception"));
@ -2169,4 +2169,35 @@ public class VolumeApiServiceImplTest {
);
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;
}
@Override
public void setParentPath(String path) {
this._parent = path;
}
@Override
public Answer executeRequest(Command cmd) {
return super.executeRequest(cmd);
@ -57,7 +52,7 @@ public class LocalNfsSecondaryStorageResource extends NfsSecondaryStorageResourc
String dir = mountUri(uri, nfsVersion);
return _parent + "/" + dir;
} 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);
throw new CloudRuntimeException(msg);
}
@ -75,14 +70,14 @@ public class LocalNfsSecondaryStorageResource extends NfsSecondaryStorageResourc
// Change permissions for the mountpoint - seems to bypass authentication
Script script = new Script(true, "chmod", _timeout, logger);
script.add("777", localRootPath);
script.add("1777", localRootPath);
String result = script.execute();
if (result != null) {
String errMsg = "Unable to set permissions for " + localRootPath + " due to " + result;
logger.error(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
// to move it somewhere more logical later.

View File

@ -19,15 +19,16 @@ import logging
from netaddr import IPAddress, IPNetwork
import subprocess
import time
from . import CsHelper
from .CsDatabag import CsDataBag
from .CsApp import CsApache, CsDnsmasq, CsPasswdSvc
from .CsRoute import CsRoute
from .CsRule import CsRule
from .CsStaticRoutes import CsStaticRoutes
VRRP_TYPES = ['guest']
class CsAddress(CsDataBag):
def compare(self):
@ -556,8 +557,10 @@ class CsIP:
(self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
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.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(["mangle", "",
"-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",
"-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:])))])
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"]:
self.fw.append(["nat", "front",
"-A POSTROUTING -o %s -j SNAT --to-source %s" %

View File

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

View File

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

View File

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

View File

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

View File

@ -54,6 +54,7 @@
"label.action": "Action",
"label.action.attach.disk": "Attach disk",
"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.firewall.rules": "Bulk delete 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.associatednetworkname": "Network name",
"label.asyncbackup": "Async backup",
"label.attach.vol.to.instance": "Attach the created Volume to an existing Instance",
"label.attaching": "Attaching",
"label.authentication.method": "Authentication Method",
"label.authentication.sshkey": "System SSH Key",
"label.use.existing.vcenter.credentials.from.zone": "Use existing vCenter credentials from the Zone",
"label.autoscale": "AutoScale",
"label.autoscalevmgroupname": "AutoScaling Group",
"label.author.email": "Author e-mail",
@ -1079,7 +1082,7 @@
"label.hastate": "HA state",
"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.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.health.check": "Health check",
"label.heapmemoryused": "Heap-memory used",
@ -2019,7 +2022,6 @@
"label.schedule": "Schedule",
"label.schedule.add": "Add schedule",
"label.scheduled.backups": "Scheduled backups",
"label.scheduled.snapshots": "Scheduled Snapshots",
"label.schedules": "Schedules",
"label.scope": "Scope",
"label.scope.tooltip": "Primary Storage Pool Scope",
@ -3283,6 +3285,7 @@
"message.license.agreements.not.accepted": "License agreements not accepted.",
"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.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.load.host.failed": "Failed to load hosts.",
"message.loadbalancer.stickypolicy.configuration": "Customize the load balancer stickiness policy:",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,14 +26,14 @@ export default {
permission: ['listManagementServersMetrics'],
resourceType: 'ManagementServer',
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']
if (store.getters.metrics) {
fields.push(...metricsFields)
}
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: [
{
name: 'details',

View File

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

View File

@ -142,7 +142,7 @@ export default {
permission: ['listServiceOfferings', 'listInfrastructure'],
searchFilters: ['name', 'zoneid', 'domainid', 'cpunumber', 'cpuspeed', 'memory'],
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'],
details: ['name', 'id', 'displaytext', 'systemvmtype', 'provisioningtype', 'storagetype', 'iscustomized', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'storagetags', 'hosttags', 'tags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness'],
resourceType: 'ServiceOffering',

View File

@ -17,6 +17,7 @@
import { shallowRef, defineAsyncComponent } from 'vue'
import store from '@/store'
import { isZoneCreated } from '@/utils/zone'
export default {
name: 'storage',
@ -103,6 +104,7 @@ export default {
icon: 'plus-outlined',
docHelp: 'adminguide/storage.html#creating-a-new-volume',
label: 'label.action.create.volume',
show: isZoneCreated,
listView: true,
popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/CreateVolume.vue')))
@ -112,7 +114,7 @@ export default {
icon: 'cloud-upload-outlined',
docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
label: 'label.upload.volume.from.local',
show: () => { return 'getUploadParamsForVolume' in store.getters.apis },
show: () => { return isZoneCreated() && 'getUploadParamsForVolume' in store.getters.apis },
listView: true,
popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadLocalVolume.vue')))
@ -122,6 +124,7 @@ export default {
icon: 'link-outlined',
docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
label: 'label.upload.volume.from.url',
show: isZoneCreated,
listView: true,
popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadVolume.vue')))
@ -165,9 +168,10 @@ export default {
label: 'label.action.take.snapshot',
dataView: true,
show: (record, store) => {
return record.state === 'Ready' && (record.hypervisor !== 'KVM' ||
record.hypervisor === 'KVM' && record.vmstate === 'Running' && store.features.kvmsnapshotenabled ||
record.hypervisor === 'KVM' && record.vmstate !== 'Running')
return record.state === 'Ready' &&
(record.hypervisor !== 'KVM' ||
['Stopped', 'Destroyed'].includes(record.vmstate) ||
store.features.kvmsnapshotenabled)
},
popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/storage/TakeSnapshot.vue')))
@ -179,9 +183,10 @@ export default {
label: 'label.action.recurring.snapshot',
dataView: true,
show: (record, store) => {
return record.state === 'Ready' && (record.hypervisor !== 'KVM' ||
record.hypervisor === 'KVM' && record.vmstate === 'Running' && store.features.kvmsnapshotenabled ||
record.hypervisor === 'KVM' && record.vmstate !== 'Running')
return record.state === 'Ready' &&
(record.hypervisor !== 'KVM' ||
(['Stopped', 'Destroyed'].includes(record.vmstate)) ||
(store.features.kvmsnapshotenabled))
},
popup: true,
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>
<a-select
v-model:value="hypervisor"
@change="resetAllFields"
@change="hypervisor => onChangeHypervisor(hypervisor)"
showSearch
optionFilterProp="value"
:filterOption="(input, option) => {
@ -109,19 +109,28 @@
</div>
<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>
</div>
<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>
</div>
<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">
@ -176,6 +185,7 @@ export default {
username: null,
password: null,
url: null,
useDefaultVMwareCred: true,
host: null,
dataCenter: null,
ovm3pool: null,
@ -257,6 +267,27 @@ export default {
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 () {
this.dedicatedDomainId = null
this.dedicatedAccount = null
@ -270,35 +301,24 @@ export default {
}
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') {
this.ovm3pool = 'on'
this.ovm3cluster = 'undefined'
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()
},
addCluster () {
@ -387,7 +407,7 @@ export default {
this.loading = false
})
},
resetAllFields () {
onChangeHypervisor (hypervisor) {
this.clustertype = 'CloudManaged'
this.username = null
this.password = null
@ -397,6 +417,16 @@ export default {
this.ovm3pool = null
this.ovm3cluster = 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) {
this.params.find(i => {

View File

@ -793,6 +793,10 @@ export default {
if (this.scopeType === 'domain') {
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.networkOfferings = []
api('listNetworkOfferings', params).then(json => {

View File

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

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