mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Flexible tags for hosts and storage pools (#7489)
Co-authored-by: João Jandre <joao@scclouds.com.br>
This commit is contained in:
parent
a31f211628
commit
26b01f6f3b
@ -1066,6 +1066,10 @@ public class ApiConstants {
|
|||||||
public static final String CLIENT_ID = "clientid";
|
public static final String CLIENT_ID = "clientid";
|
||||||
public static final String REDIRECT_URI = "redirecturi";
|
public static final String REDIRECT_URI = "redirecturi";
|
||||||
|
|
||||||
|
public static final String IS_TAG_A_RULE = "istagarule";
|
||||||
|
|
||||||
|
public static final String PARAMETER_DESCRIPTION_IS_TAG_A_RULE = "Whether the informed tag is a JS interpretable rule or not.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
||||||
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
||||||
|
|||||||
@ -60,6 +60,9 @@ public class UpdateHostCmd extends BaseCmd {
|
|||||||
@Parameter(name = ApiConstants.HOST_TAGS, type = CommandType.LIST, collectionType = CommandType.STRING, description = "list of tags to be added to the host")
|
@Parameter(name = ApiConstants.HOST_TAGS, type = CommandType.LIST, collectionType = CommandType.STRING, description = "list of tags to be added to the host")
|
||||||
private List<String> hostTags;
|
private List<String> hostTags;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_TAG_A_RULE, type = CommandType.BOOLEAN, description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the new uri for the secondary storage: nfs://host/path")
|
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the new uri for the secondary storage: nfs://host/path")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
@ -90,6 +93,10 @@ public class UpdateHostCmd extends BaseCmd {
|
|||||||
return hostTags;
|
return hostTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,6 +90,9 @@ public class CreateStoragePoolCmd extends BaseCmd {
|
|||||||
description = "hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.")
|
description = "hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.")
|
||||||
private String hypervisor;
|
private String hypervisor;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_TAG_A_RULE, type = CommandType.BOOLEAN, description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -146,6 +149,10 @@ public class CreateStoragePoolCmd extends BaseCmd {
|
|||||||
return hypervisor;
|
return hypervisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isTagARule() {
|
||||||
|
return this.isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getEntityOwnerId() {
|
public long getEntityOwnerId() {
|
||||||
return Account.ACCOUNT_ID_SYSTEM;
|
return Account.ACCOUNT_ID_SYSTEM;
|
||||||
|
|||||||
@ -61,6 +61,9 @@ public class UpdateStoragePoolCmd extends BaseCmd {
|
|||||||
" enable it back.")
|
" enable it back.")
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_TAG_A_RULE, type = CommandType.BOOLEAN, description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -89,6 +92,10 @@ public class UpdateStoragePoolCmd extends BaseCmd {
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -221,6 +221,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
@Param(description = "comma-separated list of tags for the host")
|
@Param(description = "comma-separated list of tags for the host")
|
||||||
private String hostTags;
|
private String hostTags;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.IS_TAG_A_RULE)
|
||||||
|
@Param(description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
@SerializedName("hasenoughcapacity")
|
@SerializedName("hasenoughcapacity")
|
||||||
@Param(description = "true if this host has enough CPU and RAM capacity to migrate a VM to it, false otherwise")
|
@Param(description = "true if this host has enough CPU and RAM capacity to migrate a VM to it, false otherwise")
|
||||||
private Boolean hasEnoughCapacity;
|
private Boolean hasEnoughCapacity;
|
||||||
@ -732,4 +736,12 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||||||
public void setEncryptionSupported(Boolean encryptionSupported) {
|
public void setEncryptionSupported(Boolean encryptionSupported) {
|
||||||
this.encryptionSupported = encryptionSupported;
|
this.encryptionSupported = encryptionSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsTagARule(Boolean tagARule) {
|
||||||
|
isTagARule = tagARule;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,6 +101,10 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
|
|||||||
@Param(description = "the tags for the storage pool")
|
@Param(description = "the tags for the storage pool")
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.IS_TAG_A_RULE)
|
||||||
|
@Param(description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.STATE)
|
@SerializedName(ApiConstants.STATE)
|
||||||
@Param(description = "the state of the storage pool")
|
@Param(description = "the state of the storage pool")
|
||||||
private StoragePoolStatus state;
|
private StoragePoolStatus state;
|
||||||
@ -304,6 +308,14 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
|
|||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsTagARule(Boolean tagARule) {
|
||||||
|
isTagARule = tagARule;
|
||||||
|
}
|
||||||
|
|
||||||
public StoragePoolStatus getState() {
|
public StoragePoolStatus getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,8 @@ public class PrimaryDataStoreParameters {
|
|||||||
private boolean managed;
|
private boolean managed;
|
||||||
private Long capacityIops;
|
private Long capacityIops;
|
||||||
|
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the userInfo
|
* @return the userInfo
|
||||||
*/
|
*/
|
||||||
@ -277,4 +279,12 @@ public class PrimaryDataStoreParameters {
|
|||||||
public void setUsedBytes(long usedBytes) {
|
public void setUsedBytes(long usedBytes) {
|
||||||
this.usedBytes = usedBytes;
|
this.usedBytes = usedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsTagARule(Boolean isTagARule) {
|
||||||
|
this.isTagARule = isTagARule;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import javax.persistence.Id;
|
|||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.InternalIdentity;
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "host_tags")
|
@Table(name = "host_tags")
|
||||||
@ -39,12 +40,22 @@ public class HostTagVO implements InternalIdentity {
|
|||||||
@Column(name = "tag")
|
@Column(name = "tag")
|
||||||
private String tag;
|
private String tag;
|
||||||
|
|
||||||
|
@Column(name = "is_tag_a_rule")
|
||||||
|
private boolean isTagARule;
|
||||||
|
|
||||||
protected HostTagVO() {
|
protected HostTagVO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public HostTagVO(long hostId, String tag) {
|
public HostTagVO(long hostId, String tag) {
|
||||||
this.hostId = hostId;
|
this.hostId = hostId;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
this.isTagARule = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostTagVO(long hostId, String tag, Boolean isTagARule) {
|
||||||
|
this.hostId = hostId;
|
||||||
|
this.tag = tag;
|
||||||
|
this.isTagARule = BooleanUtils.toBooleanDefaultIfNull(isTagARule, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getHostId() {
|
public long getHostId() {
|
||||||
@ -59,6 +70,11 @@ public class HostTagVO implements InternalIdentity {
|
|||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import javax.persistence.TemporalType;
|
|||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
import com.cloud.agent.api.VgpuTypesInfo;
|
import com.cloud.agent.api.VgpuTypesInfo;
|
||||||
|
import com.cloud.host.dao.HostTagsDao;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.offering.ServiceOffering;
|
import com.cloud.offering.ServiceOffering;
|
||||||
import com.cloud.resource.ResourceState;
|
import com.cloud.resource.ResourceState;
|
||||||
@ -46,7 +47,10 @@ import com.cloud.storage.Storage.StoragePoolType;
|
|||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
|
import org.apache.commons.lang.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -159,6 +163,14 @@ public class HostVO implements Host {
|
|||||||
@Transient
|
@Transient
|
||||||
List<String> hostTags;
|
List<String> hostTags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a delayed load value.
|
||||||
|
* If the value is null, then this field has not been loaded yet.
|
||||||
|
* Call host dao to load it.
|
||||||
|
*/
|
||||||
|
@Transient
|
||||||
|
Boolean isTagARule;
|
||||||
|
|
||||||
// This value is only for saving and current cannot be loaded.
|
// This value is only for saving and current cannot be loaded.
|
||||||
@Transient
|
@Transient
|
||||||
HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails = new HashMap<String, HashMap<String, VgpuTypesInfo>>();
|
HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails = new HashMap<String, HashMap<String, VgpuTypesInfo>>();
|
||||||
@ -322,8 +334,13 @@ public class HostVO implements Host {
|
|||||||
return hostTags;
|
return hostTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHostTags(List<String> hostTags) {
|
public void setHostTags(List<String> hostTags, Boolean isTagARule) {
|
||||||
this.hostTags = hostTags;
|
this.hostTags = hostTags;
|
||||||
|
this.isTagARule = isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGpuGroupDetails() {
|
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGpuGroupDetails() {
|
||||||
@ -748,6 +765,11 @@ public class HostVO implements Host {
|
|||||||
if (serviceOffering == null) {
|
if (serviceOffering == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BooleanUtils.isTrue(this.getIsTagARule())) {
|
||||||
|
return TagAsRuleHelper.interpretTagAsRule(this.getHostTags().get(0), serviceOffering.getHostTag(), HostTagsDao.hostTagRuleExecutionTimeout.value());
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.isEmpty(serviceOffering.getHostTag())) {
|
if (StringUtils.isEmpty(serviceOffering.getHostTag())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,6 +108,8 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
|
|||||||
|
|
||||||
List<HostVO> listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType);
|
List<HostVO> listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType);
|
||||||
|
|
||||||
|
List<HostVO> listAllHostsThatHaveNoRuleTag(Host.Type type, Long clusterId, Long podId, Long dcId);
|
||||||
|
|
||||||
List<HostVO> listAllHostsByType(Host.Type type);
|
List<HostVO> listAllHostsByType(Host.Type type);
|
||||||
|
|
||||||
HostVO findByPublicIp(String publicIp);
|
HostVO findByPublicIp(String publicIp);
|
||||||
@ -161,4 +163,8 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
|
|||||||
* @return ordered list of hypervisor versions
|
* @return ordered list of hypervisor versions
|
||||||
*/
|
*/
|
||||||
List<String> listOrderedHostsHypervisorVersionsInDatacenter(long datacenterId, HypervisorType hypervisorType);
|
List<String> listOrderedHostsHypervisorVersionsInDatacenter(long datacenterId, HypervisorType hypervisorType);
|
||||||
|
|
||||||
|
List<HostVO> findHostsWithTagRuleThatMatchComputeOferringTags(String computeOfferingTags);
|
||||||
|
|
||||||
|
List<Long> findClustersThatMatchHostTagRule(String computeOfferingTags);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,11 @@ import java.sql.SQLException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -32,6 +34,8 @@ import javax.annotation.PostConstruct;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.persistence.TableGenerator;
|
import javax.persistence.TableGenerator;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import com.cloud.agent.api.VgpuTypesInfo;
|
import com.cloud.agent.api.VgpuTypesInfo;
|
||||||
@ -80,8 +84,8 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
private static final Logger state_logger = Logger.getLogger(ResourceState.class);
|
private static final Logger state_logger = Logger.getLogger(ResourceState.class);
|
||||||
|
|
||||||
private static final String LIST_HOST_IDS_BY_COMPUTETAGS = "SELECT filtered.host_id, COUNT(filtered.tag) AS tag_count "
|
private static final String LIST_HOST_IDS_BY_COMPUTETAGS = "SELECT filtered.host_id, COUNT(filtered.tag) AS tag_count "
|
||||||
+ "FROM (SELECT host_id, tag FROM host_tags GROUP BY host_id,tag) AS filtered "
|
+ "FROM (SELECT host_id, tag, is_tag_a_rule FROM host_tags GROUP BY host_id,tag) AS filtered "
|
||||||
+ "WHERE tag IN(%s) "
|
+ "WHERE tag IN(%s) AND is_tag_a_rule = 0 "
|
||||||
+ "GROUP BY host_id "
|
+ "GROUP BY host_id "
|
||||||
+ "HAVING tag_count = %s ";
|
+ "HAVING tag_count = %s ";
|
||||||
private static final String SEPARATOR = ",";
|
private static final String SEPARATOR = ",";
|
||||||
@ -148,6 +152,10 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
protected GenericSearchBuilder<ClusterVO, Long> AllClustersSearch;
|
protected GenericSearchBuilder<ClusterVO, Long> AllClustersSearch;
|
||||||
protected SearchBuilder<HostVO> HostsInClusterSearch;
|
protected SearchBuilder<HostVO> HostsInClusterSearch;
|
||||||
|
|
||||||
|
protected SearchBuilder<HostVO> searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag;
|
||||||
|
|
||||||
|
protected SearchBuilder<HostTagVO> searchBuilderFindByRuleTag;
|
||||||
|
|
||||||
protected Attribute _statusAttr;
|
protected Attribute _statusAttr;
|
||||||
protected Attribute _resourceStateAttr;
|
protected Attribute _resourceStateAttr;
|
||||||
protected Attribute _msIdAttr;
|
protected Attribute _msIdAttr;
|
||||||
@ -455,6 +463,22 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
HostIdSearch.and("dataCenterId", HostIdSearch.entity().getDataCenterId(), Op.EQ);
|
HostIdSearch.and("dataCenterId", HostIdSearch.entity().getDataCenterId(), Op.EQ);
|
||||||
HostIdSearch.done();
|
HostIdSearch.done();
|
||||||
|
|
||||||
|
searchBuilderFindByRuleTag = _hostTagsDao.createSearchBuilder();
|
||||||
|
searchBuilderFindByRuleTag.and("is_tag_a_rule", searchBuilderFindByRuleTag.entity().getIsTagARule(), Op.EQ);
|
||||||
|
searchBuilderFindByRuleTag.or("tagDoesNotExist", searchBuilderFindByRuleTag.entity().getIsTagARule(), Op.NULL);
|
||||||
|
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag = createSearchBuilder();
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getId(), Op.EQ);
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("type", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getType(), Op.EQ);
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("cluster_id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getClusterId(), Op.EQ);
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("pod_id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getPodId(), Op.EQ);
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("data_center_id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getDataCenterId(), Op.EQ);
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.join("id", searchBuilderFindByRuleTag, searchBuilderFindByRuleTag.entity().getHostId(),
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getId(), JoinType.LEFTOUTER);
|
||||||
|
|
||||||
|
searchBuilderFindByRuleTag.done();
|
||||||
|
searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.done();
|
||||||
|
|
||||||
_statusAttr = _allAttributes.get("status");
|
_statusAttr = _allAttributes.get("status");
|
||||||
_msIdAttr = _allAttributes.get("managementServerId");
|
_msIdAttr = _allAttributes.get("managementServerId");
|
||||||
_pingTimeAttr = _allAttributes.get("lastPinged");
|
_pingTimeAttr = _allAttributes.get("lastPinged");
|
||||||
@ -792,9 +816,12 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<HostVO> listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId, String haTag) {
|
public List<HostVO> listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId, String haTag) {
|
||||||
SearchBuilder<HostTagVO> hostTagSearch = null;
|
SearchBuilder<HostTagVO> hostTagSearch = _hostTagsDao.createSearchBuilder();
|
||||||
|
hostTagSearch.and();
|
||||||
|
hostTagSearch.op("isTagARule", hostTagSearch.entity().getIsTagARule(), Op.EQ);
|
||||||
|
hostTagSearch.or("tagDoesNotExist", hostTagSearch.entity().getIsTagARule(), Op.NULL);
|
||||||
|
hostTagSearch.cp();
|
||||||
if (haTag != null && !haTag.isEmpty()) {
|
if (haTag != null && !haTag.isEmpty()) {
|
||||||
hostTagSearch = _hostTagsDao.createSearchBuilder();
|
|
||||||
hostTagSearch.and().op("tag", hostTagSearch.entity().getTag(), SearchCriteria.Op.NEQ);
|
hostTagSearch.and().op("tag", hostTagSearch.entity().getTag(), SearchCriteria.Op.NEQ);
|
||||||
hostTagSearch.or("tagNull", hostTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
|
hostTagSearch.or("tagNull", hostTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
|
||||||
hostTagSearch.cp();
|
hostTagSearch.cp();
|
||||||
@ -809,12 +836,14 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
hostSearch.and("status", hostSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
hostSearch.and("status", hostSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
||||||
hostSearch.and("resourceState", hostSearch.entity().getResourceState(), SearchCriteria.Op.EQ);
|
hostSearch.and("resourceState", hostSearch.entity().getResourceState(), SearchCriteria.Op.EQ);
|
||||||
|
|
||||||
if (haTag != null && !haTag.isEmpty()) {
|
|
||||||
hostSearch.join("hostTagSearch", hostTagSearch, hostSearch.entity().getId(), hostTagSearch.entity().getHostId(), JoinBuilder.JoinType.LEFTOUTER);
|
hostSearch.join("hostTagSearch", hostTagSearch, hostSearch.entity().getId(), hostTagSearch.entity().getHostId(), JoinBuilder.JoinType.LEFTOUTER);
|
||||||
}
|
|
||||||
|
|
||||||
SearchCriteria<HostVO> sc = hostSearch.create();
|
SearchCriteria<HostVO> sc = hostSearch.create();
|
||||||
|
|
||||||
|
sc.setJoinParameters("hostTagSearch", "isTagARule", false);
|
||||||
|
|
||||||
if (haTag != null && !haTag.isEmpty()) {
|
if (haTag != null && !haTag.isEmpty()) {
|
||||||
sc.setJoinParameters("hostTagSearch", "tag", haTag);
|
sc.setJoinParameters("hostTagSearch", "tag", haTag);
|
||||||
}
|
}
|
||||||
@ -846,8 +875,13 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadHostTags(HostVO host) {
|
public void loadHostTags(HostVO host) {
|
||||||
List<String> hostTags = _hostTagsDao.getHostTags(host.getId());
|
List<HostTagVO> hostTagVOList = _hostTagsDao.getHostTags(host.getId());
|
||||||
host.setHostTags(hostTags);
|
if (CollectionUtils.isNotEmpty(hostTagVOList)) {
|
||||||
|
List<String> hostTagList = hostTagVOList.parallelStream().map(HostTagVO::getTag).collect(Collectors.toList());
|
||||||
|
host.setHostTags(hostTagList, hostTagVOList.get(0).getIsTagARule());
|
||||||
|
} else {
|
||||||
|
host.setHostTags(null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DB
|
@DB
|
||||||
@ -881,10 +915,10 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
|
|
||||||
protected void saveHostTags(HostVO host) {
|
protected void saveHostTags(HostVO host) {
|
||||||
List<String> hostTags = host.getHostTags();
|
List<String> hostTags = host.getHostTags();
|
||||||
if (hostTags == null || (hostTags != null && hostTags.isEmpty())) {
|
if (CollectionUtils.isEmpty(hostTags)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_hostTagsDao.persist(host.getId(), hostTags);
|
_hostTagsDao.persist(host.getId(), hostTags, host.getIsTagARule());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void saveGpuRecords(HostVO host) {
|
protected void saveGpuRecords(HostVO host) {
|
||||||
@ -1244,6 +1278,26 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HostVO> listAllHostsThatHaveNoRuleTag(Type type, Long clusterId, Long podId, Long dcId) {
|
||||||
|
SearchCriteria<HostVO> sc = searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.create();
|
||||||
|
if (type != null) {
|
||||||
|
sc.setParameters("type", type);
|
||||||
|
}
|
||||||
|
if (clusterId != null) {
|
||||||
|
sc.setParameters("cluster_id", clusterId);
|
||||||
|
}
|
||||||
|
if (podId != null) {
|
||||||
|
sc.setParameters("pod_id", podId);
|
||||||
|
}
|
||||||
|
if (dcId != null) {
|
||||||
|
sc.setParameters("data_center_id", dcId);
|
||||||
|
}
|
||||||
|
sc.setJoinParameters("id", "is_tag_a_rule", false);
|
||||||
|
|
||||||
|
return search(sc, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Long> listClustersByHostTag(String computeOfferingTags) {
|
public List<Long> listClustersByHostTag(String computeOfferingTags) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
@ -1266,9 +1320,6 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
result.add(rs.getLong(1));
|
result.add(rs.getLong(1));
|
||||||
}
|
}
|
||||||
pstmt.close();
|
pstmt.close();
|
||||||
if(result.isEmpty()){
|
|
||||||
throw new CloudRuntimeException("No suitable host found for follow compute offering tags: " + computeOfferingTags);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new CloudRuntimeException("DB Exception on: " + sql, e);
|
throw new CloudRuntimeException("DB Exception on: " + sql, e);
|
||||||
@ -1293,15 +1344,33 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
|
|||||||
result.add(rs.getLong(1));
|
result.add(rs.getLong(1));
|
||||||
}
|
}
|
||||||
pstmt.close();
|
pstmt.close();
|
||||||
if(result.isEmpty()){
|
|
||||||
throw new CloudRuntimeException("No suitable host found for follow compute offering tags: " + computeOfferingTags);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new CloudRuntimeException("DB Exception on: " + select, e);
|
throw new CloudRuntimeException("DB Exception on: " + select, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<HostVO> findHostsWithTagRuleThatMatchComputeOferringTags(String computeOfferingTags) {
|
||||||
|
List<HostTagVO> hostTagVOList = _hostTagsDao.findHostRuleTags();
|
||||||
|
List<HostVO> result = new ArrayList<>();
|
||||||
|
for (HostTagVO rule: hostTagVOList) {
|
||||||
|
if (TagAsRuleHelper.interpretTagAsRule(rule.getTag(), computeOfferingTags, HostTagsDao.hostTagRuleExecutionTimeout.value())) {
|
||||||
|
result.add(findById(rule.getHostId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> findClustersThatMatchHostTagRule(String computeOfferingTags) {
|
||||||
|
Set<Long> result = new HashSet<>();
|
||||||
|
List<HostVO> hosts = findHostsWithTagRuleThatMatchComputeOferringTags(computeOfferingTags);
|
||||||
|
for (HostVO host: hosts) {
|
||||||
|
result.add(host.getClusterId());
|
||||||
|
}
|
||||||
|
return new ArrayList<>(result);
|
||||||
|
}
|
||||||
|
|
||||||
private String getHostIdsByComputeTags(List<String> offeringTags){
|
private String getHostIdsByComputeTags(List<String> offeringTags){
|
||||||
List<String> questionMarks = new ArrayList();
|
List<String> questionMarks = new ArrayList();
|
||||||
offeringTags.forEach((tag) -> { questionMarks.add("?"); });
|
offeringTags.forEach((tag) -> { questionMarks.add("?"); });
|
||||||
|
|||||||
@ -20,15 +20,21 @@ import java.util.List;
|
|||||||
|
|
||||||
import com.cloud.host.HostTagVO;
|
import com.cloud.host.HostTagVO;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
|
||||||
public interface HostTagsDao extends GenericDao<HostTagVO, Long> {
|
public interface HostTagsDao extends GenericDao<HostTagVO, Long> {
|
||||||
|
|
||||||
void persist(long hostId, List<String> hostTags);
|
ConfigKey<Long> hostTagRuleExecutionTimeout = new ConfigKey<>("Advanced", Long.class, "host.tag.rule.execution.timeout", "2000", "The maximum runtime, in milliseconds, " +
|
||||||
|
"to execute a host tag rule; if it is reached, a timeout will happen.", true);
|
||||||
|
|
||||||
List<String> getHostTags(long hostId);
|
void persist(long hostId, List<String> hostTags, Boolean isTagARule);
|
||||||
|
|
||||||
|
List<HostTagVO> getHostTags(long hostId);
|
||||||
|
|
||||||
List<String> getDistinctImplicitHostTags(List<Long> hostIds, String[] implicitHostTags);
|
List<String> getDistinctImplicitHostTags(List<Long> hostIds, String[] implicitHostTags);
|
||||||
|
|
||||||
void deleteTags(long hostId);
|
void deleteTags(long hostId);
|
||||||
|
|
||||||
|
List<HostTagVO> findHostRuleTags();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,10 +16,10 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.host.dao;
|
package com.cloud.host.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.host.HostTagVO;
|
import com.cloud.host.HostTagVO;
|
||||||
@ -31,13 +31,14 @@ import com.cloud.utils.db.TransactionLegacy;
|
|||||||
import com.cloud.utils.db.SearchCriteria.Func;
|
import com.cloud.utils.db.SearchCriteria.Func;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class HostTagsDaoImpl extends GenericDaoBase<HostTagVO, Long> implements HostTagsDao {
|
public class HostTagsDaoImpl extends GenericDaoBase<HostTagVO, Long> implements HostTagsDao, Configurable {
|
||||||
protected final SearchBuilder<HostTagVO> HostSearch;
|
protected final SearchBuilder<HostTagVO> HostSearch;
|
||||||
protected final GenericSearchBuilder<HostTagVO, String> DistinctImplictTagsSearch;
|
protected final GenericSearchBuilder<HostTagVO, String> DistinctImplictTagsSearch;
|
||||||
|
|
||||||
public HostTagsDaoImpl() {
|
public HostTagsDaoImpl() {
|
||||||
HostSearch = createSearchBuilder();
|
HostSearch = createSearchBuilder();
|
||||||
HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
|
HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
|
||||||
|
HostSearch.and("isTagARule", HostSearch.entity().getIsTagARule(), SearchCriteria.Op.EQ);
|
||||||
HostSearch.done();
|
HostSearch.done();
|
||||||
|
|
||||||
DistinctImplictTagsSearch = createSearchBuilder(String.class);
|
DistinctImplictTagsSearch = createSearchBuilder(String.class);
|
||||||
@ -48,17 +49,11 @@ public class HostTagsDaoImpl extends GenericDaoBase<HostTagVO, Long> implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getHostTags(long hostId) {
|
public List<HostTagVO> getHostTags(long hostId) {
|
||||||
SearchCriteria<HostTagVO> sc = HostSearch.create();
|
SearchCriteria<HostTagVO> sc = HostSearch.create();
|
||||||
sc.setParameters("hostId", hostId);
|
sc.setParameters("hostId", hostId);
|
||||||
|
|
||||||
List<HostTagVO> results = search(sc, null);
|
return search(sc, null);
|
||||||
List<String> hostTags = new ArrayList<String>(results.size());
|
|
||||||
for (HostTagVO result : results) {
|
|
||||||
hostTags.add(result.getTag());
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostTags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -80,7 +75,15 @@ public class HostTagsDaoImpl extends GenericDaoBase<HostTagVO, Long> implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void persist(long hostId, List<String> hostTags) {
|
public List<HostTagVO> findHostRuleTags() {
|
||||||
|
SearchCriteria<HostTagVO> sc = HostSearch.create();
|
||||||
|
sc.setParameters("isTagARule", true);
|
||||||
|
|
||||||
|
return search(sc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void persist(long hostId, List<String> hostTags, Boolean isTagARule) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
|
||||||
txn.start();
|
txn.start();
|
||||||
@ -91,10 +94,20 @@ public class HostTagsDaoImpl extends GenericDaoBase<HostTagVO, Long> implements
|
|||||||
for (String tag : hostTags) {
|
for (String tag : hostTags) {
|
||||||
tag = tag.trim();
|
tag = tag.trim();
|
||||||
if (tag.length() > 0) {
|
if (tag.length() > 0) {
|
||||||
HostTagVO vo = new HostTagVO(hostId, tag);
|
HostTagVO vo = new HostTagVO(hostId, tag, isTagARule);
|
||||||
persist(vo);
|
persist(vo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
|
return new ConfigKey<?>[] {hostTagRuleExecutionTimeout};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfigComponentName() {
|
||||||
|
return HostTagsDaoImpl.class.getSimpleName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,9 @@ import javax.persistence.GenerationType;
|
|||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import com.cloud.utils.NumbersUtil;
|
||||||
import org.apache.cloudstack.api.InternalIdentity;
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "storage_pool_tags")
|
@Table(name = "storage_pool_tags")
|
||||||
@ -43,9 +45,19 @@ public class StoragePoolTagVO implements InternalIdentity {
|
|||||||
@Column(name = "tag")
|
@Column(name = "tag")
|
||||||
private String tag;
|
private String tag;
|
||||||
|
|
||||||
|
@Column(name = "is_tag_a_rule")
|
||||||
|
private boolean isTagARule;
|
||||||
|
|
||||||
public StoragePoolTagVO(long poolId, String tag) {
|
public StoragePoolTagVO(long poolId, String tag) {
|
||||||
this.poolId = poolId;
|
this.poolId = poolId;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
this.isTagARule = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoragePoolTagVO(long poolId, String tag, Boolean isTagARule) {
|
||||||
|
this.poolId = poolId;
|
||||||
|
this.tag = tag;
|
||||||
|
this.isTagARule = BooleanUtils.toBooleanDefaultIfNull(isTagARule, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,4 +73,20 @@ public class StoragePoolTagVO implements InternalIdentity {
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isTagARule() {
|
||||||
|
return this.isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof StoragePoolTagVO) {
|
||||||
|
return this.poolId == ((StoragePoolTagVO)obj).getPoolId();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return NumbersUtil.hash(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,10 +25,14 @@ import com.cloud.utils.db.GenericDao;
|
|||||||
|
|
||||||
public interface StoragePoolTagsDao extends GenericDao<StoragePoolTagVO, Long> {
|
public interface StoragePoolTagsDao extends GenericDao<StoragePoolTagVO, Long> {
|
||||||
|
|
||||||
void persist(long poolId, List<String> storagePoolTags);
|
void persist(long poolId, List<String> storagePoolTags, Boolean isTagARule);
|
||||||
|
|
||||||
|
void persist(List<StoragePoolTagVO> storagePoolTags);
|
||||||
List<String> getStoragePoolTags(long poolId);
|
List<String> getStoragePoolTags(long poolId);
|
||||||
void deleteTags(long poolId);
|
void deleteTags(long poolId);
|
||||||
List<StoragePoolTagVO> searchByIds(Long... stIds);
|
List<StoragePoolTagVO> searchByIds(Long... stIds);
|
||||||
StorageTagResponse newStorageTagResponse(StoragePoolTagVO tag);
|
StorageTagResponse newStorageTagResponse(StoragePoolTagVO tag);
|
||||||
|
|
||||||
|
List<StoragePoolTagVO> findStoragePoolTags(long poolId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,9 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallbackNoReturn;
|
||||||
|
import com.cloud.utils.db.TransactionStatus;
|
||||||
import org.apache.cloudstack.api.response.StorageTagResponse;
|
import org.apache.cloudstack.api.response.StorageTagResponse;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
|
||||||
@ -50,7 +53,7 @@ public class StoragePoolTagsDaoImpl extends GenericDaoBase<StoragePoolTagVO, Lon
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void persist(long poolId, List<String> storagePoolTags) {
|
public void persist(long poolId, List<String> storagePoolTags, Boolean isTagARule) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
|
||||||
txn.start();
|
txn.start();
|
||||||
@ -61,13 +64,23 @@ public class StoragePoolTagsDaoImpl extends GenericDaoBase<StoragePoolTagVO, Lon
|
|||||||
for (String tag : storagePoolTags) {
|
for (String tag : storagePoolTags) {
|
||||||
tag = tag.trim();
|
tag = tag.trim();
|
||||||
if (tag.length() > 0) {
|
if (tag.length() > 0) {
|
||||||
StoragePoolTagVO vo = new StoragePoolTagVO(poolId, tag);
|
StoragePoolTagVO vo = new StoragePoolTagVO(poolId, tag, isTagARule);
|
||||||
persist(vo);
|
persist(vo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void persist(List<StoragePoolTagVO> storagePoolTags) {
|
||||||
|
Transaction.execute(TransactionLegacy.CLOUD_DB, new TransactionCallbackNoReturn() {
|
||||||
|
@Override public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
for (StoragePoolTagVO storagePoolTagVO : storagePoolTags) {
|
||||||
|
persist(storagePoolTagVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getStoragePoolTags(long poolId) {
|
public List<String> getStoragePoolTags(long poolId) {
|
||||||
SearchCriteria<StoragePoolTagVO> sc = StoragePoolSearch.create();
|
SearchCriteria<StoragePoolTagVO> sc = StoragePoolSearch.create();
|
||||||
@ -157,4 +170,12 @@ public class StoragePoolTagsDaoImpl extends GenericDaoBase<StoragePoolTagVO, Lon
|
|||||||
return tagResponse;
|
return tagResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StoragePoolTagVO> findStoragePoolTags(long poolId) {
|
||||||
|
SearchCriteria<StoragePoolTagVO> sc = StoragePoolSearch.create();
|
||||||
|
sc.setParameters("poolId", poolId);
|
||||||
|
|
||||||
|
return search(sc, null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,7 +53,7 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
*/
|
*/
|
||||||
void updateCapacityIops(long id, long capacityIops);
|
void updateCapacityIops(long id, long capacityIops);
|
||||||
|
|
||||||
StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags);
|
StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags, Boolean isTagARule);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find pool by name.
|
* Find pool by name.
|
||||||
@ -77,7 +77,7 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
*/
|
*/
|
||||||
List<StoragePoolVO> findPoolsByDetails(long dcId, long podId, Long clusterId, Map<String, String> details, ScopeType scope);
|
List<StoragePoolVO> findPoolsByDetails(long dcId, long podId, Long clusterId, Map<String, String> details, ScopeType scope);
|
||||||
|
|
||||||
List<StoragePoolVO> findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags);
|
List<StoragePoolVO> findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, boolean validateTagRule, long ruleExecuteTimeout);
|
||||||
|
|
||||||
List<StoragePoolVO> findDisabledPoolsByScope(long dcId, Long podId, Long clusterId, ScopeType scope);
|
List<StoragePoolVO> findDisabledPoolsByScope(long dcId, Long podId, Long clusterId, ScopeType scope);
|
||||||
|
|
||||||
@ -112,9 +112,9 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
|
|||||||
|
|
||||||
List<StoragePoolVO> listPoolsByCluster(long clusterId);
|
List<StoragePoolVO> listPoolsByCluster(long clusterId);
|
||||||
|
|
||||||
List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags);
|
List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags, boolean validateTagRule);
|
||||||
|
|
||||||
List<StoragePoolVO> findZoneWideStoragePoolsByTags(long dcId, String[] tags);
|
List<StoragePoolVO> findZoneWideStoragePoolsByTags(long dcId, String[] tags, boolean validateTagRule);
|
||||||
|
|
||||||
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType);
|
List<StoragePoolVO> findZoneWideStoragePoolsByHypervisor(long dataCenterId, HypervisorType hypervisorType);
|
||||||
|
|
||||||
|
|||||||
@ -67,11 +67,11 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
|
|
||||||
protected final String DetailsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_details ON storage_pool.id = storage_pool_details.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' and storage_pool.data_center_id = ? and (storage_pool.pod_id = ? or storage_pool.pod_id is null) and storage_pool.scope = ? and (";
|
protected final String DetailsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_details ON storage_pool.id = storage_pool_details.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' and storage_pool.data_center_id = ? and (storage_pool.pod_id = ? or storage_pool.pod_id is null) and storage_pool.scope = ? and (";
|
||||||
protected final String DetailsSqlSuffix = ") GROUP BY storage_pool_details.pool_id HAVING COUNT(storage_pool_details.name) >= ?";
|
protected final String DetailsSqlSuffix = ") GROUP BY storage_pool_details.pool_id HAVING COUNT(storage_pool_details.name) >= ?";
|
||||||
private final String ZoneWideTagsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_tags ON storage_pool.id = storage_pool_tags.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' and storage_pool.data_center_id = ? and storage_pool.scope = ? and (";
|
private final String ZoneWideTagsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_tags ON storage_pool.id = storage_pool_tags.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' AND storage_pool_tags.is_tag_a_rule = 0 and storage_pool.data_center_id = ? and storage_pool.scope = ? and (";
|
||||||
private final String ZoneWideTagsSqlSuffix = ") GROUP BY storage_pool_tags.pool_id HAVING COUNT(storage_pool_tags.tag) >= ?";
|
private final String ZoneWideTagsSqlSuffix = ") GROUP BY storage_pool_tags.pool_id HAVING COUNT(storage_pool_tags.tag) >= ?";
|
||||||
|
|
||||||
// Storage tags are now separate from storage_pool_details, leaving only details on that table
|
// Storage tags are now separate from storage_pool_details, leaving only details on that table
|
||||||
protected final String TagsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_tags ON storage_pool.id = storage_pool_tags.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' and storage_pool.data_center_id = ? and (storage_pool.pod_id = ? or storage_pool.pod_id is null) and storage_pool.scope = ? and (";
|
protected final String TagsSqlPrefix = "SELECT storage_pool.* from storage_pool LEFT JOIN storage_pool_tags ON storage_pool.id = storage_pool_tags.pool_id WHERE storage_pool.removed is null and storage_pool.status = 'Up' AND storage_pool_tags.is_tag_a_rule = 0 and storage_pool.data_center_id = ? and (storage_pool.pod_id = ? or storage_pool.pod_id is null) and storage_pool.scope = ? and (";
|
||||||
protected final String TagsSqlSuffix = ") GROUP BY storage_pool_tags.pool_id HAVING COUNT(storage_pool_tags.tag) >= ?";
|
protected final String TagsSqlSuffix = ") GROUP BY storage_pool_tags.pool_id HAVING COUNT(storage_pool_tags.tag) >= ?";
|
||||||
|
|
||||||
private static final String GET_STORAGE_POOLS_OF_VOLUMES_WITHOUT_OR_NOT_HAVING_TAGS = "SELECT s.* " +
|
private static final String GET_STORAGE_POOLS_OF_VOLUMES_WITHOUT_OR_NOT_HAVING_TAGS = "SELECT s.* " +
|
||||||
@ -278,7 +278,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DB
|
@DB
|
||||||
public StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags) {
|
public StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, List<String> tags, Boolean isTagARule) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
txn.start();
|
txn.start();
|
||||||
pool = super.persist(pool);
|
pool = super.persist(pool);
|
||||||
@ -289,7 +289,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(tags)) {
|
if (CollectionUtils.isNotEmpty(tags)) {
|
||||||
_tagsDao.persist(pool.getId(), tags);
|
_tagsDao.persist(pool.getId(), tags, isTagARule);
|
||||||
}
|
}
|
||||||
txn.commit();
|
txn.commit();
|
||||||
return pool;
|
return pool;
|
||||||
@ -404,10 +404,15 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StoragePoolVO> findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags) {
|
public List<StoragePoolVO> findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, boolean validateTagRule, long ruleExecuteTimeout) {
|
||||||
List<StoragePoolVO> storagePools = null;
|
List<StoragePoolVO> storagePools = null;
|
||||||
if (tags == null || tags.length == 0) {
|
if (tags == null || tags.length == 0) {
|
||||||
storagePools = listBy(dcId, podId, clusterId, ScopeType.CLUSTER);
|
storagePools = listBy(dcId, podId, clusterId, ScopeType.CLUSTER);
|
||||||
|
|
||||||
|
if (validateTagRule) {
|
||||||
|
storagePools = getPoolsWithoutTagRule(storagePools);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
String sqlValues = getSqlValuesFromStorageTags(tags);
|
String sqlValues = getSqlValuesFromStorageTags(tags);
|
||||||
storagePools = findPoolsByDetailsOrTagsInternal(dcId, podId, clusterId, ScopeType.CLUSTER, sqlValues, ValueType.TAGS, tags.length);
|
storagePools = findPoolsByDetailsOrTagsInternal(dcId, podId, clusterId, ScopeType.CLUSTER, sqlValues, ValueType.TAGS, tags.length);
|
||||||
@ -437,10 +442,14 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags) {
|
public List<StoragePoolVO> findLocalStoragePoolsByTags(long dcId, long podId, Long clusterId, String[] tags, boolean validateTagRule) {
|
||||||
List<StoragePoolVO> storagePools = null;
|
List<StoragePoolVO> storagePools = null;
|
||||||
if (tags == null || tags.length == 0) {
|
if (tags == null || tags.length == 0) {
|
||||||
storagePools = listBy(dcId, podId, clusterId, ScopeType.HOST);
|
storagePools = listBy(dcId, podId, clusterId, ScopeType.HOST);
|
||||||
|
|
||||||
|
if (validateTagRule) {
|
||||||
|
storagePools = getPoolsWithoutTagRule(storagePools);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
String sqlValues = getSqlValuesFromStorageTags(tags);
|
String sqlValues = getSqlValuesFromStorageTags(tags);
|
||||||
storagePools = findPoolsByDetailsOrTagsInternal(dcId, podId, clusterId, ScopeType.HOST, sqlValues, ValueType.TAGS, tags.length);
|
storagePools = findPoolsByDetailsOrTagsInternal(dcId, podId, clusterId, ScopeType.HOST, sqlValues, ValueType.TAGS, tags.length);
|
||||||
@ -483,13 +492,20 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<StoragePoolVO> findZoneWideStoragePoolsByTags(long dcId, String[] tags) {
|
public List<StoragePoolVO> findZoneWideStoragePoolsByTags(long dcId, String[] tags, boolean validateTagRule) {
|
||||||
if (tags == null || tags.length == 0) {
|
if (tags == null || tags.length == 0) {
|
||||||
QueryBuilder<StoragePoolVO> sc = QueryBuilder.create(StoragePoolVO.class);
|
QueryBuilder<StoragePoolVO> sc = QueryBuilder.create(StoragePoolVO.class);
|
||||||
sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
|
sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
|
||||||
sc.and(sc.entity().getStatus(), Op.EQ, Status.Up);
|
sc.and(sc.entity().getStatus(), Op.EQ, Status.Up);
|
||||||
sc.and(sc.entity().getScope(), Op.EQ, ScopeType.ZONE);
|
sc.and(sc.entity().getScope(), Op.EQ, ScopeType.ZONE);
|
||||||
return sc.list();
|
|
||||||
|
List<StoragePoolVO> storagePools = sc.list();
|
||||||
|
|
||||||
|
if (validateTagRule) {
|
||||||
|
storagePools = getPoolsWithoutTagRule(storagePools);
|
||||||
|
}
|
||||||
|
|
||||||
|
return storagePools;
|
||||||
} else {
|
} else {
|
||||||
String sqlValues = getSqlValuesFromStorageTags(tags);
|
String sqlValues = getSqlValuesFromStorageTags(tags);
|
||||||
String sql = getSqlPreparedStatement(ZoneWideTagsSqlPrefix, ZoneWideTagsSqlSuffix, sqlValues, null);
|
String sql = getSqlPreparedStatement(ZoneWideTagsSqlPrefix, ZoneWideTagsSqlSuffix, sqlValues, null);
|
||||||
@ -497,6 +513,20 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<StoragePoolVO> getPoolsWithoutTagRule(List<StoragePoolVO> storagePools) {
|
||||||
|
List<StoragePoolVO> storagePoolsToReturn = new ArrayList<>();
|
||||||
|
for (StoragePoolVO storagePool : storagePools) {
|
||||||
|
|
||||||
|
List<StoragePoolTagVO> poolTags = _tagsDao.findStoragePoolTags(storagePool.getId());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(poolTags) || !poolTags.get(0).isTagARule()) {
|
||||||
|
storagePoolsToReturn.add(storagePool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return storagePoolsToReturn;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> searchForStoragePoolTags(long poolId) {
|
public List<String> searchForStoragePoolTags(long poolId) {
|
||||||
return _tagsDao.getStoragePoolTags(poolId);
|
return _tagsDao.getStoragePoolTags(poolId);
|
||||||
|
|||||||
@ -224,3 +224,12 @@ CREATE TABLE `cloud`.`oauth_provider` (
|
|||||||
`removed` datetime COMMENT 'date removed if not null',
|
`removed` datetime COMMENT 'date removed if not null',
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- Flexible tags
|
||||||
|
ALTER TABLE `cloud`.`storage_pool_tags` ADD COLUMN is_tag_a_rule int(1) UNSIGNED not null DEFAULT 0;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`storage_pool_tags` MODIFY tag text NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`host_tags` ADD COLUMN is_tag_a_rule int(1) UNSIGNED not null DEFAULT 0;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`host_tags` MODIFY tag text NOT NULL;
|
||||||
|
|||||||
@ -0,0 +1,111 @@
|
|||||||
|
-- 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.
|
||||||
|
|
||||||
|
-- VIEW `cloud`.`host_view`;
|
||||||
|
|
||||||
|
DROP VIEW IF EXISTS `cloud`.`host_view`;
|
||||||
|
|
||||||
|
CREATE VIEW `cloud`.`host_view` AS
|
||||||
|
SELECT
|
||||||
|
host.id,
|
||||||
|
host.uuid,
|
||||||
|
host.name,
|
||||||
|
host.status,
|
||||||
|
host.disconnected,
|
||||||
|
host.type,
|
||||||
|
host.private_ip_address,
|
||||||
|
host.version,
|
||||||
|
host.hypervisor_type,
|
||||||
|
host.hypervisor_version,
|
||||||
|
host.capabilities,
|
||||||
|
host.last_ping,
|
||||||
|
host.created,
|
||||||
|
host.removed,
|
||||||
|
host.resource_state,
|
||||||
|
host.mgmt_server_id,
|
||||||
|
host.cpu_sockets,
|
||||||
|
host.cpus,
|
||||||
|
host.speed,
|
||||||
|
host.ram,
|
||||||
|
cluster.id cluster_id,
|
||||||
|
cluster.uuid cluster_uuid,
|
||||||
|
cluster.name cluster_name,
|
||||||
|
cluster.cluster_type,
|
||||||
|
data_center.id data_center_id,
|
||||||
|
data_center.uuid data_center_uuid,
|
||||||
|
data_center.name data_center_name,
|
||||||
|
data_center.networktype data_center_type,
|
||||||
|
host_pod_ref.id pod_id,
|
||||||
|
host_pod_ref.uuid pod_uuid,
|
||||||
|
host_pod_ref.name pod_name,
|
||||||
|
GROUP_CONCAT(DISTINCT(host_tags.tag)) AS tag,
|
||||||
|
`host_tags`.`is_tag_a_rule` AS `is_tag_a_rule`,
|
||||||
|
guest_os_category.id guest_os_category_id,
|
||||||
|
guest_os_category.uuid guest_os_category_uuid,
|
||||||
|
guest_os_category.name guest_os_category_name,
|
||||||
|
mem_caps.used_capacity memory_used_capacity,
|
||||||
|
mem_caps.reserved_capacity memory_reserved_capacity,
|
||||||
|
cpu_caps.used_capacity cpu_used_capacity,
|
||||||
|
cpu_caps.reserved_capacity cpu_reserved_capacity,
|
||||||
|
async_job.id job_id,
|
||||||
|
async_job.uuid job_uuid,
|
||||||
|
async_job.job_status job_status,
|
||||||
|
async_job.account_id job_account_id,
|
||||||
|
oobm.enabled AS `oobm_enabled`,
|
||||||
|
oobm.power_state AS `oobm_power_state`,
|
||||||
|
ha_config.enabled AS `ha_enabled`,
|
||||||
|
ha_config.ha_state AS `ha_state`,
|
||||||
|
ha_config.provider AS `ha_provider`,
|
||||||
|
`last_annotation_view`.`annotation` AS `annotation`,
|
||||||
|
`last_annotation_view`.`created` AS `last_annotated`,
|
||||||
|
`user`.`username` AS `username`
|
||||||
|
FROM
|
||||||
|
`cloud`.`host`
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`cluster` ON host.cluster_id = cluster.id
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`data_center` ON host.data_center_id = data_center.id
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`host_pod_ref` ON host.pod_id = host_pod_ref.id
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`host_details` ON host.id = host_details.host_id
|
||||||
|
AND host_details.name = 'guest.os.category.id'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`guest_os_category` ON guest_os_category.id = CONVERT ( host_details.value, UNSIGNED )
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`host_tags` ON host_tags.host_id = host.id
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`op_host_capacity` mem_caps ON host.id = mem_caps.host_id
|
||||||
|
AND mem_caps.capacity_type = 0
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`op_host_capacity` cpu_caps ON host.id = cpu_caps.host_id
|
||||||
|
AND cpu_caps.capacity_type = 1
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`async_job` ON async_job.instance_id = host.id
|
||||||
|
AND async_job.instance_type = 'Host'
|
||||||
|
AND async_job.job_status = 0
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`oobm` ON oobm.host_id = host.id
|
||||||
|
left join
|
||||||
|
`cloud`.`ha_config` ON ha_config.resource_id=host.id
|
||||||
|
and ha_config.resource_type='Host'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`last_annotation_view` ON `last_annotation_view`.`entity_uuid` = `host`.`uuid`
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`user` ON `user`.`uuid` = `last_annotation_view`.`user_uuid`
|
||||||
|
GROUP BY
|
||||||
|
`host`.`id`;
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
-- Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
-- or more contributor license agreements. See the NOTICE file
|
||||||
|
-- distributed with this work for additional information
|
||||||
|
-- regarding copyright ownership. The ASF licenses this file
|
||||||
|
-- to you under the Apache License, Version 2.0 (the
|
||||||
|
-- "License"); you may not use this file except in compliance
|
||||||
|
-- with the License. You may obtain a copy of the License at
|
||||||
|
--
|
||||||
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
--
|
||||||
|
-- Unless required by applicable law or agreed to in writing,
|
||||||
|
-- software distributed under the License is distributed on an
|
||||||
|
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
-- KIND, either express or implied. See the License for the
|
||||||
|
-- specific language governing permissions and limitations
|
||||||
|
-- under the License.
|
||||||
|
|
||||||
|
-- VIEW `cloud`.`storage_pool_view`;
|
||||||
|
|
||||||
|
DROP VIEW IF EXISTS `cloud`.`storage_pool_view`;
|
||||||
|
|
||||||
|
CREATE VIEW `cloud`.`storage_pool_view` AS
|
||||||
|
SELECT
|
||||||
|
`storage_pool`.`id` AS `id`,
|
||||||
|
`storage_pool`.`uuid` AS `uuid`,
|
||||||
|
`storage_pool`.`name` AS `name`,
|
||||||
|
`storage_pool`.`status` AS `status`,
|
||||||
|
`storage_pool`.`path` AS `path`,
|
||||||
|
`storage_pool`.`pool_type` AS `pool_type`,
|
||||||
|
`storage_pool`.`host_address` AS `host_address`,
|
||||||
|
`storage_pool`.`created` AS `created`,
|
||||||
|
`storage_pool`.`removed` AS `removed`,
|
||||||
|
`storage_pool`.`capacity_bytes` AS `capacity_bytes`,
|
||||||
|
`storage_pool`.`capacity_iops` AS `capacity_iops`,
|
||||||
|
`storage_pool`.`scope` AS `scope`,
|
||||||
|
`storage_pool`.`hypervisor` AS `hypervisor`,
|
||||||
|
`storage_pool`.`storage_provider_name` AS `storage_provider_name`,
|
||||||
|
`storage_pool`.`parent` AS `parent`,
|
||||||
|
`cluster`.`id` AS `cluster_id`,
|
||||||
|
`cluster`.`uuid` AS `cluster_uuid`,
|
||||||
|
`cluster`.`name` AS `cluster_name`,
|
||||||
|
`cluster`.`cluster_type` AS `cluster_type`,
|
||||||
|
`data_center`.`id` AS `data_center_id`,
|
||||||
|
`data_center`.`uuid` AS `data_center_uuid`,
|
||||||
|
`data_center`.`name` AS `data_center_name`,
|
||||||
|
`data_center`.`networktype` AS `data_center_type`,
|
||||||
|
`host_pod_ref`.`id` AS `pod_id`,
|
||||||
|
`host_pod_ref`.`uuid` AS `pod_uuid`,
|
||||||
|
`host_pod_ref`.`name` AS `pod_name`,
|
||||||
|
`storage_pool_tags`.`tag` AS `tag`,
|
||||||
|
`storage_pool_tags`.`is_tag_a_rule` AS `is_tag_a_rule`,
|
||||||
|
`op_host_capacity`.`used_capacity` AS `disk_used_capacity`,
|
||||||
|
`op_host_capacity`.`reserved_capacity` AS `disk_reserved_capacity`,
|
||||||
|
`async_job`.`id` AS `job_id`,
|
||||||
|
`async_job`.`uuid` AS `job_uuid`,
|
||||||
|
`async_job`.`job_status` AS `job_status`,
|
||||||
|
`async_job`.`account_id` AS `job_account_id`
|
||||||
|
FROM
|
||||||
|
((((((`cloud`.`storage_pool`
|
||||||
|
LEFT JOIN `cloud`.`cluster` ON ((`storage_pool`.`cluster_id` = `cluster`.`id`)))
|
||||||
|
LEFT JOIN `cloud`.`data_center` ON ((`storage_pool`.`data_center_id` = `data_center`.`id`)))
|
||||||
|
LEFT JOIN `cloud`.`host_pod_ref` ON ((`storage_pool`.`pod_id` = `host_pod_ref`.`id`)))
|
||||||
|
LEFT JOIN `cloud`.`storage_pool_tags` ON (((`storage_pool_tags`.`pool_id` = `storage_pool`.`id`))))
|
||||||
|
LEFT JOIN `cloud`.`op_host_capacity` ON (((`storage_pool`.`id` = `op_host_capacity`.`host_id`)
|
||||||
|
AND (`op_host_capacity`.`capacity_type` IN (3 , 9)))))
|
||||||
|
LEFT JOIN `cloud`.`async_job` ON (((`async_job`.`instance_id` = `storage_pool`.`id`)
|
||||||
|
AND (`async_job`.`instance_type` = 'StoragePool')
|
||||||
|
AND (`async_job`.`job_status` = 0))));
|
||||||
@ -1,61 +1,84 @@
|
|||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// or more contributor license agreements. See the NOTICE file
|
||||||
// distributed with this work for additional information
|
// distributed with this work for additional information
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
// to you under the Apache License, Version 2.0 (the
|
// to you under the Apache License, Version 2.0 (the
|
||||||
// "License"); you may not use this file except in compliance
|
// "License"); you may not use this file except in compliance
|
||||||
// with the License. You may obtain a copy of the License at
|
// with the License. You may obtain a copy of the License at
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing,
|
// Unless required by applicable law or agreed to in writing,
|
||||||
// software distributed under the License is distributed on an
|
// software distributed under the License is distributed on an
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
// KIND, either express or implied. See the License for the
|
// KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations
|
// specific language governing permissions and limitations
|
||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.host;
|
package com.cloud.host;
|
||||||
|
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import static org.junit.Assert.assertFalse;
|
import java.util.List;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import org.junit.Test;
|
import static org.junit.Assert.assertFalse;
|
||||||
import org.junit.Before;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import org.junit.Test;
|
||||||
public class HostVOTest {
|
import org.junit.Before;
|
||||||
HostVO host;
|
|
||||||
ServiceOfferingVO offering;
|
public class HostVOTest {
|
||||||
|
HostVO host;
|
||||||
@Before
|
ServiceOfferingVO offering;
|
||||||
public void setUp() throws Exception {
|
|
||||||
host = new HostVO();
|
@Before
|
||||||
offering = new ServiceOfferingVO("TestSO", 0, 0, 0, 0, 0,
|
public void setUp() throws Exception {
|
||||||
false, "TestSO", false,VirtualMachine.Type.User,false);
|
host = new HostVO();
|
||||||
}
|
offering = new ServiceOfferingVO("TestSO", 0, 0, 0, 0, 0,
|
||||||
|
false, "TestSO", false,VirtualMachine.Type.User,false);
|
||||||
@Test
|
}
|
||||||
public void testNoSO() {
|
|
||||||
assertFalse(host.checkHostServiceOfferingTags(null));
|
@Test
|
||||||
}
|
public void testNoSO() {
|
||||||
|
assertFalse(host.checkHostServiceOfferingTags(null));
|
||||||
@Test
|
}
|
||||||
public void testNoTag() {
|
|
||||||
assertTrue(host.checkHostServiceOfferingTags(offering));
|
@Test
|
||||||
}
|
public void testNoTag() {
|
||||||
|
assertTrue(host.checkHostServiceOfferingTags(offering));
|
||||||
@Test
|
}
|
||||||
public void testRightTag() {
|
|
||||||
host.setHostTags(Arrays.asList("tag1","tag2"));
|
@Test
|
||||||
offering.setHostTag("tag2,tag1");
|
public void testRightTag() {
|
||||||
assertTrue(host.checkHostServiceOfferingTags(offering));
|
host.setHostTags(Arrays.asList("tag1","tag2"), false);
|
||||||
}
|
offering.setHostTag("tag2,tag1");
|
||||||
|
assertTrue(host.checkHostServiceOfferingTags(offering));
|
||||||
@Test
|
}
|
||||||
public void testWrongTag() {
|
|
||||||
host.setHostTags(Arrays.asList("tag1","tag2"));
|
@Test
|
||||||
offering.setHostTag("tag2,tag4");
|
public void testWrongTag() {
|
||||||
assertFalse(host.checkHostServiceOfferingTags(offering));
|
host.setHostTags(Arrays.asList("tag1","tag2"), false);
|
||||||
}
|
offering.setHostTag("tag2,tag4");
|
||||||
}
|
assertFalse(host.checkHostServiceOfferingTags(offering));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkHostServiceOfferingTagsTestRuleTagWithServiceTagThatMatches() {
|
||||||
|
host.setHostTags(List.of("tags[0] == 'A'"), true);
|
||||||
|
offering.setHostTag("A");
|
||||||
|
assertTrue(host.checkHostServiceOfferingTags(offering));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkHostServiceOfferingTagsTestRuleTagWithServiceTagThatDoesNotMatch() {
|
||||||
|
host.setHostTags(List.of("tags[0] == 'A'"), true);
|
||||||
|
offering.setHostTag("B");
|
||||||
|
assertFalse(host.checkHostServiceOfferingTags(offering));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkHostServiceOfferingTagsTestRuleTagWithNullServiceTag() {
|
||||||
|
host.setHostTags(List.of("tags[0] == 'A'"), true);
|
||||||
|
offering.setHostTag(null);
|
||||||
|
assertFalse(host.checkHostServiceOfferingTags(offering));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import java.util.Map;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.api.query.dao.StoragePoolJoinDao;
|
||||||
import com.cloud.exception.StorageUnavailableException;
|
import com.cloud.exception.StorageUnavailableException;
|
||||||
import com.cloud.storage.ScopeType;
|
import com.cloud.storage.ScopeType;
|
||||||
import com.cloud.storage.StoragePoolStatus;
|
import com.cloud.storage.StoragePoolStatus;
|
||||||
@ -85,6 +86,9 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
|
|||||||
*/
|
*/
|
||||||
private SecureRandom secureRandom = new SecureRandom();
|
private SecureRandom secureRandom = new SecureRandom();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected StoragePoolJoinDao storagePoolJoinDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||||
super.configure(name, params);
|
super.configure(name, params);
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import java.util.Map;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.storage.VolumeApiServiceImpl;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -78,11 +79,12 @@ public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocat
|
|||||||
logDisabledStoragePools(dcId, podId, clusterId, ScopeType.CLUSTER);
|
logDisabledStoragePools(dcId, podId, clusterId, ScopeType.CLUSTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<StoragePoolVO> pools = storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags());
|
List<StoragePoolVO> pools = storagePoolDao.findPoolsByTags(dcId, podId, clusterId, dskCh.getTags(), true, VolumeApiServiceImpl.storageTagRuleExecutionTimeout.value());
|
||||||
|
pools.addAll(storagePoolJoinDao.findStoragePoolByScopeAndRuleTags(dcId, podId, clusterId, ScopeType.CLUSTER, List.of(dskCh.getTags())));
|
||||||
s_logger.debug(String.format("Found pools [%s] that match with tags [%s].", pools, Arrays.toString(dskCh.getTags())));
|
s_logger.debug(String.format("Found pools [%s] that match with tags [%s].", pools, Arrays.toString(dskCh.getTags())));
|
||||||
|
|
||||||
// add remaining pools in cluster, that did not match tags, to avoid set
|
// add remaining pools in cluster, that did not match tags, to avoid set
|
||||||
List<StoragePoolVO> allPools = storagePoolDao.findPoolsByTags(dcId, podId, clusterId, null);
|
List<StoragePoolVO> allPools = storagePoolDao.findPoolsByTags(dcId, podId, clusterId, null, false, 0);
|
||||||
allPools.removeAll(pools);
|
allPools.removeAll(pools);
|
||||||
for (StoragePoolVO pool : allPools) {
|
for (StoragePoolVO pool : allPools) {
|
||||||
s_logger.trace(String.format("Adding pool [%s] to the 'avoid' set since it did not match any tags.", pool));
|
s_logger.trace(String.format("Adding pool [%s] to the 'avoid' set since it did not match any tags.", pool));
|
||||||
|
|||||||
@ -101,7 +101,8 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<StoragePoolVO> availablePools =
|
List<StoragePoolVO> availablePools =
|
||||||
storagePoolDao.findLocalStoragePoolsByTags(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), dskCh.getTags());
|
storagePoolDao.findLocalStoragePoolsByTags(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), dskCh.getTags(), true);
|
||||||
|
availablePools.addAll(storagePoolJoinDao.findStoragePoolByScopeAndRuleTags(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), ScopeType.HOST, List.of(dskCh.getTags())));
|
||||||
for (StoragePoolVO pool : availablePools) {
|
for (StoragePoolVO pool : availablePools) {
|
||||||
if (suitablePools.size() == returnUpTo) {
|
if (suitablePools.size() == returnUpTo) {
|
||||||
break;
|
break;
|
||||||
@ -117,7 +118,7 @@ public class LocalStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add remaining pools in cluster to the 'avoid' set which did not match tags
|
// add remaining pools in cluster to the 'avoid' set which did not match tags
|
||||||
List<StoragePoolVO> allPools = storagePoolDao.findLocalStoragePoolsByTags(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), null);
|
List<StoragePoolVO> allPools = storagePoolDao.findLocalStoragePoolsByTags(plan.getDataCenterId(), plan.getPodId(), plan.getClusterId(), null, false);
|
||||||
allPools.removeAll(availablePools);
|
allPools.removeAll(availablePools);
|
||||||
for (StoragePoolVO pool : allPools) {
|
for (StoragePoolVO pool : allPools) {
|
||||||
avoid.addPool(pool.getId());
|
avoid.addPool(pool.getId());
|
||||||
|
|||||||
@ -63,9 +63,9 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<StoragePool> suitablePools = new ArrayList<>();
|
List<StoragePool> suitablePools = new ArrayList<>();
|
||||||
|
List<StoragePoolVO> storagePools = storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags(), true);
|
||||||
List<StoragePoolVO> storagePools = storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), dskCh.getTags());
|
storagePools.addAll(storagePoolJoinDao.findStoragePoolByScopeAndRuleTags(plan.getDataCenterId(), null, null, ScopeType.ZONE, List.of(dskCh.getTags())));
|
||||||
if (storagePools == null) {
|
if (storagePools.isEmpty()) {
|
||||||
LOGGER.debug(String.format("Could not find any zone wide storage pool that matched with any of the following tags [%s].", Arrays.toString(dskCh.getTags())));
|
LOGGER.debug(String.format("Could not find any zone wide storage pool that matched with any of the following tags [%s].", Arrays.toString(dskCh.getTags())));
|
||||||
storagePools = new ArrayList<>();
|
storagePools = new ArrayList<>();
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator {
|
|||||||
storagePools.addAll(anyHypervisorStoragePools);
|
storagePools.addAll(anyHypervisorStoragePools);
|
||||||
|
|
||||||
// add remaining pools in zone, that did not match tags, to avoid set
|
// add remaining pools in zone, that did not match tags, to avoid set
|
||||||
List<StoragePoolVO> allPools = storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), null);
|
List<StoragePoolVO> allPools = storagePoolDao.findZoneWideStoragePoolsByTags(plan.getDataCenterId(), null, false);
|
||||||
allPools.removeAll(storagePools);
|
allPools.removeAll(storagePools);
|
||||||
for (StoragePoolVO pool : allPools) {
|
for (StoragePoolVO pool : allPools) {
|
||||||
avoid.addPool(pool.getId());
|
avoid.addPool(pool.getId());
|
||||||
|
|||||||
@ -136,7 +136,7 @@ public class PrimaryDataStoreHelper {
|
|||||||
storageTags.add(tag);
|
storageTags.add(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataStoreVO = dataStoreDao.persist(dataStoreVO, details, storageTags);
|
dataStoreVO = dataStoreDao.persist(dataStoreVO, details, storageTags, params.isTagARule());
|
||||||
return dataStoreMgr.getDataStore(dataStoreVO.getId(), DataStoreRole.Primary);
|
return dataStoreMgr.getDataStore(dataStoreVO.getId(), DataStoreRole.Primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import java.util.List;
|
|||||||
public class Host extends GenericPresetVariable {
|
public class Host extends GenericPresetVariable {
|
||||||
private List<String> tags;
|
private List<String> tags;
|
||||||
|
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
public List<String> getTags() {
|
public List<String> getTags() {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
@ -31,4 +33,12 @@ public class Host extends GenericPresetVariable {
|
|||||||
fieldNamesToIncludeInToString.add("tags");
|
fieldNamesToIncludeInToString.add("tags");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsTagARule(Boolean isTagARule) {
|
||||||
|
this.isTagARule = isTagARule;
|
||||||
|
fieldNamesToIncludeInToString.add("isTagARule");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,9 +25,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.cloud.host.HostTagVO;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.storage.StoragePoolTagVO;
|
||||||
import org.apache.cloudstack.acl.RoleVO;
|
import org.apache.cloudstack.acl.RoleVO;
|
||||||
import org.apache.cloudstack.acl.dao.RoleDao;
|
import org.apache.cloudstack.acl.dao.RoleDao;
|
||||||
import org.apache.cloudstack.backup.BackupOfferingVO;
|
import org.apache.cloudstack.backup.BackupOfferingVO;
|
||||||
@ -351,7 +353,17 @@ public class PresetVariableHelper {
|
|||||||
Host host = new Host();
|
Host host = new Host();
|
||||||
host.setId(hostVo.getUuid());
|
host.setId(hostVo.getUuid());
|
||||||
host.setName(hostVo.getName());
|
host.setName(hostVo.getName());
|
||||||
host.setTags(hostTagsDao.getHostTags(hostId));
|
List<HostTagVO> hostTagVOList = hostTagsDao.getHostTags(hostId);
|
||||||
|
List<String> hostTags = new ArrayList<>();
|
||||||
|
boolean isTagARule = false;
|
||||||
|
if (CollectionUtils.isNotEmpty(hostTagVOList)) {
|
||||||
|
isTagARule = hostTagVOList.get(0).getIsTagARule();
|
||||||
|
if (!isTagARule) {
|
||||||
|
hostTags = hostTagVOList.parallelStream().map(HostTagVO::getTag).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host.setTags(hostTags);
|
||||||
|
host.setIsTagARule(isTagARule);
|
||||||
|
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
@ -508,7 +520,17 @@ public class PresetVariableHelper {
|
|||||||
storage.setId(storagePoolVo.getUuid());
|
storage.setId(storagePoolVo.getUuid());
|
||||||
storage.setName(storagePoolVo.getName());
|
storage.setName(storagePoolVo.getName());
|
||||||
storage.setScope(storagePoolVo.getScope());
|
storage.setScope(storagePoolVo.getScope());
|
||||||
storage.setTags(storagePoolTagsDao.getStoragePoolTags(storageId));
|
List<StoragePoolTagVO> storagePoolTagVOList = storagePoolTagsDao.findStoragePoolTags(storageId);
|
||||||
|
List<String> storageTags = new ArrayList<>();
|
||||||
|
boolean isTagARule = false;
|
||||||
|
if (CollectionUtils.isNotEmpty(storagePoolTagVOList)) {
|
||||||
|
isTagARule = storagePoolTagVOList.get(0).isTagARule();
|
||||||
|
if (!isTagARule) {
|
||||||
|
storageTags = storagePoolTagVOList.parallelStream().map(StoragePoolTagVO::getTag).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storage.setTags(storageTags);
|
||||||
|
storage.setIsTagARule(isTagARule);
|
||||||
|
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ import com.cloud.storage.ScopeType;
|
|||||||
|
|
||||||
public class Storage extends GenericPresetVariable {
|
public class Storage extends GenericPresetVariable {
|
||||||
private List<String> tags;
|
private List<String> tags;
|
||||||
|
|
||||||
|
private Boolean isTagARule;
|
||||||
private ScopeType scope;
|
private ScopeType scope;
|
||||||
|
|
||||||
public List<String> getTags() {
|
public List<String> getTags() {
|
||||||
@ -34,6 +36,15 @@ public class Storage extends GenericPresetVariable {
|
|||||||
fieldNamesToIncludeInToString.add("tags");
|
fieldNamesToIncludeInToString.add("tags");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsTagARule(Boolean isTagARule) {
|
||||||
|
this.isTagARule = isTagARule;
|
||||||
|
fieldNamesToIncludeInToString.add("isTagARule");
|
||||||
|
}
|
||||||
|
|
||||||
public ScopeType getScope() {
|
public ScopeType getScope() {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.cloud.host.HostTagVO;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.storage.StoragePoolTagVO;
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.acl.RoleVO;
|
import org.apache.cloudstack.acl.RoleVO;
|
||||||
import org.apache.cloudstack.acl.dao.RoleDao;
|
import org.apache.cloudstack.acl.dao.RoleDao;
|
||||||
@ -241,6 +243,14 @@ public class PresetVariableHelperTest {
|
|||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<HostTagVO> getHostTagsForTests() {
|
||||||
|
return Arrays.asList(new HostTagVO(1, "tag1", false), new HostTagVO(1, "tag2", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<HostTagVO> getHostRuleTagsForTests() {
|
||||||
|
return List.of(new HostTagVO(1, "tagrule", true));
|
||||||
|
}
|
||||||
|
|
||||||
private Storage getStorageForTests() {
|
private Storage getStorageForTests() {
|
||||||
Storage storage = new Storage();
|
Storage storage = new Storage();
|
||||||
storage.setId("storage_id");
|
storage.setId("storage_id");
|
||||||
@ -250,6 +260,14 @@ public class PresetVariableHelperTest {
|
|||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<StoragePoolTagVO> getStorageTagsForTests() {
|
||||||
|
return Arrays.asList(new StoragePoolTagVO(1, "tag1", false), new StoragePoolTagVO(1, "tag2", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<StoragePoolTagVO> getStorageRuleTagsForTests() {
|
||||||
|
return List.of(new StoragePoolTagVO(1, "tagrule", true));
|
||||||
|
}
|
||||||
|
|
||||||
private Set<Map.Entry<Integer, QuotaTypes>> getQuotaTypesForTests(Integer... typesToRemove) {
|
private Set<Map.Entry<Integer, QuotaTypes>> getQuotaTypesForTests(Integer... typesToRemove) {
|
||||||
Map<Integer, QuotaTypes> quotaTypesMap = new LinkedHashMap<>(QuotaTypes.listQuotaTypes());
|
Map<Integer, QuotaTypes> quotaTypesMap = new LinkedHashMap<>(QuotaTypes.listQuotaTypes());
|
||||||
|
|
||||||
@ -539,15 +557,16 @@ public class PresetVariableHelperTest {
|
|||||||
@Test
|
@Test
|
||||||
public void setPresetVariableHostInValueIfUsageTypeIsRunningVmTestQuotaTypeIsRunningVmSetHost() {
|
public void setPresetVariableHostInValueIfUsageTypeIsRunningVmTestQuotaTypeIsRunningVmSetHost() {
|
||||||
Value result = new Value();
|
Value result = new Value();
|
||||||
Host expected = getHostForTests();
|
Host expectedHost = getHostForTests();
|
||||||
|
List<HostTagVO> expectedHostTags = getHostTagsForTests();
|
||||||
|
|
||||||
Mockito.doReturn(expected).when(presetVariableHelperSpy).getPresetVariableValueHost(Mockito.anyLong());
|
Mockito.doReturn(expectedHost).when(presetVariableHelperSpy).getPresetVariableValueHost(Mockito.anyLong());
|
||||||
presetVariableHelperSpy.setPresetVariableHostInValueIfUsageTypeIsRunningVm(result, UsageTypes.RUNNING_VM, vmInstanceVoMock);
|
presetVariableHelperSpy.setPresetVariableHostInValueIfUsageTypeIsRunningVm(result, UsageTypes.RUNNING_VM, vmInstanceVoMock);
|
||||||
|
|
||||||
Assert.assertNotNull(result.getHost());
|
Assert.assertNotNull(result.getHost());
|
||||||
|
|
||||||
assertPresetVariableIdAndName(expected, result.getHost());
|
assertPresetVariableIdAndName(expectedHost, result.getHost());
|
||||||
Assert.assertEquals(expected.getTags(), result.getHost().getTags());
|
Assert.assertEquals(expectedHost.getTags(), result.getHost().getTags());
|
||||||
validateFieldNamesToIncludeInToString(Arrays.asList("host"), result);
|
validateFieldNamesToIncludeInToString(Arrays.asList("host"), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,18 +574,39 @@ public class PresetVariableHelperTest {
|
|||||||
public void getPresetVariableValueHostTestSetFieldsAndReturnObject() {
|
public void getPresetVariableValueHostTestSetFieldsAndReturnObject() {
|
||||||
Host expected = getHostForTests();
|
Host expected = getHostForTests();
|
||||||
HostVO hostVoMock = Mockito.mock(HostVO.class);
|
HostVO hostVoMock = Mockito.mock(HostVO.class);
|
||||||
|
List<HostTagVO> hostTagVOListMock = getHostTagsForTests();
|
||||||
|
|
||||||
Mockito.doReturn(hostVoMock).when(hostDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
|
Mockito.doReturn(hostVoMock).when(hostDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
|
||||||
mockMethodValidateIfObjectIsNull();
|
mockMethodValidateIfObjectIsNull();
|
||||||
Mockito.doReturn(expected.getId()).when(hostVoMock).getUuid();
|
Mockito.doReturn(expected.getId()).when(hostVoMock).getUuid();
|
||||||
Mockito.doReturn(expected.getName()).when(hostVoMock).getName();
|
Mockito.doReturn(expected.getName()).when(hostVoMock).getName();
|
||||||
Mockito.doReturn(expected.getTags()).when(hostTagsDaoMock).getHostTags(Mockito.anyLong());
|
Mockito.doReturn(hostTagVOListMock).when(hostTagsDaoMock).getHostTags(Mockito.anyLong());
|
||||||
|
|
||||||
Host result = presetVariableHelperSpy.getPresetVariableValueHost(1l);
|
Host result = presetVariableHelperSpy.getPresetVariableValueHost(1l);
|
||||||
|
|
||||||
assertPresetVariableIdAndName(expected, result);
|
assertPresetVariableIdAndName(expected, result);
|
||||||
Assert.assertEquals(expected.getTags(), result.getTags());
|
Assert.assertEquals(expected.getTags(), result.getTags());
|
||||||
validateFieldNamesToIncludeInToString(Arrays.asList("id", "name", "tags"), result);
|
validateFieldNamesToIncludeInToString(Arrays.asList("id", "isTagARule", "name", "tags"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPresetVariableValueHostTestSetFieldsWithRuleTagAndReturnObject() {
|
||||||
|
Host expected = getHostForTests();
|
||||||
|
HostVO hostVoMock = Mockito.mock(HostVO.class);
|
||||||
|
List<HostTagVO> hostTagVOListMock = getHostRuleTagsForTests();
|
||||||
|
|
||||||
|
Mockito.doReturn(hostVoMock).when(hostDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
|
||||||
|
mockMethodValidateIfObjectIsNull();
|
||||||
|
Mockito.doReturn(expected.getId()).when(hostVoMock).getUuid();
|
||||||
|
Mockito.doReturn(expected.getName()).when(hostVoMock).getName();
|
||||||
|
Mockito.doReturn(hostTagVOListMock).when(hostTagsDaoMock).getHostTags(Mockito.anyLong());
|
||||||
|
|
||||||
|
Host result = presetVariableHelperSpy.getPresetVariableValueHost(1l);
|
||||||
|
|
||||||
|
assertPresetVariableIdAndName(expected, result);
|
||||||
|
Assert.assertEquals(new ArrayList<>(), result.getTags());
|
||||||
|
Assert.assertTrue(result.getIsTagARule());
|
||||||
|
validateFieldNamesToIncludeInToString(Arrays.asList("id", "isTagARule", "name", "tags"), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -755,13 +795,15 @@ public class PresetVariableHelperTest {
|
|||||||
Storage expected = getStorageForTests();
|
Storage expected = getStorageForTests();
|
||||||
Mockito.doReturn(null).when(presetVariableHelperSpy).getSecondaryStorageForSnapshot(Mockito.anyLong(), Mockito.anyInt());
|
Mockito.doReturn(null).when(presetVariableHelperSpy).getSecondaryStorageForSnapshot(Mockito.anyLong(), Mockito.anyInt());
|
||||||
|
|
||||||
|
List<StoragePoolTagVO> storageTagVOListMock = getStorageTagsForTests();
|
||||||
|
|
||||||
StoragePoolVO storagePoolVoMock = Mockito.mock(StoragePoolVO.class);
|
StoragePoolVO storagePoolVoMock = Mockito.mock(StoragePoolVO.class);
|
||||||
Mockito.doReturn(storagePoolVoMock).when(primaryStorageDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
|
Mockito.doReturn(storagePoolVoMock).when(primaryStorageDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
|
||||||
|
|
||||||
Mockito.doReturn(expected.getId()).when(storagePoolVoMock).getUuid();
|
Mockito.doReturn(expected.getId()).when(storagePoolVoMock).getUuid();
|
||||||
Mockito.doReturn(expected.getName()).when(storagePoolVoMock).getName();
|
Mockito.doReturn(expected.getName()).when(storagePoolVoMock).getName();
|
||||||
Mockito.doReturn(expected.getScope()).when(storagePoolVoMock).getScope();
|
Mockito.doReturn(expected.getScope()).when(storagePoolVoMock).getScope();
|
||||||
Mockito.doReturn(expected.getTags()).when(storagePoolTagsDaoMock).getStoragePoolTags(Mockito.anyLong());
|
Mockito.doReturn(storageTagVOListMock).when(storagePoolTagsDaoMock).findStoragePoolTags(Mockito.anyLong());
|
||||||
|
|
||||||
Storage result = presetVariableHelperSpy.getPresetVariableValueStorage(1l, 2);
|
Storage result = presetVariableHelperSpy.getPresetVariableValueStorage(1l, 2);
|
||||||
|
|
||||||
@ -769,7 +811,32 @@ public class PresetVariableHelperTest {
|
|||||||
Assert.assertEquals(expected.getScope(), result.getScope());
|
Assert.assertEquals(expected.getScope(), result.getScope());
|
||||||
Assert.assertEquals(expected.getTags(), result.getTags());
|
Assert.assertEquals(expected.getTags(), result.getTags());
|
||||||
|
|
||||||
validateFieldNamesToIncludeInToString(Arrays.asList("id", "name", "scope", "tags"), result);
|
validateFieldNamesToIncludeInToString(Arrays.asList("id", "isTagARule", "name", "scope", "tags"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPresetVariableValueStorageTestGetSecondaryStorageForSnapshotReturnsNullWithRuleTag() {
|
||||||
|
Storage expected = getStorageForTests();
|
||||||
|
Mockito.doReturn(null).when(presetVariableHelperSpy).getSecondaryStorageForSnapshot(Mockito.anyLong(), Mockito.anyInt());
|
||||||
|
|
||||||
|
List<StoragePoolTagVO> storageTagVOListMock = getStorageRuleTagsForTests();
|
||||||
|
|
||||||
|
StoragePoolVO storagePoolVoMock = Mockito.mock(StoragePoolVO.class);
|
||||||
|
Mockito.doReturn(storagePoolVoMock).when(primaryStorageDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
|
||||||
|
|
||||||
|
Mockito.doReturn(expected.getId()).when(storagePoolVoMock).getUuid();
|
||||||
|
Mockito.doReturn(expected.getName()).when(storagePoolVoMock).getName();
|
||||||
|
Mockito.doReturn(expected.getScope()).when(storagePoolVoMock).getScope();
|
||||||
|
Mockito.doReturn(storageTagVOListMock).when(storagePoolTagsDaoMock).findStoragePoolTags(Mockito.anyLong());
|
||||||
|
|
||||||
|
Storage result = presetVariableHelperSpy.getPresetVariableValueStorage(1l, 2);
|
||||||
|
|
||||||
|
assertPresetVariableIdAndName(expected, result);
|
||||||
|
Assert.assertEquals(expected.getScope(), result.getScope());
|
||||||
|
Assert.assertEquals(new ArrayList<>(), result.getTags());
|
||||||
|
Assert.assertTrue(result.getIsTagARule());
|
||||||
|
|
||||||
|
validateFieldNamesToIncludeInToString(Arrays.asList("id", "isTagARule", "name", "scope", "tags"), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -22,7 +22,9 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.ListUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
|
|||||||
}
|
}
|
||||||
String hostTag = offering.getHostTag();
|
String hostTag = offering.getHostTag();
|
||||||
if (hostTag != null) {
|
if (hostTag != null) {
|
||||||
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId + " having host tag:" + hostTag);
|
s_logger.debug(String.format("Looking for hosts in dc [%s], pod [%s], cluster [%s] and complying with host tag [%s].", dcId, podId, clusterId, hostTag));
|
||||||
} else {
|
} else {
|
||||||
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
|
s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
|
||||||
}
|
}
|
||||||
@ -82,7 +84,7 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
|
|||||||
if (hostTag != null) {
|
if (hostTag != null) {
|
||||||
hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
|
hostsCopy.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
|
||||||
} else {
|
} else {
|
||||||
hostsCopy.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId));
|
hostsCopy.retainAll(_hostDao.listAllHostsThatHaveNoRuleTag(type, clusterId, podId, dcId));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// list all computing hosts, regardless of whether they support routing...it's random after all
|
// list all computing hosts, regardless of whether they support routing...it's random after all
|
||||||
@ -90,9 +92,16 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
|
|||||||
if (hostTag != null) {
|
if (hostTag != null) {
|
||||||
hostsCopy = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag);
|
hostsCopy = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag);
|
||||||
} else {
|
} else {
|
||||||
hostsCopy = _resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId);
|
hostsCopy = _hostDao.listAllHostsThatHaveNoRuleTag(type, clusterId, podId, dcId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hostsCopy = ListUtils.union(hostsCopy, _hostDao.findHostsWithTagRuleThatMatchComputeOferringTags(hostTag));
|
||||||
|
|
||||||
|
if (hostsCopy.isEmpty()) {
|
||||||
|
s_logger.error(String.format("No suitable host found for vm [%s] with tags [%s].", vmProfile, hostTag));
|
||||||
|
throw new CloudRuntimeException(String.format("No suitable host found for vm [%s].", vmProfile));
|
||||||
|
}
|
||||||
|
|
||||||
s_logger.debug("Random Allocator found " + hostsCopy.size() + " hosts");
|
s_logger.debug("Random Allocator found " + hostsCopy.size() + " hosts");
|
||||||
if (hostsCopy.size() == 0) {
|
if (hostsCopy.size() == 0) {
|
||||||
return suitableHosts;
|
return suitableHosts;
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import com.cloud.configuration.dao.ResourceCountDao;
|
|||||||
import com.cloud.dc.DedicatedResourceVO;
|
import com.cloud.dc.DedicatedResourceVO;
|
||||||
import com.cloud.dc.dao.DedicatedResourceDao;
|
import com.cloud.dc.dao.DedicatedResourceDao;
|
||||||
import com.cloud.host.HostStats;
|
import com.cloud.host.HostStats;
|
||||||
|
import com.cloud.host.HostTagVO;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
|
||||||
@ -234,7 +235,9 @@ public class PrometheusExporterImpl extends ManagerBase implements PrometheusExp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String markTagMaps(HostVO host, Map<String, Integer> totalHosts, Map<String, Integer> upHosts, Map<String, Integer> downHosts) {
|
private String markTagMaps(HostVO host, Map<String, Integer> totalHosts, Map<String, Integer> upHosts, Map<String, Integer> downHosts) {
|
||||||
List<String> hostTags = _hostTagsDao.getHostTags(host.getId());
|
List<HostTagVO> hostTagVOS = _hostTagsDao.getHostTags(host.getId());
|
||||||
|
List<String> hostTags = new ArrayList<>();
|
||||||
|
hostTagVOS.forEach(hostTagVO -> hostTags.add(hostTagVO.getTag()));
|
||||||
markTags(hostTags,totalHosts);
|
markTags(hostTags,totalHosts);
|
||||||
if (host.getStatus() == Status.Up && !host.isInMaintenanceStates()) {
|
if (host.getStatus() == Status.Up && !host.isInMaintenanceStates()) {
|
||||||
markTags(hostTags, upHosts);
|
markTags(hostTags, upHosts);
|
||||||
@ -277,10 +280,12 @@ public class PrometheusExporterImpl extends ManagerBase implements PrometheusExp
|
|||||||
metricsList.add(new ItemHostMemory(zoneName, zoneUuid, null, null, null, null, ALLOCATED, allocatedCapacityByTag.third(), 0, tag));
|
metricsList.add(new ItemHostMemory(zoneName, zoneUuid, null, null, null, null, ALLOCATED, allocatedCapacityByTag.third(), 0, tag));
|
||||||
});
|
});
|
||||||
|
|
||||||
List<String> allHostTags = hostDao.listAll().stream()
|
List<HostTagVO> allHostTagVOS = hostDao.listAll().stream()
|
||||||
.flatMap( h -> _hostTagsDao.getHostTags(h.getId()).stream())
|
.flatMap( h -> _hostTagsDao.getHostTags(h.getId()).stream())
|
||||||
.distinct()
|
.distinct()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
List<String> allHostTags = new ArrayList<>();
|
||||||
|
allHostTagVOS.forEach(hostTagVO -> allHostTags.add(hostTagVO.getTag()));
|
||||||
|
|
||||||
for (final State state : State.values()) {
|
for (final State state : State.values()) {
|
||||||
for (final String hostTag : allHostTags) {
|
for (final String hostTag : allHostTags) {
|
||||||
|
|||||||
@ -107,6 +107,7 @@ public class ElastistorPrimaryDataStoreLifeCycle implements PrimaryDataStoreLife
|
|||||||
Long capacityBytes = (Long) dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long) dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long) dsInfos.get("capacityIops");
|
Long capacityIops = (Long) dsInfos.get("capacityIops");
|
||||||
String tags = (String) dsInfos.get("tags");
|
String tags = (String) dsInfos.get("tags");
|
||||||
|
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
|
||||||
boolean managed = (Boolean) dsInfos.get("managed");
|
boolean managed = (Boolean) dsInfos.get("managed");
|
||||||
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
||||||
String domainName = details.get("domainname");
|
String domainName = details.get("domainname");
|
||||||
@ -196,6 +197,7 @@ public class ElastistorPrimaryDataStoreLifeCycle implements PrimaryDataStoreLife
|
|||||||
parameters.setCapacityIops(capacityIops);
|
parameters.setCapacityIops(capacityIops);
|
||||||
parameters.setHypervisorType(HypervisorType.Any);
|
parameters.setHypervisorType(HypervisorType.Any);
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
parameters.setClusterId(clusterId);
|
parameters.setClusterId(clusterId);
|
||||||
|
|
||||||
|
|||||||
@ -100,6 +100,7 @@ public class DateraPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycl
|
|||||||
Long capacityBytes = (Long) dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long) dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long) dsInfos.get("capacityIops");
|
Long capacityIops = (Long) dsInfos.get("capacityIops");
|
||||||
String tags = (String) dsInfos.get("tags");
|
String tags = (String) dsInfos.get("tags");
|
||||||
|
boolean isTagARule = (Boolean)dsInfos.get("isTagARule");
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
||||||
String domainName = details.get("domainname");
|
String domainName = details.get("domainname");
|
||||||
@ -181,6 +182,7 @@ public class DateraPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycl
|
|||||||
parameters.setCapacityIops(capacityIops);
|
parameters.setCapacityIops(capacityIops);
|
||||||
parameters.setHypervisorType(HypervisorType.Any);
|
parameters.setHypervisorType(HypervisorType.Any);
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
|
|
||||||
String managementVip = DateraUtil.getManagementVip(url);
|
String managementVip = DateraUtil.getManagementVip(url);
|
||||||
|
|||||||
@ -138,6 +138,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
|
|||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
|
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule((Boolean)dsInfos.get("isTagARule"));
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
|
|
||||||
String scheme = dsInfos.get("scheme").toString();
|
String scheme = dsInfos.get("scheme").toString();
|
||||||
|
|||||||
@ -91,6 +91,7 @@ public class LinstorPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif
|
|||||||
String providerName = (String) dsInfos.get("providerName");
|
String providerName = (String) dsInfos.get("providerName");
|
||||||
Long capacityIops = (Long) dsInfos.get("capacityIops");
|
Long capacityIops = (Long) dsInfos.get("capacityIops");
|
||||||
String tags = (String) dsInfos.get("tags");
|
String tags = (String) dsInfos.get("tags");
|
||||||
|
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
||||||
|
|
||||||
@ -168,6 +169,7 @@ public class LinstorPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif
|
|||||||
parameters.setCapacityIops(capacityIops);
|
parameters.setCapacityIops(capacityIops);
|
||||||
parameters.setHypervisorType(HypervisorType.KVM);
|
parameters.setHypervisorType(HypervisorType.KVM);
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
parameters.setUserInfo(resourceGroup);
|
parameters.setUserInfo(resourceGroup);
|
||||||
|
|
||||||
|
|||||||
@ -69,6 +69,7 @@ public class NexentaPrimaryDataStoreLifeCycle
|
|||||||
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
||||||
String tags = (String)dsInfos.get("tags");
|
String tags = (String)dsInfos.get("tags");
|
||||||
|
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
|
||||||
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
||||||
NexentaUtil.NexentaPluginParameters params = NexentaUtil.parseNexentaPluginUrl(url);
|
NexentaUtil.NexentaPluginParameters params = NexentaUtil.parseNexentaPluginUrl(url);
|
||||||
DataCenterVO zone = zoneDao.findById(zoneId);
|
DataCenterVO zone = zoneDao.findById(zoneId);
|
||||||
@ -98,6 +99,7 @@ public class NexentaPrimaryDataStoreLifeCycle
|
|||||||
parameters.setCapacityIops(capacityIops);
|
parameters.setCapacityIops(capacityIops);
|
||||||
parameters.setHypervisorType(Hypervisor.HypervisorType.Any);
|
parameters.setHypervisorType(Hypervisor.HypervisorType.Any);
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
|
|
||||||
details.put(NexentaUtil.NMS_URL, params.getNmsUrl().toString());
|
details.put(NexentaUtil.NMS_URL, params.getNmsUrl().toString());
|
||||||
|
|
||||||
|
|||||||
@ -139,6 +139,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCyc
|
|||||||
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
||||||
String tags = (String)dsInfos.get("tags");
|
String tags = (String)dsInfos.get("tags");
|
||||||
|
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
|
||||||
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
|
||||||
|
|
||||||
if (zoneId == null) {
|
if (zoneId == null) {
|
||||||
@ -224,6 +225,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCyc
|
|||||||
parameters.setHypervisorType(Hypervisor.HypervisorType.KVM);
|
parameters.setHypervisorType(Hypervisor.HypervisorType.KVM);
|
||||||
parameters.setUuid(UUID.randomUUID().toString());
|
parameters.setUuid(UUID.randomUUID().toString());
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
|
|
||||||
StoragePoolStatistics poolStatistics = scaleIOPool.getStatistics();
|
StoragePoolStatistics poolStatistics = scaleIOPool.getStatistics();
|
||||||
if (poolStatistics != null) {
|
if (poolStatistics != null) {
|
||||||
|
|||||||
@ -91,6 +91,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
Long capacityIops = (Long)dsInfos.get("capacityIops");
|
||||||
String tags = (String)dsInfos.get("tags");
|
String tags = (String)dsInfos.get("tags");
|
||||||
|
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
|
|
||||||
@ -142,6 +143,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
|
|
||||||
String managementVip = SolidFireUtil.getManagementVip(url);
|
String managementVip = SolidFireUtil.getManagementVip(url);
|
||||||
|
|||||||
@ -104,6 +104,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
|
|||||||
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
Long capacityBytes = (Long)dsInfos.get("capacityBytes");
|
||||||
Long capacityIops = (Long)dsInfos.get(CAPACITY_IOPS);
|
Long capacityIops = (Long)dsInfos.get(CAPACITY_IOPS);
|
||||||
String tags = (String)dsInfos.get("tags");
|
String tags = (String)dsInfos.get("tags");
|
||||||
|
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
|
|
||||||
@ -152,6 +153,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor
|
|||||||
parameters.setCapacityIops(capacityIops);
|
parameters.setCapacityIops(capacityIops);
|
||||||
parameters.setHypervisorType(hypervisorType);
|
parameters.setHypervisorType(hypervisorType);
|
||||||
parameters.setTags(tags);
|
parameters.setTags(tags);
|
||||||
|
parameters.setIsTagARule(isTagARule);
|
||||||
parameters.setDetails(details);
|
parameters.setDetails(details);
|
||||||
|
|
||||||
String managementVip = SolidFireUtil.getManagementVip(url);
|
String managementVip = SolidFireUtil.getManagementVip(url);
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import java.util.Map;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -182,7 +183,6 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
|
|||||||
|
|
||||||
if (hasSvcOfferingTag && hasTemplateTag) {
|
if (hasSvcOfferingTag && hasTemplateTag) {
|
||||||
hostsMatchingOfferingTag.retainAll(hostsMatchingTemplateTag);
|
hostsMatchingOfferingTag.retainAll(hostsMatchingTemplateTag);
|
||||||
clusterHosts = _hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate);
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Found " + hostsMatchingOfferingTag.size() + " Hosts satisfying both tags, host ids are:" + hostsMatchingOfferingTag);
|
s_logger.debug("Found " + hostsMatchingOfferingTag.size() + " Hosts satisfying both tags, host ids are:" + hostsMatchingOfferingTag);
|
||||||
}
|
}
|
||||||
@ -202,6 +202,13 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
|
|||||||
clusterHosts.retainAll(hostsMatchingUefiTag);
|
clusterHosts.retainAll(hostsMatchingUefiTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clusterHosts.addAll(_hostDao.findHostsWithTagRuleThatMatchComputeOferringTags(hostTagOnOffering));
|
||||||
|
|
||||||
|
|
||||||
|
if (clusterHosts.isEmpty()) {
|
||||||
|
s_logger.error(String.format("No suitable host found for vm [%s] with tags [%s].", vmProfile, hostTagOnOffering));
|
||||||
|
throw new CloudRuntimeException(String.format("No suitable host found for vm [%s].", vmProfile));
|
||||||
|
}
|
||||||
// add all hosts that we are not considering to the avoid list
|
// add all hosts that we are not considering to the avoid list
|
||||||
List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
|
List<HostVO> allhostsInCluster = _hostDao.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId, null);
|
||||||
allhostsInCluster.removeAll(clusterHosts);
|
allhostsInCluster.removeAll(clusterHosts);
|
||||||
@ -267,6 +274,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostsCopy.addAll(_hostDao.findHostsWithTagRuleThatMatchComputeOferringTags(hostTagOnOffering));
|
||||||
|
|
||||||
if (!hostsCopy.isEmpty()) {
|
if (!hostsCopy.isEmpty()) {
|
||||||
suitableHosts = allocateTo(plan, offering, template, avoid, hostsCopy, returnUpTo, considerReservedCapacity, account);
|
suitableHosts = allocateTo(plan, offering, template, avoid, hostsCopy, returnUpTo, considerReservedCapacity, account);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -205,6 +205,7 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
|
|||||||
|
|
||||||
String hostTags = host.getTag();
|
String hostTags = host.getTag();
|
||||||
hostResponse.setHostTags(hostTags);
|
hostResponse.setHostTags(hostTags);
|
||||||
|
hostResponse.setIsTagARule(host.getIsTagARule());
|
||||||
hostResponse.setHaHost(containsHostHATag(hostTags));
|
hostResponse.setHaHost(containsHostHATag(hostTags));
|
||||||
|
|
||||||
hostResponse.setHypervisorVersion(host.getHypervisorVersion());
|
hostResponse.setHypervisorVersion(host.getHypervisorVersion());
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import org.apache.cloudstack.api.response.StoragePoolResponse;
|
|||||||
import com.cloud.api.query.vo.StoragePoolJoinVO;
|
import com.cloud.api.query.vo.StoragePoolJoinVO;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
|
||||||
public interface StoragePoolJoinDao extends GenericDao<StoragePoolJoinVO, Long> {
|
public interface StoragePoolJoinDao extends GenericDao<StoragePoolJoinVO, Long> {
|
||||||
|
|
||||||
@ -44,4 +45,6 @@ public interface StoragePoolJoinDao extends GenericDao<StoragePoolJoinVO, Long>
|
|||||||
|
|
||||||
Pair<List<StoragePoolJoinVO>, Integer> searchAndCount(Long storagePoolId, String storagePoolName, Long zoneId, String path, Long podId, Long clusterId, String address, ScopeType scopeType, StoragePoolStatus status, String keyword, Filter searchFilter);
|
Pair<List<StoragePoolJoinVO>, Integer> searchAndCount(Long storagePoolId, String storagePoolName, Long zoneId, String path, Long podId, Long clusterId, String address, ScopeType scopeType, StoragePoolStatus status, String keyword, Filter searchFilter);
|
||||||
|
|
||||||
|
List<StoragePoolVO> findStoragePoolByScopeAndRuleTags(Long datacenterId, Long podId, Long clusterId, ScopeType scopeType, List<String> tags);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import com.cloud.storage.Storage;
|
|||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.StoragePoolStatus;
|
import com.cloud.storage.StoragePoolStatus;
|
||||||
import com.cloud.storage.StorageStats;
|
import com.cloud.storage.StorageStats;
|
||||||
|
import com.cloud.storage.VolumeApiServiceImpl;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.StringUtils;
|
import com.cloud.utils.StringUtils;
|
||||||
@ -44,6 +45,7 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
|||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -71,10 +73,13 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
|||||||
@Inject
|
@Inject
|
||||||
private StoragePoolDetailsDao storagePoolDetailsDao;
|
private StoragePoolDetailsDao storagePoolDetailsDao;
|
||||||
|
|
||||||
|
|
||||||
private final SearchBuilder<StoragePoolJoinVO> spSearch;
|
private final SearchBuilder<StoragePoolJoinVO> spSearch;
|
||||||
|
|
||||||
private final SearchBuilder<StoragePoolJoinVO> spIdSearch;
|
private final SearchBuilder<StoragePoolJoinVO> spIdSearch;
|
||||||
|
|
||||||
|
private final SearchBuilder<StoragePoolJoinVO> findByDatacenterAndScopeSb;
|
||||||
|
|
||||||
protected StoragePoolJoinDaoImpl() {
|
protected StoragePoolJoinDaoImpl() {
|
||||||
|
|
||||||
spSearch = createSearchBuilder();
|
spSearch = createSearchBuilder();
|
||||||
@ -85,6 +90,15 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
|||||||
spIdSearch.and("id", spIdSearch.entity().getId(), SearchCriteria.Op.EQ);
|
spIdSearch.and("id", spIdSearch.entity().getId(), SearchCriteria.Op.EQ);
|
||||||
spIdSearch.done();
|
spIdSearch.done();
|
||||||
|
|
||||||
|
findByDatacenterAndScopeSb = createSearchBuilder();
|
||||||
|
findByDatacenterAndScopeSb.and("zoneId", findByDatacenterAndScopeSb.entity().getZoneId(), SearchCriteria.Op.EQ);
|
||||||
|
findByDatacenterAndScopeSb.and("clusterId", findByDatacenterAndScopeSb.entity().getClusterId(), SearchCriteria.Op.EQ);
|
||||||
|
findByDatacenterAndScopeSb.and("podId", findByDatacenterAndScopeSb.entity().getPodId(), SearchCriteria.Op.EQ);
|
||||||
|
findByDatacenterAndScopeSb.and("scope", findByDatacenterAndScopeSb.entity().getScope(), SearchCriteria.Op.EQ);
|
||||||
|
findByDatacenterAndScopeSb.and("status", findByDatacenterAndScopeSb.entity().getStatus(), SearchCriteria.Op.EQ);
|
||||||
|
findByDatacenterAndScopeSb.and("is_tag_a_rule", findByDatacenterAndScopeSb.entity().getIsTagARule(), SearchCriteria.Op.EQ);
|
||||||
|
findByDatacenterAndScopeSb.done();
|
||||||
|
|
||||||
_count = "select count(distinct id) from storage_pool_view WHERE ";
|
_count = "select count(distinct id) from storage_pool_view WHERE ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +163,7 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
|||||||
poolResponse.setClusterName(pool.getClusterName());
|
poolResponse.setClusterName(pool.getClusterName());
|
||||||
poolResponse.setProvider(pool.getStorageProviderName());
|
poolResponse.setProvider(pool.getStorageProviderName());
|
||||||
poolResponse.setTags(pool.getTag());
|
poolResponse.setTags(pool.getTag());
|
||||||
|
poolResponse.setIsTagARule(pool.getIsTagARule());
|
||||||
poolResponse.setOverProvisionFactor(Double.toString(CapacityManager.StorageOverprovisioningFactor.valueIn(pool.getId())));
|
poolResponse.setOverProvisionFactor(Double.toString(CapacityManager.StorageOverprovisioningFactor.valueIn(pool.getId())));
|
||||||
|
|
||||||
// set async job
|
// set async job
|
||||||
@ -221,6 +236,7 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
|||||||
poolResponse.setClusterName(pool.getClusterName());
|
poolResponse.setClusterName(pool.getClusterName());
|
||||||
poolResponse.setProvider(pool.getStorageProviderName());
|
poolResponse.setProvider(pool.getStorageProviderName());
|
||||||
poolResponse.setTags(pool.getTag());
|
poolResponse.setTags(pool.getTag());
|
||||||
|
poolResponse.setIsTagARule(pool.getIsTagARule());
|
||||||
|
|
||||||
// set async job
|
// set async job
|
||||||
poolResponse.setJobId(pool.getJobUuid());
|
poolResponse.setJobId(pool.getJobUuid());
|
||||||
@ -366,4 +382,46 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
|
|||||||
sc.setParameters("parent", 0);
|
sc.setParameters("parent", 0);
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public List<StoragePoolVO> findStoragePoolByScopeAndRuleTags(Long datacenterId, Long podId, Long clusterId, ScopeType scopeType, List<String> tags) {
|
||||||
|
SearchCriteria<StoragePoolJoinVO> sc = findByDatacenterAndScopeSb.create();
|
||||||
|
if (datacenterId != null) {
|
||||||
|
sc.setParameters("zoneId", datacenterId);
|
||||||
|
}
|
||||||
|
if (clusterId != null) {
|
||||||
|
sc.setParameters("clusterId", clusterId);
|
||||||
|
}
|
||||||
|
if (podId != null) {
|
||||||
|
sc.setParameters("podId", podId);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.setParameters("scope", scopeType);
|
||||||
|
sc.setParameters("status", "Up");
|
||||||
|
sc.setParameters("is_tag_a_rule", true);
|
||||||
|
List<StoragePoolJoinVO> storagePools = search(sc, null, false, false);
|
||||||
|
|
||||||
|
List<StoragePoolVO> filteredPools = new ArrayList<>();
|
||||||
|
|
||||||
|
StringBuilder injectableTagsBuilder = new StringBuilder();
|
||||||
|
for (String tag : tags) {
|
||||||
|
injectableTagsBuilder.append(tag).append(",");
|
||||||
|
}
|
||||||
|
if (!tags.isEmpty()) {
|
||||||
|
injectableTagsBuilder.deleteCharAt(injectableTagsBuilder.length() - 1);
|
||||||
|
}
|
||||||
|
String injectableTag = injectableTagsBuilder.toString();
|
||||||
|
|
||||||
|
for (StoragePoolJoinVO storagePoolJoinVO : storagePools) {
|
||||||
|
if (TagAsRuleHelper.interpretTagAsRule(storagePoolJoinVO.getTag(), injectableTag, VolumeApiServiceImpl.storageTagRuleExecutionTimeout.value())) {
|
||||||
|
StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolJoinVO.getId());
|
||||||
|
if (storagePoolVO != null) {
|
||||||
|
filteredPools.add(storagePoolVO);
|
||||||
|
} else {
|
||||||
|
s_logger.warn(String.format("Unable to find Storage Pool [%s] in the DB.", storagePoolJoinVO.getUuid()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredPools;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -172,6 +172,9 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
|
|||||||
@Column(name = "tag")
|
@Column(name = "tag")
|
||||||
private String tag;
|
private String tag;
|
||||||
|
|
||||||
|
@Column(name = "is_tag_a_rule")
|
||||||
|
private Boolean isTagARule;
|
||||||
|
|
||||||
@Column(name = "memory_used_capacity")
|
@Column(name = "memory_used_capacity")
|
||||||
private long memUsedCapacity;
|
private long memUsedCapacity;
|
||||||
|
|
||||||
@ -388,6 +391,10 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
public String getAnnotation() {
|
public String getAnnotation() {
|
||||||
return annotation;
|
return annotation;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,6 +110,9 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
|||||||
@Column(name = "tag")
|
@Column(name = "tag")
|
||||||
private String tag;
|
private String tag;
|
||||||
|
|
||||||
|
@Column(name = "is_tag_a_rule")
|
||||||
|
private boolean isTagARule;
|
||||||
|
|
||||||
@Column(name = "disk_used_capacity")
|
@Column(name = "disk_used_capacity")
|
||||||
private long usedCapacity;
|
private long usedCapacity;
|
||||||
|
|
||||||
@ -243,6 +246,10 @@ public class StoragePoolJoinVO extends BaseViewVO implements InternalIdentity, I
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getIsTagARule() {
|
||||||
|
return isTagARule;
|
||||||
|
}
|
||||||
|
|
||||||
public long getUsedCapacity() {
|
public long getUsedCapacity() {
|
||||||
return usedCapacity;
|
return usedCapacity;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,10 @@ import javax.naming.ConfigurationException;
|
|||||||
|
|
||||||
import com.cloud.hypervisor.HypervisorGuru;
|
import com.cloud.hypervisor.HypervisorGuru;
|
||||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||||
|
import com.cloud.host.HostTagVO;
|
||||||
|
import com.cloud.storage.StoragePoolTagVO;
|
||||||
|
import com.cloud.storage.VolumeApiServiceImpl;
|
||||||
|
import com.googlecode.ipv6.IPv6Address;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker;
|
import org.apache.cloudstack.acl.SecurityChecker;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroup;
|
import org.apache.cloudstack.affinity.AffinityGroup;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupService;
|
import org.apache.cloudstack.affinity.AffinityGroupService;
|
||||||
@ -128,6 +132,7 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
|||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
@ -293,7 +298,6 @@ import com.google.common.base.Enums;
|
|||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.googlecode.ipv6.IPv6Address;
|
|
||||||
import com.googlecode.ipv6.IPv6Network;
|
import com.googlecode.ipv6.IPv6Network;
|
||||||
|
|
||||||
public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
|
public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
|
||||||
@ -4080,17 +4084,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
if (CollectionUtils.isNotEmpty(pools)) {
|
if (CollectionUtils.isNotEmpty(pools)) {
|
||||||
List<String> listOfTags = Arrays.asList(tags.split(","));
|
List<String> listOfTags = Arrays.asList(tags.split(","));
|
||||||
for (StoragePoolVO storagePoolVO : pools) {
|
for (StoragePoolVO storagePoolVO : pools) {
|
||||||
List<String> tagsOnPool = storagePoolTagDao.getStoragePoolTags(storagePoolVO.getId());
|
List<StoragePoolTagVO> tagsOnPool = storagePoolTagDao.findStoragePoolTags(storagePoolVO.getId());
|
||||||
if (CollectionUtils.isEmpty(tagsOnPool) || !tagsOnPool.containsAll(listOfTags)) {
|
List<String> tagsAsString = tagsOnPool.stream().map(StoragePoolTagVO::getTag).collect(Collectors.toList());
|
||||||
DiskOfferingVO offeringToRetrieveInfo = _diskOfferingDao.findById(diskOffering.getId());
|
|
||||||
List<VolumeVO> volumes = _volumeDao.findByDiskOfferingId(diskOffering.getId());
|
if ((CollectionUtils.isNotEmpty(tagsAsString) && tagsAsString.containsAll(listOfTags)) ||
|
||||||
String listOfVolumesNamesAndUuid = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(volumes, "name", "uuid");
|
(tagsOnPool.size() == 1 && tagsOnPool.get(0).isTagARule() &&
|
||||||
String diskOfferingInfo = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(offeringToRetrieveInfo, "name", "uuid");
|
TagAsRuleHelper.interpretTagAsRule(tagsOnPool.get(0).getTag(), tags, VolumeApiServiceImpl.storageTagRuleExecutionTimeout.value()))) {
|
||||||
String poolInfo = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(storagePoolVO, "name", "uuid");
|
continue;
|
||||||
throw new InvalidParameterValueException(String.format("There are active volumes using the disk offering %s, and the pool %s doesn't have the new tags. " +
|
|
||||||
"The following volumes are using the mentioned disk offering %s. Please first add the new tags to the mentioned storage pools before adding them" +
|
|
||||||
" to the disk offering.", diskOfferingInfo, poolInfo, listOfVolumesNamesAndUuid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiskOfferingVO offeringToRetrieveInfo = _diskOfferingDao.findById(diskOffering.getId());
|
||||||
|
List<VolumeVO> volumes = _volumeDao.findByDiskOfferingId(diskOffering.getId());
|
||||||
|
String listOfVolumesNamesAndUuid = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(volumes, "name", "uuid");
|
||||||
|
String diskOfferingInfo = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(offeringToRetrieveInfo, "name", "uuid");
|
||||||
|
String poolInfo = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(storagePoolVO, "name", "uuid");
|
||||||
|
throw new InvalidParameterValueException(String.format("There are active volumes using the disk offering %s, and the pool %s doesn't have the new tags. " +
|
||||||
|
"The following volumes are using the mentioned disk offering %s. Please first add the new tags to the mentioned storage pools before adding them" +
|
||||||
|
" to the disk offering.", diskOfferingInfo, poolInfo, listOfVolumesNamesAndUuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
diskOffering.setTags(tags);
|
diskOffering.setTags(tags);
|
||||||
@ -4117,10 +4127,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
if (CollectionUtils.isNotEmpty(hosts)) {
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
List<String> listOfHostTags = Arrays.asList(hostTags.split(","));
|
List<String> listOfHostTags = Arrays.asList(hostTags.split(","));
|
||||||
for (HostVO host : hosts) {
|
for (HostVO host : hosts) {
|
||||||
List<String> tagsOnHost = hostTagDao.getHostTags(host.getId());
|
List<HostTagVO> tagsOnHost = hostTagDao.getHostTags(host.getId());
|
||||||
if (CollectionUtils.isEmpty(tagsOnHost) || !tagsOnHost.containsAll(listOfHostTags)) {
|
List<String> tagsAsString = tagsOnHost.stream().map(HostTagVO::getTag).collect(Collectors.toList());
|
||||||
throw new InvalidParameterValueException(String.format("There are active VMs using offering [%s], and the hosts [%s] don't have the new tags", offering.getId(), hosts));
|
|
||||||
|
if ((CollectionUtils.isNotEmpty(tagsAsString) && tagsAsString.containsAll(listOfHostTags)) ||
|
||||||
|
(tagsOnHost.size() == 1 && tagsOnHost.get(0).getIsTagARule() &&
|
||||||
|
TagAsRuleHelper.interpretTagAsRule(tagsOnHost.get(0).getTag(), hostTags, HostTagsDao.hostTagRuleExecutionTimeout.value()))) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new InvalidParameterValueException(String.format("There are active VMs using offering [%s], and the hosts [%s] don't have the new tags",
|
||||||
|
offering.getId(), hosts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offering.setHostTag(hostTags);
|
offering.setHostTag(hostTags);
|
||||||
|
|||||||
@ -1361,7 +1361,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
|
|
||||||
if (vmRequiresSharedStorage) {
|
if (vmRequiresSharedStorage) {
|
||||||
// check shared pools
|
// check shared pools
|
||||||
List<StoragePoolVO> allPoolsInCluster = _storagePoolDao.findPoolsByTags(clusterVO.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null);
|
List<StoragePoolVO> allPoolsInCluster = _storagePoolDao.findPoolsByTags(clusterVO.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null, false, 0);
|
||||||
for (StoragePoolVO pool : allPoolsInCluster) {
|
for (StoragePoolVO pool : allPoolsInCluster) {
|
||||||
if (!allocatorAvoidOutput.shouldAvoid(pool)) {
|
if (!allocatorAvoidOutput.shouldAvoid(pool)) {
|
||||||
// there's some pool in the cluster that is not yet in avoid set
|
// there's some pool in the cluster that is not yet in avoid set
|
||||||
@ -1374,7 +1374,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||||||
if (vmRequiresLocalStorege) {
|
if (vmRequiresLocalStorege) {
|
||||||
// check local pools
|
// check local pools
|
||||||
List<StoragePoolVO> allLocalPoolsInCluster =
|
List<StoragePoolVO> allLocalPoolsInCluster =
|
||||||
_storagePoolDao.findLocalStoragePoolsByTags(clusterVO.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null);
|
_storagePoolDao.findLocalStoragePoolsByTags(clusterVO.getDataCenterId(), clusterVO.getPodId(), clusterVO.getId(), null, false);
|
||||||
for (StoragePoolVO pool : allLocalPoolsInCluster) {
|
for (StoragePoolVO pool : allLocalPoolsInCluster) {
|
||||||
if (!allocatorAvoidOutput.shouldAvoid(pool)) {
|
if (!allocatorAvoidOutput.shouldAvoid(pool)) {
|
||||||
// there's some pool in the cluster that is not yet
|
// there's some pool in the cluster that is not yet
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import javax.inject.Inject;
|
|||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
import com.cloud.capacity.CapacityVO;
|
import com.cloud.capacity.CapacityVO;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
@ -521,6 +522,12 @@ public class FirstFitPlanner extends AdapterBase implements DeploymentClusterPla
|
|||||||
private void removeClustersWithoutMatchingTag(List<Long> clusterListForVmAllocation, String hostTagOnOffering) {
|
private void removeClustersWithoutMatchingTag(List<Long> clusterListForVmAllocation, String hostTagOnOffering) {
|
||||||
|
|
||||||
List<Long> matchingClusters = hostDao.listClustersByHostTag(hostTagOnOffering);
|
List<Long> matchingClusters = hostDao.listClustersByHostTag(hostTagOnOffering);
|
||||||
|
matchingClusters.addAll(hostDao.findClustersThatMatchHostTagRule(hostTagOnOffering));
|
||||||
|
|
||||||
|
if (matchingClusters.isEmpty()) {
|
||||||
|
s_logger.error(String.format("No suitable host found for the following compute offering tags [%s].", hostTagOnOffering));
|
||||||
|
throw new CloudRuntimeException("No suitable host found.");
|
||||||
|
}
|
||||||
|
|
||||||
clusterListForVmAllocation.retainAll(matchingClusters);
|
clusterListForVmAllocation.retainAll(matchingClusters);
|
||||||
|
|
||||||
|
|||||||
@ -32,11 +32,13 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
import com.cloud.alert.AlertManager;
|
import com.cloud.alert.AlertManager;
|
||||||
|
import com.cloud.host.HostTagVO;
|
||||||
import com.cloud.exception.StorageConflictException;
|
import com.cloud.exception.StorageConflictException;
|
||||||
import com.cloud.exception.StorageUnavailableException;
|
import com.cloud.exception.StorageUnavailableException;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
@ -856,7 +858,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
if (s_logger.isTraceEnabled()) {
|
if (s_logger.isTraceEnabled()) {
|
||||||
s_logger.trace("Adding Host Tags for KVM host, tags: :" + hostTags);
|
s_logger.trace("Adding Host Tags for KVM host, tags: :" + hostTags);
|
||||||
}
|
}
|
||||||
_hostTagsDao.persist(host.getId(), hostTags);
|
_hostTagsDao.persist(host.getId(), hostTags, false);
|
||||||
}
|
}
|
||||||
hosts.add(host);
|
hosts.add(host);
|
||||||
|
|
||||||
@ -1909,7 +1911,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateHostTags(HostVO host, Long hostId, List<String> hostTags) {
|
private void updateHostTags(HostVO host, Long hostId, List<String> hostTags, Boolean isTagARule) {
|
||||||
List<VMInstanceVO> activeVMs = _vmDao.listByHostId(hostId);
|
List<VMInstanceVO> activeVMs = _vmDao.listByHostId(hostId);
|
||||||
s_logger.warn(String.format("The following active VMs [%s] are using the host [%s]. " +
|
s_logger.warn(String.format("The following active VMs [%s] are using the host [%s]. " +
|
||||||
"Updating the host tags will not affect them.", activeVMs, host));
|
"Updating the host tags will not affect them.", activeVMs, host));
|
||||||
@ -1917,17 +1919,17 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Updating Host Tags to :" + hostTags);
|
s_logger.debug("Updating Host Tags to :" + hostTags);
|
||||||
}
|
}
|
||||||
_hostTagsDao.persist(hostId, new ArrayList<>(new HashSet<>(hostTags)));
|
_hostTagsDao.persist(hostId, new ArrayList<>(new HashSet<>(hostTags)), isTagARule);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Host updateHost(final UpdateHostCmd cmd) throws NoTransitionException {
|
public Host updateHost(final UpdateHostCmd cmd) throws NoTransitionException {
|
||||||
return updateHost(cmd.getId(), cmd.getName(), cmd.getOsCategoryId(),
|
return updateHost(cmd.getId(), cmd.getName(), cmd.getOsCategoryId(),
|
||||||
cmd.getAllocationState(), cmd.getUrl(), cmd.getHostTags(), cmd.getAnnotation(), false);
|
cmd.getAllocationState(), cmd.getUrl(), cmd.getHostTags(), cmd.getIsTagARule(), cmd.getAnnotation(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Host updateHost(Long hostId, String name, Long guestOSCategoryId, String allocationState,
|
private Host updateHost(Long hostId, String name, Long guestOSCategoryId, String allocationState,
|
||||||
String url, List<String> hostTags, String annotation, boolean isUpdateFromHostHealthCheck) throws NoTransitionException {
|
String url, List<String> hostTags, Boolean isTagARule, String annotation, boolean isUpdateFromHostHealthCheck) throws NoTransitionException {
|
||||||
// Verify that the host exists
|
// Verify that the host exists
|
||||||
final HostVO host = _hostDao.findById(hostId);
|
final HostVO host = _hostDao.findById(hostId);
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
@ -1948,7 +1950,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hostTags != null) {
|
if (hostTags != null) {
|
||||||
updateHostTags(host, hostId, hostTags);
|
updateHostTags(host, hostId, hostTags, isTagARule);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
@ -2007,7 +2009,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Host autoUpdateHostAllocationState(Long hostId, ResourceState.Event resourceEvent) throws NoTransitionException {
|
public Host autoUpdateHostAllocationState(Long hostId, ResourceState.Event resourceEvent) throws NoTransitionException {
|
||||||
return updateHost(hostId, null, null, resourceEvent.toString(), null, null, null, true);
|
return updateHost(hostId, null, null, resourceEvent.toString(), null, null, null, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2339,7 +2341,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
final List<String> implicitHostTags = ssCmd.getHostTags();
|
final List<String> implicitHostTags = ssCmd.getHostTags();
|
||||||
if (!implicitHostTags.isEmpty()) {
|
if (!implicitHostTags.isEmpty()) {
|
||||||
if (hostTags == null) {
|
if (hostTags == null) {
|
||||||
hostTags = _hostTagsDao.getHostTags(host.getId());
|
hostTags = _hostTagsDao.getHostTags(host.getId()).parallelStream().map(HostTagVO::getTag).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if (hostTags != null) {
|
if (hostTags != null) {
|
||||||
implicitHostTags.removeAll(hostTags);
|
implicitHostTags.removeAll(hostTags);
|
||||||
@ -2367,7 +2369,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
host.setManagementServerId(_nodeId);
|
host.setManagementServerId(_nodeId);
|
||||||
host.setStorageUrl(startup.getIqn());
|
host.setStorageUrl(startup.getIqn());
|
||||||
host.setLastPinged(System.currentTimeMillis() >> 10);
|
host.setLastPinged(System.currentTimeMillis() >> 10);
|
||||||
host.setHostTags(hostTags);
|
host.setHostTags(hostTags, false);
|
||||||
host.setDetails(details);
|
host.setDetails(details);
|
||||||
if (startup.getStorageIpAddressDeux() != null) {
|
if (startup.getStorageIpAddressDeux() != null) {
|
||||||
host.setStorageIpAddressDeux(startup.getStorageIpAddressDeux());
|
host.setStorageIpAddressDeux(startup.getStorageIpAddressDeux());
|
||||||
@ -3351,7 +3353,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHostTags(final long hostId) {
|
public String getHostTags(final long hostId) {
|
||||||
final List<String> hostTags = _hostTagsDao.getHostTags(hostId);
|
final List<String> hostTags = _hostTagsDao.getHostTags(hostId).parallelStream().map(HostTagVO::getTag).collect(Collectors.toList());
|
||||||
if (hostTags == null) {
|
if (hostTags == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -54,6 +54,7 @@ import com.cloud.exception.AgentUnavailableException;
|
|||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.exception.OperationTimedoutException;
|
import com.cloud.exception.OperationTimedoutException;
|
||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
|
import com.cloud.host.HostTagVO;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
@ -615,7 +616,7 @@ public class RollingMaintenanceManagerImpl extends ManagerBase implements Rollin
|
|||||||
if (CollectionUtils.isEmpty(vmsRunning)) {
|
if (CollectionUtils.isEmpty(vmsRunning)) {
|
||||||
return new Pair<>(true, "OK");
|
return new Pair<>(true, "OK");
|
||||||
}
|
}
|
||||||
List<String> hostTags = hostTagsDao.getHostTags(host.getId());
|
List<HostTagVO> hostTags = hostTagsDao.getHostTags(host.getId());
|
||||||
|
|
||||||
int successfullyCheckedVmMigrations = 0;
|
int successfullyCheckedVmMigrations = 0;
|
||||||
for (VMInstanceVO runningVM : vmsRunning) {
|
for (VMInstanceVO runningVM : vmsRunning) {
|
||||||
@ -668,14 +669,14 @@ public class RollingMaintenanceManagerImpl extends ManagerBase implements Rollin
|
|||||||
/**
|
/**
|
||||||
* Check hosts tags
|
* Check hosts tags
|
||||||
*/
|
*/
|
||||||
private boolean checkHostTags(List<String> hostTags, List<String> hostInClusterTags, String offeringTag) {
|
private boolean checkHostTags(List<HostTagVO> hostTags, List<HostTagVO> hostInClusterTags, String offeringTag) {
|
||||||
if (CollectionUtils.isEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) {
|
if (CollectionUtils.isEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) {
|
||||||
return true;
|
return true;
|
||||||
} else if ((CollectionUtils.isNotEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) ||
|
} else if ((CollectionUtils.isNotEmpty(hostTags) && CollectionUtils.isEmpty(hostInClusterTags)) ||
|
||||||
(CollectionUtils.isEmpty(hostTags) && CollectionUtils.isNotEmpty(hostInClusterTags))) {
|
(CollectionUtils.isEmpty(hostTags) && CollectionUtils.isNotEmpty(hostInClusterTags))) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return hostInClusterTags.contains(offeringTag);
|
return hostInClusterTags.parallelStream().anyMatch(hostTagVO -> offeringTag.equals(hostTagVO.getTag()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -854,6 +854,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
params.put("hypervisorType", hypervisorType);
|
params.put("hypervisorType", hypervisorType);
|
||||||
params.put("url", cmd.getUrl());
|
params.put("url", cmd.getUrl());
|
||||||
params.put("tags", cmd.getTags());
|
params.put("tags", cmd.getTags());
|
||||||
|
params.put("isTagARule", cmd.isTagARule());
|
||||||
params.put("name", cmd.getStoragePoolName());
|
params.put("name", cmd.getStoragePoolName());
|
||||||
params.put("details", details);
|
params.put("details", details);
|
||||||
params.put("providerName", storeProvider.getName());
|
params.put("providerName", storeProvider.getName());
|
||||||
@ -1017,10 +1018,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
if (pool.getPoolType() == StoragePoolType.DatastoreCluster) {
|
if (pool.getPoolType() == StoragePoolType.DatastoreCluster) {
|
||||||
List<StoragePoolVO> childStoragePools = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(pool.getId());
|
List<StoragePoolVO> childStoragePools = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(pool.getId());
|
||||||
for (StoragePoolVO childPool : childStoragePools) {
|
for (StoragePoolVO childPool : childStoragePools) {
|
||||||
_storagePoolTagsDao.persist(childPool.getId(), storagePoolTags);
|
_storagePoolTagsDao.persist(childPool.getId(), storagePoolTags, cmd.isTagARule());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_storagePoolTagsDao.persist(pool.getId(), storagePoolTags);
|
_storagePoolTagsDao.persist(pool.getId(), storagePoolTags, cmd.isTagARule());
|
||||||
}
|
}
|
||||||
|
|
||||||
Long updatedCapacityBytes = null;
|
Long updatedCapacityBytes = null;
|
||||||
@ -1991,7 +1992,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
|
|
||||||
public void syncDatastoreClusterStoragePool(long datastoreClusterPoolId, List<ModifyStoragePoolAnswer> childDatastoreAnswerList, long hostId) {
|
public void syncDatastoreClusterStoragePool(long datastoreClusterPoolId, List<ModifyStoragePoolAnswer> childDatastoreAnswerList, long hostId) {
|
||||||
StoragePoolVO datastoreClusterPool = _storagePoolDao.findById(datastoreClusterPoolId);
|
StoragePoolVO datastoreClusterPool = _storagePoolDao.findById(datastoreClusterPoolId);
|
||||||
List<String> storageTags = _storagePoolTagsDao.getStoragePoolTags(datastoreClusterPoolId);
|
List<StoragePoolTagVO> storageTags = _storagePoolTagsDao.findStoragePoolTags(datastoreClusterPoolId);
|
||||||
List<StoragePoolVO> childDatastores = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(datastoreClusterPoolId);
|
List<StoragePoolVO> childDatastores = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(datastoreClusterPoolId);
|
||||||
Set<String> childDatastoreUUIDs = new HashSet<>();
|
Set<String> childDatastoreUUIDs = new HashSet<>();
|
||||||
for (StoragePoolVO childDatastore : childDatastores) {
|
for (StoragePoolVO childDatastore : childDatastores) {
|
||||||
@ -2019,18 +2020,18 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
dataStoreVO.setParent(datastoreClusterPoolId);
|
dataStoreVO.setParent(datastoreClusterPoolId);
|
||||||
_storagePoolDao.update(dataStoreVO.getId(), dataStoreVO);
|
_storagePoolDao.update(dataStoreVO.getId(), dataStoreVO);
|
||||||
if (CollectionUtils.isNotEmpty(storageTags)) {
|
if (CollectionUtils.isNotEmpty(storageTags)) {
|
||||||
storageTags.addAll(_storagePoolTagsDao.getStoragePoolTags(dataStoreVO.getId()));
|
storageTags.addAll(_storagePoolTagsDao.findStoragePoolTags(dataStoreVO.getId()));
|
||||||
} else {
|
} else {
|
||||||
storageTags = _storagePoolTagsDao.getStoragePoolTags(dataStoreVO.getId());
|
storageTags = _storagePoolTagsDao.findStoragePoolTags(dataStoreVO.getId());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(storageTags)) {
|
if (CollectionUtils.isNotEmpty(storageTags)) {
|
||||||
Set<String> set = new LinkedHashSet<>(storageTags);
|
Set<StoragePoolTagVO> set = new LinkedHashSet<>(storageTags);
|
||||||
storageTags.clear();
|
storageTags.clear();
|
||||||
storageTags.addAll(set);
|
storageTags.addAll(set);
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Updating Storage Pool Tags to :" + storageTags);
|
s_logger.debug("Updating Storage Pool Tags to :" + storageTags);
|
||||||
}
|
}
|
||||||
_storagePoolTagsDao.persist(dataStoreVO.getId(), storageTags);
|
_storagePoolTagsDao.persist(storageTags);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is to find datastores which are removed from datastore cluster.
|
// This is to find datastores which are removed from datastore cluster.
|
||||||
@ -2038,7 +2039,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
childDatastoreUUIDs.remove(dataStoreVO.getUuid());
|
childDatastoreUUIDs.remove(dataStoreVO.getUuid());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dataStoreVO = createChildDatastoreVO(datastoreClusterPool, childDataStoreAnswer);
|
dataStoreVO = createChildDatastoreVO(datastoreClusterPool, childDataStoreAnswer, storageTags);
|
||||||
}
|
}
|
||||||
updateStoragePoolHostVOAndBytes(dataStoreVO, hostId, childDataStoreAnswer);
|
updateStoragePoolHostVOAndBytes(dataStoreVO, hostId, childDataStoreAnswer);
|
||||||
}
|
}
|
||||||
@ -2079,9 +2080,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StoragePoolVO createChildDatastoreVO(StoragePoolVO datastoreClusterPool, ModifyStoragePoolAnswer childDataStoreAnswer) {
|
private StoragePoolVO createChildDatastoreVO(StoragePoolVO datastoreClusterPool, ModifyStoragePoolAnswer childDataStoreAnswer, List<StoragePoolTagVO> storagePoolTagVOList) {
|
||||||
StoragePoolInfo childStoragePoolInfo = childDataStoreAnswer.getPoolInfo();
|
StoragePoolInfo childStoragePoolInfo = childDataStoreAnswer.getPoolInfo();
|
||||||
List<String> storageTags = _storagePoolTagsDao.getStoragePoolTags(datastoreClusterPool.getId());
|
|
||||||
|
|
||||||
StoragePoolVO dataStoreVO = new StoragePoolVO();
|
StoragePoolVO dataStoreVO = new StoragePoolVO();
|
||||||
dataStoreVO.setStorageProviderName(datastoreClusterPool.getStorageProviderName());
|
dataStoreVO.setStorageProviderName(datastoreClusterPool.getStorageProviderName());
|
||||||
@ -2108,7 +2108,15 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
if(StringUtils.isNotEmpty(childDataStoreAnswer.getPoolType())) {
|
if(StringUtils.isNotEmpty(childDataStoreAnswer.getPoolType())) {
|
||||||
details.put("pool_type", childDataStoreAnswer.getPoolType());
|
details.put("pool_type", childDataStoreAnswer.getPoolType());
|
||||||
}
|
}
|
||||||
_storagePoolDao.persist(dataStoreVO, details, storageTags);
|
|
||||||
|
List<String> storagePoolTags = new ArrayList<>();
|
||||||
|
boolean isTagARule = false;
|
||||||
|
if (CollectionUtils.isNotEmpty(storagePoolTagVOList)) {
|
||||||
|
storagePoolTags = storagePoolTagVOList.parallelStream().map(StoragePoolTagVO::getTag).collect(Collectors.toList());
|
||||||
|
isTagARule = storagePoolTagVOList.get(0).isTagARule();
|
||||||
|
}
|
||||||
|
|
||||||
|
_storagePoolDao.persist(dataStoreVO, details, storagePoolTags, isTagARule);
|
||||||
return dataStoreVO;
|
return dataStoreVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -106,6 +106,7 @@ import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
|
|||||||
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
||||||
import org.apache.cloudstack.utils.identity.ManagementServerNode;
|
import org.apache.cloudstack.utils.identity.ManagementServerNode;
|
||||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||||
|
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
@ -346,6 +347,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
@Inject
|
@Inject
|
||||||
protected StoragePoolDetailsDao storagePoolDetailsDao;
|
protected StoragePoolDetailsDao storagePoolDetailsDao;
|
||||||
|
|
||||||
|
|
||||||
protected Gson _gson;
|
protected Gson _gson;
|
||||||
|
|
||||||
private static final List<HypervisorType> SupportedHypervisorsForVolResize = Arrays.asList(HypervisorType.KVM, HypervisorType.XenServer,
|
private static final List<HypervisorType> SupportedHypervisorsForVolResize = Arrays.asList(HypervisorType.KVM, HypervisorType.XenServer,
|
||||||
@ -375,6 +377,9 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
"Time (in milliseconds) to wait before assuming the VM was unable to detach a volume after the hypervisor sends the detach command.",
|
"Time (in milliseconds) to wait before assuming the VM was unable to detach a volume after the hypervisor sends the detach command.",
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
public static ConfigKey<Long> storageTagRuleExecutionTimeout = new ConfigKey<>("Advanced", Long.class, "storage.tag.rule.execution.timeout", "2000", "The maximum runtime,"
|
||||||
|
+ " in milliseconds, to execute a storage tag rule; if it is reached, a timeout will happen.", true);
|
||||||
|
|
||||||
private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
|
private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
|
||||||
|
|
||||||
private static final Set<Volume.State> STATES_VOLUME_CANNOT_BE_DESTROYED = new HashSet<>(Arrays.asList(Volume.State.Destroy, Volume.State.Expunging, Volume.State.Expunged, Volume.State.Allocated));
|
private static final Set<Volume.State> STATES_VOLUME_CANNOT_BE_DESTROYED = new HashSet<>(Arrays.asList(Volume.State.Destroy, Volume.State.Expunging, Volume.State.Expunged, Volume.State.Allocated));
|
||||||
@ -3266,7 +3271,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
if (!doesTargetStorageSupportDiskOffering(destPool, newDiskOffering)) {
|
if (!doesTargetStorageSupportDiskOffering(destPool, newDiskOffering)) {
|
||||||
throw new InvalidParameterValueException(String.format("Migration failed: target pool [%s, tags:%s] has no matching tags for volume [%s, uuid:%s, tags:%s]", destPool.getName(),
|
throw new InvalidParameterValueException(String.format("Migration failed: target pool [%s, tags:%s] has no matching tags for volume [%s, uuid:%s, tags:%s]", destPool.getName(),
|
||||||
getStoragePoolTags(destPool), volume.getName(), volume.getUuid(), newDiskOffering.getTags()));
|
storagePoolTagsDao.getStoragePoolTags(destPool.getId()), volume.getName(), volume.getUuid(), newDiskOffering.getTags()));
|
||||||
}
|
}
|
||||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
||||||
VMInstanceVO vm = null;
|
VMInstanceVO vm = null;
|
||||||
@ -3329,17 +3334,31 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean doesTargetStorageSupportDiskOffering(StoragePool destPool, String diskOfferingTags) {
|
public boolean doesTargetStorageSupportDiskOffering(StoragePool destPool, String diskOfferingTags) {
|
||||||
if (StringUtils.isBlank(diskOfferingTags)) {
|
Pair<List<String>, Boolean> storagePoolTags = getStoragePoolTags(destPool);
|
||||||
|
if ((storagePoolTags == null || !storagePoolTags.second()) && org.apache.commons.lang.StringUtils.isBlank(diskOfferingTags)) {
|
||||||
|
if (storagePoolTags == null) {
|
||||||
|
s_logger.debug(String.format("Destination storage pool [%s] does not have any tags, and so does the disk offering. Therefore, they are compatible", destPool.getUuid()));
|
||||||
|
} else {
|
||||||
|
s_logger.debug("Destination storage pool has tags [%s], and the disk offering has no tags. Therefore, they are compatible.");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String storagePoolTags = getStoragePoolTags(destPool);
|
if (storagePoolTags == null || CollectionUtils.isEmpty(storagePoolTags.first())) {
|
||||||
if (StringUtils.isBlank(storagePoolTags)) {
|
s_logger.debug(String.format("Destination storage pool [%s] has no tags, while disk offering has tags [%s]. Therefore, they are not compatible", destPool.getUuid(),
|
||||||
|
diskOfferingTags));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String[] storageTagsAsStringArray = StringUtils.split(storagePoolTags, ",");
|
List<String> storageTagsList = storagePoolTags.first();
|
||||||
String[] newDiskOfferingTagsAsStringArray = StringUtils.split(diskOfferingTags, ",");
|
String[] newDiskOfferingTagsAsStringArray = org.apache.commons.lang.StringUtils.split(diskOfferingTags, ",");
|
||||||
|
|
||||||
return CollectionUtils.isSubCollection(Arrays.asList(newDiskOfferingTagsAsStringArray), Arrays.asList(storageTagsAsStringArray));
|
boolean result;
|
||||||
|
if (storagePoolTags.second()) {
|
||||||
|
result = TagAsRuleHelper.interpretTagAsRule(storageTagsList.get(0), diskOfferingTags, storageTagRuleExecutionTimeout.value());
|
||||||
|
} else {
|
||||||
|
result = CollectionUtils.isSubCollection(Arrays.asList(newDiskOfferingTagsAsStringArray), storageTagsList);
|
||||||
|
}
|
||||||
|
s_logger.debug(String.format("Destination storage pool [%s] accepts tags [%s]? %s", destPool.getUuid(), diskOfferingTags, result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean doesNewDiskOfferingHasTagsAsOldDiskOffering(DiskOfferingVO oldDO, DiskOfferingVO newDO) {
|
public static boolean doesNewDiskOfferingHasTagsAsOldDiskOffering(DiskOfferingVO oldDO, DiskOfferingVO newDO) {
|
||||||
@ -3355,14 +3374,17 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the storage pool tags as a {@link String}. If the storage pool does not have tags we return a null value.
|
* Returns a {@link Pair}, where the first value is the list of the StoragePool tags, and the second value is whether the returned tags are to be interpreted as a rule,
|
||||||
|
* or a normal list of tags.
|
||||||
|
* <br><br>
|
||||||
|
* If the storage pool does not have tags we return a null value.
|
||||||
*/
|
*/
|
||||||
protected String getStoragePoolTags(StoragePool destPool) {
|
protected Pair<List<String>, Boolean> getStoragePoolTags(StoragePool destPool) {
|
||||||
List<String> destPoolTags = storagePoolTagsDao.getStoragePoolTags(destPool.getId());
|
List<StoragePoolTagVO> destPoolTags = storagePoolTagsDao.findStoragePoolTags(destPool.getId());
|
||||||
if (CollectionUtils.isEmpty(destPoolTags)) {
|
if (CollectionUtils.isEmpty(destPoolTags)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return StringUtils.join(destPoolTags, ",");
|
return new Pair<>(destPoolTags.parallelStream().map(StoragePoolTagVO::getTag).collect(Collectors.toList()), destPoolTags.get(0).isTagARule());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, boolean liveMigrateVolume, DiskOfferingVO newDiskOffering) {
|
private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, boolean liveMigrateVolume, DiskOfferingVO newDiskOffering) {
|
||||||
|
|||||||
@ -101,7 +101,7 @@ public class StoragePoolMonitor implements Listener {
|
|||||||
scCmd.getHypervisorType() == HypervisorType.Ovm || scCmd.getHypervisorType() == HypervisorType.Hyperv ||
|
scCmd.getHypervisorType() == HypervisorType.Ovm || scCmd.getHypervisorType() == HypervisorType.Hyperv ||
|
||||||
scCmd.getHypervisorType() == HypervisorType.LXC || scCmd.getHypervisorType() == HypervisorType.Ovm3) {
|
scCmd.getHypervisorType() == HypervisorType.LXC || scCmd.getHypervisorType() == HypervisorType.Ovm3) {
|
||||||
List<StoragePoolVO> pools = _poolDao.listBy(host.getDataCenterId(), host.getPodId(), host.getClusterId(), ScopeType.CLUSTER);
|
List<StoragePoolVO> pools = _poolDao.listBy(host.getDataCenterId(), host.getPodId(), host.getClusterId(), ScopeType.CLUSTER);
|
||||||
List<StoragePoolVO> zoneStoragePoolsByTags = _poolDao.findZoneWideStoragePoolsByTags(host.getDataCenterId(), null);
|
List<StoragePoolVO> zoneStoragePoolsByTags = _poolDao.findZoneWideStoragePoolsByTags(host.getDataCenterId(), null, false);
|
||||||
List<StoragePoolVO> zoneStoragePoolsByHypervisor = _poolDao.findZoneWideStoragePoolsByHypervisor(host.getDataCenterId(), scCmd.getHypervisorType());
|
List<StoragePoolVO> zoneStoragePoolsByHypervisor = _poolDao.findZoneWideStoragePoolsByHypervisor(host.getDataCenterId(), scCmd.getHypervisorType());
|
||||||
zoneStoragePoolsByTags.retainAll(zoneStoragePoolsByHypervisor);
|
zoneStoragePoolsByTags.retainAll(zoneStoragePoolsByHypervisor);
|
||||||
pools.addAll(zoneStoragePoolsByTags);
|
pools.addAll(zoneStoragePoolsByTags);
|
||||||
|
|||||||
@ -58,6 +58,7 @@ import com.cloud.network.dao.PhysicalNetworkDao;
|
|||||||
import com.cloud.network.dao.PhysicalNetworkVO;
|
import com.cloud.network.dao.PhysicalNetworkVO;
|
||||||
import com.cloud.projects.ProjectManager;
|
import com.cloud.projects.ProjectManager;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
|
import com.cloud.storage.StoragePoolTagVO;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.DiskOfferingDao;
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
import com.cloud.storage.dao.StoragePoolTagsDao;
|
import com.cloud.storage.dao.StoragePoolTagsDao;
|
||||||
@ -1163,12 +1164,17 @@ public class ConfigurationManagerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void updateDiskOfferingTagsWithPrimaryStorageWithCorrectTagsTestSuccess(){
|
public void updateDiskOfferingTagsWithPrimaryStorageWithCorrectTagsTestSuccess(){
|
||||||
String tags = "tag1,tag2";
|
String tags = "tag1,tag2";
|
||||||
List<String> storageTagsWithCorrectTags = new ArrayList<>(Arrays.asList("tag1","tag2"));
|
|
||||||
List<StoragePoolVO> pools = new ArrayList<>(Arrays.asList(storagePoolVO));
|
List<StoragePoolVO> pools = new ArrayList<>(Arrays.asList(storagePoolVO));
|
||||||
List<VolumeVO> volumes = new ArrayList<>(Arrays.asList(volumeVO));
|
List<VolumeVO> volumes = new ArrayList<>(Arrays.asList(volumeVO));
|
||||||
|
|
||||||
|
StoragePoolTagVO poolTagMock1 = Mockito.mock(StoragePoolTagVO.class);
|
||||||
|
StoragePoolTagVO poolTagMock2 = Mockito.mock(StoragePoolTagVO.class);
|
||||||
|
List<StoragePoolTagVO> poolTags = List.of(poolTagMock1, poolTagMock2);
|
||||||
|
Mockito.doReturn("tag1").when(poolTagMock1).getTag();
|
||||||
|
Mockito.doReturn("tag2").when(poolTagMock2).getTag();
|
||||||
|
|
||||||
Mockito.when(primaryDataStoreDao.listStoragePoolsWithActiveVolumesByOfferingId(anyLong())).thenReturn(pools);
|
Mockito.when(primaryDataStoreDao.listStoragePoolsWithActiveVolumesByOfferingId(anyLong())).thenReturn(pools);
|
||||||
Mockito.when(storagePoolTagsDao.getStoragePoolTags(anyLong())).thenReturn(storageTagsWithCorrectTags);
|
Mockito.when(storagePoolTagsDao.findStoragePoolTags(anyLong())).thenReturn(poolTags);
|
||||||
Mockito.when(diskOfferingDao.findById(anyLong())).thenReturn(diskOfferingVOMock);
|
Mockito.when(diskOfferingDao.findById(anyLong())).thenReturn(diskOfferingVOMock);
|
||||||
Mockito.when(_volumeDao.findByDiskOfferingId(anyLong())).thenReturn(volumes);
|
Mockito.when(_volumeDao.findByDiskOfferingId(anyLong())).thenReturn(volumes);
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -117,6 +118,7 @@ import com.cloud.user.ResourceLimitService;
|
|||||||
import com.cloud.user.User;
|
import com.cloud.user.User;
|
||||||
import com.cloud.user.UserVO;
|
import com.cloud.user.UserVO;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.db.TransactionLegacy;
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.fsm.NoTransitionException;
|
import com.cloud.utils.fsm.NoTransitionException;
|
||||||
@ -650,29 +652,35 @@ public class VolumeApiServiceImplTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getStoragePoolTagsTestStorageWithoutTags() {
|
public void getStoragePoolTagsTestStorageWithoutTags() {
|
||||||
Mockito.when(storagePoolTagsDao.getStoragePoolTags(storagePoolMockId)).thenReturn(new ArrayList<>());
|
Pair<List<String>, Boolean> returnedStoragePoolTags = volumeApiServiceImpl.getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
String returnedStoragePoolTags = volumeApiServiceImpl.getStoragePoolTags(storagePoolMock);
|
|
||||||
|
|
||||||
Assert.assertNull(returnedStoragePoolTags);
|
Assert.assertNull(returnedStoragePoolTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getStoragePoolTagsTestStorageWithTags() {
|
public void getStoragePoolTagsTestStorageWithTags() {
|
||||||
ArrayList<String> tags = new ArrayList<>();
|
StoragePoolTagVO tag1 = new StoragePoolTagVO(1,"tag1", false);
|
||||||
String tag1 = "tag1";
|
StoragePoolTagVO tag2 = new StoragePoolTagVO(1,"tag2", false);
|
||||||
String tag2 = "tag2";
|
StoragePoolTagVO tag3 = new StoragePoolTagVO(1,"tag3", false);
|
||||||
String tag3 = "tag3";
|
List<StoragePoolTagVO> tags = Arrays.asList(tag1, tag2, tag3);
|
||||||
|
|
||||||
tags.add(tag1);
|
Mockito.when(storagePoolTagsDao.findStoragePoolTags(storagePoolMockId)).thenReturn(tags);
|
||||||
tags.add(tag2);
|
|
||||||
tags.add(tag3);
|
|
||||||
|
|
||||||
Mockito.when(storagePoolTagsDao.getStoragePoolTags(storagePoolMockId)).thenReturn(tags);
|
Pair<List<String>, Boolean> returnedStoragePoolTags = volumeApiServiceImpl.getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
String returnedStoragePoolTags = volumeApiServiceImpl.getStoragePoolTags(storagePoolMock);
|
Assert.assertEquals(new Pair<>(Arrays.asList("tag1","tag2","tag3"), false), returnedStoragePoolTags);
|
||||||
|
}
|
||||||
|
|
||||||
Assert.assertEquals("tag1,tag2,tag3", returnedStoragePoolTags);
|
@Test
|
||||||
|
public void getStoragePoolTagsTestStorageWithRuleTag() {
|
||||||
|
StoragePoolTagVO tag1 = new StoragePoolTagVO(1,"tag1", true);
|
||||||
|
List<StoragePoolTagVO> tags = List.of(tag1);
|
||||||
|
|
||||||
|
Mockito.when(storagePoolTagsDao.findStoragePoolTags(storagePoolMockId)).thenReturn(tags);
|
||||||
|
|
||||||
|
Pair<List<String>, Boolean> returnedStoragePoolTags = volumeApiServiceImpl.getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
|
Assert.assertEquals(new Pair<>(List.of("tag1"), true), returnedStoragePoolTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -757,7 +765,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
|
|
||||||
Mockito.when(newDiskOfferingMock.getTags()).thenReturn("tag1");
|
Mockito.when(newDiskOfferingMock.getTags()).thenReturn("tag1");
|
||||||
|
|
||||||
Mockito.doReturn("tag1").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.doReturn(new Pair<>(List.of("tag1"), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
|
volumeApiServiceImpl.validateConditionsToReplaceDiskOfferingOfVolume(volumeVoMock, newDiskOfferingMock, storagePoolMock);
|
||||||
|
|
||||||
@ -1138,7 +1146,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("A,B,C").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("A,B,C").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.doReturn("A").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.doReturn(new Pair<>(List.of("A"), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
@ -1151,7 +1159,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("A,B,C").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("A,B,C").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.doReturn("A,B,C,D,X,Y").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.doReturn(new Pair<>(List.of("A","B","C","D","X","Y"), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
@ -1164,7 +1172,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.lenient().doReturn("A,B,C,D,X,Y").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.lenient().doReturn(new Pair<>(List.of("A,B,C,D,X,Y"), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
@ -1177,7 +1185,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("A").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("A").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.doReturn("").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.doReturn(new Pair<>(List.of(""), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
@ -1190,7 +1198,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.lenient().doReturn("").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.lenient().doReturn(new Pair<>(List.of(""), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
@ -1203,7 +1211,7 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("A,B").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("A,B").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.doReturn("C,D").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.doReturn(new Pair<>(List.of("C,D"), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
@ -1216,13 +1224,52 @@ public class VolumeApiServiceImplTest {
|
|||||||
Mockito.doReturn("A").when(diskOfferingVoMock).getTags();
|
Mockito.doReturn("A").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
Mockito.doReturn("A").when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
Mockito.doReturn(new Pair<>(List.of("A"), false)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
Assert.assertTrue(result);
|
Assert.assertTrue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doesTargetStorageSupportDiskOfferingTestStorageRuleTagWithDiskOfferingTagThatMatches() {
|
||||||
|
DiskOfferingVO diskOfferingVoMock = Mockito.mock(DiskOfferingVO.class);
|
||||||
|
Mockito.doReturn("A").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
|
Mockito.doReturn(new Pair<>(List.of("tags[0] == 'A'"), true)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doesTargetStorageSupportDiskOfferingTestStorageRuleTagWithDiskOfferingTagThatDoesNotMatch() {
|
||||||
|
DiskOfferingVO diskOfferingVoMock = Mockito.mock(DiskOfferingVO.class);
|
||||||
|
Mockito.doReturn("'").when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
|
Mockito.doReturn(new Pair<>(List.of("tags[0] == 'A'"), true)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doesTargetStorageSupportDiskOfferingTestStorageRuleTagWithNullDiskOfferingTag() {
|
||||||
|
DiskOfferingVO diskOfferingVoMock = Mockito.mock(DiskOfferingVO.class);
|
||||||
|
Mockito.doReturn(null).when(diskOfferingVoMock).getTags();
|
||||||
|
|
||||||
|
StoragePool storagePoolMock = Mockito.mock(StoragePool.class);
|
||||||
|
Mockito.doReturn(new Pair<>(List.of("tags[0] == 'A'"), true)).when(volumeApiServiceImpl).getStoragePoolTags(storagePoolMock);
|
||||||
|
|
||||||
|
boolean result = volumeApiServiceImpl.doesTargetStorageSupportDiskOffering(storagePoolMock, diskOfferingVoMock);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void validateIfVmHaveBackupsTestExceptionWhenTryToDetachVolumeFromVMWhichBackupOffering() {
|
public void validateIfVmHaveBackupsTestExceptionWhenTryToDetachVolumeFromVMWhichBackupOffering() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -60,7 +60,7 @@ public class StoragePoolMonitorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testProcessConnectStoragePoolNormal() throws Exception {
|
public void testProcessConnectStoragePoolNormal() throws Exception {
|
||||||
Mockito.when(poolDao.listBy(nullable(Long.class), nullable(Long.class), nullable(Long.class), Mockito.any(ScopeType.class))).thenReturn(Collections.singletonList(pool));
|
Mockito.when(poolDao.listBy(nullable(Long.class), nullable(Long.class), nullable(Long.class), Mockito.any(ScopeType.class))).thenReturn(Collections.singletonList(pool));
|
||||||
Mockito.when(poolDao.findZoneWideStoragePoolsByTags(Mockito.anyLong(), Mockito.any(String[].class))).thenReturn(Collections.<StoragePoolVO>emptyList());
|
Mockito.when(poolDao.findZoneWideStoragePoolsByTags(Mockito.anyLong(), Mockito.any(String[].class), Mockito.anyBoolean())).thenReturn(Collections.<StoragePoolVO>emptyList());
|
||||||
Mockito.when(poolDao.findZoneWideStoragePoolsByHypervisor(Mockito.anyLong(), Mockito.any(Hypervisor.HypervisorType.class))).thenReturn(Collections.<StoragePoolVO>emptyList());
|
Mockito.when(poolDao.findZoneWideStoragePoolsByHypervisor(Mockito.anyLong(), Mockito.any(Hypervisor.HypervisorType.class))).thenReturn(Collections.<StoragePoolVO>emptyList());
|
||||||
Mockito.doReturn(true).when(storageManager).connectHostToSharedPool(host.getId(), pool.getId());
|
Mockito.doReturn(true).when(storageManager).connectHostToSharedPool(host.getId(), pool.getId());
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ public class StoragePoolMonitorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testProcessConnectStoragePoolFailureOnHost() throws Exception {
|
public void testProcessConnectStoragePoolFailureOnHost() throws Exception {
|
||||||
Mockito.when(poolDao.listBy(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.any(ScopeType.class))).thenReturn(Collections.singletonList(pool));
|
Mockito.when(poolDao.listBy(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), Mockito.any(ScopeType.class))).thenReturn(Collections.singletonList(pool));
|
||||||
Mockito.when(poolDao.findZoneWideStoragePoolsByTags(Mockito.anyLong(), Mockito.any(String[].class))).thenReturn(Collections.<StoragePoolVO>emptyList());
|
Mockito.when(poolDao.findZoneWideStoragePoolsByTags(Mockito.anyLong(), Mockito.any(String[].class), Mockito.anyBoolean())).thenReturn(Collections.<StoragePoolVO>emptyList());
|
||||||
Mockito.when(poolDao.findZoneWideStoragePoolsByHypervisor(Mockito.anyLong(), Mockito.any(Hypervisor.HypervisorType.class))).thenReturn(Collections.<StoragePoolVO>emptyList());
|
Mockito.when(poolDao.findZoneWideStoragePoolsByHypervisor(Mockito.anyLong(), Mockito.any(Hypervisor.HypervisorType.class))).thenReturn(Collections.<StoragePoolVO>emptyList());
|
||||||
Mockito.doThrow(new StorageUnavailableException("unable to mount storage", 123L)).when(storageManager).connectHostToSharedPool(Mockito.anyLong(), Mockito.anyLong());
|
Mockito.doThrow(new StorageUnavailableException("unable to mount storage", 123L)).when(storageManager).connectHostToSharedPool(Mockito.anyLong(), Mockito.anyLong());
|
||||||
|
|
||||||
|
|||||||
@ -1081,6 +1081,7 @@
|
|||||||
"label.isdedicated": "Dedicated",
|
"label.isdedicated": "Dedicated",
|
||||||
"label.isdefault": "Is default",
|
"label.isdefault": "Is default",
|
||||||
"label.isdynamicallyscalable": "Dynamically scalable",
|
"label.isdynamicallyscalable": "Dynamically scalable",
|
||||||
|
"label.istagarule": "Tag as JS rule",
|
||||||
"label.isextractable": "Extractable",
|
"label.isextractable": "Extractable",
|
||||||
"label.isfeatured": "Featured",
|
"label.isfeatured": "Featured",
|
||||||
"label.isforced": "Force delete",
|
"label.isforced": "Force delete",
|
||||||
|
|||||||
@ -844,6 +844,7 @@
|
|||||||
"label.isdedicated": "Dedicado",
|
"label.isdedicated": "Dedicado",
|
||||||
"label.isdefault": "\u00c9\u0089 padr\u00e3o",
|
"label.isdefault": "\u00c9\u0089 padr\u00e3o",
|
||||||
"label.isdynamicallyscalable": "Dinamicamente escal\u00e1vel",
|
"label.isdynamicallyscalable": "Dinamicamente escal\u00e1vel",
|
||||||
|
"label.istagarule": "Tag como regra JS",
|
||||||
"label.isextractable": "Extra\u00edvel",
|
"label.isextractable": "Extra\u00edvel",
|
||||||
"label.isfeatured": "Em destaque",
|
"label.isfeatured": "Em destaque",
|
||||||
"label.isforced": "For\u00e7ar exclus\u00e3o",
|
"label.isforced": "For\u00e7ar exclus\u00e3o",
|
||||||
|
|||||||
@ -68,7 +68,7 @@ export default {
|
|||||||
icon: 'edit-outlined',
|
icon: 'edit-outlined',
|
||||||
label: 'label.edit',
|
label: 'label.edit',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
args: ['name', 'hosttags', 'oscategoryid'],
|
args: ['name', 'hosttags', 'istagarule', 'oscategoryid'],
|
||||||
mapping: {
|
mapping: {
|
||||||
oscategoryid: {
|
oscategoryid: {
|
||||||
api: 'listOsCategories'
|
api: 'listOsCategories'
|
||||||
|
|||||||
@ -89,7 +89,7 @@ export default {
|
|||||||
icon: 'edit-outlined',
|
icon: 'edit-outlined',
|
||||||
label: 'label.edit',
|
label: 'label.edit',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
args: ['name', 'tags', 'capacitybytes', 'capacityiops']
|
args: ['name', 'tags', 'istagarule', 'capacitybytes', 'capacityiops']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
api: 'updateStoragePool',
|
api: 'updateStoragePool',
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
//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.utils.jsinterpreter;
|
||||||
|
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import org.apache.commons.lang3.StringEscapeUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class TagAsRuleHelper {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(TagAsRuleHelper.class);
|
||||||
|
|
||||||
|
private static final String PARSE_TAGS = "tags = tags ? tags.split(',') : [];";
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean interpretTagAsRule(String rule, String tags, long timeout) {
|
||||||
|
String script = PARSE_TAGS + rule;
|
||||||
|
tags = String.format("'%s'", StringEscapeUtils.escapeEcmaScript(tags));
|
||||||
|
try (JsInterpreter jsInterpreter = new JsInterpreter(timeout)) {
|
||||||
|
jsInterpreter.injectVariable("tags", tags);
|
||||||
|
Object scriptReturn = jsInterpreter.executeScript(script);
|
||||||
|
if (scriptReturn instanceof Boolean) {
|
||||||
|
return (Boolean)scriptReturn;
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
String message = String.format("Error while executing script [%s].", script);
|
||||||
|
LOGGER.error(message, ex);
|
||||||
|
throw new CloudRuntimeException(message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug(String.format("Result of tag rule [%s] was not a boolean, returning false.", script));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user