From 818e6f98fd6bd3732c5867d8b2ae85365f374b95 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Tue, 15 Oct 2013 16:57:53 -0700 Subject: [PATCH] CLOUDSTACK-4874: added resource tags to the Service offering object. Tags can be created by using createTag API command; you can list service offerings by tags when pass "resourceTag" parameter to the listServiceOfferings call --- api/src/com/cloud/server/ResourceTag.java | 3 +- .../apache/cloudstack/api/ApiConstants.java | 1 + .../offering/ListServiceOfferingsCmd.java | 31 ++++++++++++++- .../api/response/ServiceOfferingResponse.java | 21 +++++++--- server/src/com/cloud/api/ApiDBUtils.java | 4 ++ .../com/cloud/api/query/QueryManagerImpl.java | 39 +++++++++++++++++-- .../api/query/dao/ResourceTagJoinDao.java | 3 ++ .../api/query/dao/ResourceTagJoinDaoImpl.java | 25 +++++++++--- .../query/dao/ServiceOfferingJoinDaoImpl.java | 18 ++++++--- .../cloud/tags/TaggedResourceManagerImpl.java | 14 ++++--- .../uuididentity/dao/IdentityDaoImpl.java | 8 +++- 11 files changed, 137 insertions(+), 30 deletions(-) diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java index 1c16f251bd3..9e166ab8c99 100644 --- a/api/src/com/cloud/server/ResourceTag.java +++ b/api/src/com/cloud/server/ResourceTag.java @@ -41,7 +41,8 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit StaticRoute, VMSnapshot, RemoteAccessVpn, - Zone + Zone, + ServiceOffering } /** diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index f85784bbde0..62eed0908d4 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -518,6 +518,7 @@ public class ApiConstants { public static final String ROUTING = "isrouting"; public static final String MAX_CONNECTIONS = "maxconnections"; public static final String SERVICE_STATE = "servicestate"; + public static final String RESOURCE_TAG = "resourcetag"; public enum HostDetails { all, capacity, events, stats, min; } diff --git a/api/src/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java b/api/src/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java index ca16cdc7efe..06aad9d4732 100644 --- a/api/src/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java @@ -16,10 +16,16 @@ // under the License. package org.apache.cloudstack.api.command.user.offering; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; @@ -27,6 +33,8 @@ import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.log4j.Logger; +import com.cloud.exception.InvalidParameterValueException; + @APICommand(name = "listServiceOfferings", description="Lists all available service offerings.", responseObject=ServiceOfferingResponse.class) public class ListServiceOfferingsCmd extends BaseListCmd { public static final Logger s_logger = Logger.getLogger(ListServiceOfferingsCmd.class.getName()); @@ -57,6 +65,9 @@ public class ListServiceOfferingsCmd extends BaseListCmd { @Parameter(name=ApiConstants.SYSTEM_VM_TYPE, type=CommandType.STRING, description="the system VM type. Possible types are \"consoleproxy\", \"secondarystoragevm\" or \"domainrouter\".") private String systemVmType; + + @Parameter(name = ApiConstants.RESOURCE_TAG, type = CommandType.MAP, description = "List service offerings by resource tags (key/value pairs)", since="4.3") + private Map resourceTag; ///////////////////////////////////////////////////// @@ -86,6 +97,25 @@ public class ListServiceOfferingsCmd extends BaseListCmd { public String getSystemVmType(){ return systemVmType; } + + public Map getResourceTags() { + Map tagsMap = null; + if (resourceTag != null && !resourceTag.isEmpty()) { + tagsMap = new HashMap(); + Collection servicesCollection = resourceTag.values(); + Iterator iter = servicesCollection.iterator(); + while (iter.hasNext()) { + HashMap services = (HashMap) iter.next(); + String key = services.get("key"); + String value = services.get("value"); + if (value == null) { + throw new InvalidParameterValueException("No value is passed in for key " + key); + } + tagsMap.put(key, value); + } + } + return tagsMap; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -98,7 +128,6 @@ public class ListServiceOfferingsCmd extends BaseListCmd { @Override public void execute(){ - ListResponse response = _queryService.searchForServiceOfferings(this); response.setResponseName(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java index 5c5b369ec25..d6838402b3c 100644 --- a/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ServiceOfferingResponse.java @@ -17,12 +17,9 @@ package org.apache.cloudstack.api.response; import java.util.Date; - - -import com.google.gson.annotations.SerializedName; - +import java.util.LinkedHashSet; import java.util.Map; - +import java.util.Set; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; @@ -30,6 +27,7 @@ import org.apache.cloudstack.api.EntityReference; import com.cloud.offering.ServiceOffering; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @EntityReference(value = ServiceOffering.class) public class ServiceOfferingResponse extends BaseResponse { @@ -108,6 +106,15 @@ public class ServiceOfferingResponse extends BaseResponse { @SerializedName(ApiConstants.SERVICE_OFFERING_DETAILS) @Param(description = "additional key/value details tied with this service offering", since = "4.2.0") private Map details; + + @SerializedName(ApiConstants.RESOURCE_TAG) @Param(description="the list of resource tags associated with service offering." + + " The resource tags are not used for Volume/VM placement on the specific host.", + responseObject = ResourceTagResponse.class, since="4.3") + private Set resourceTags; + + public ServiceOfferingResponse(){ + resourceTags = new LinkedHashSet(); + } public String getId() { return id; @@ -287,4 +294,8 @@ public class ServiceOfferingResponse extends BaseResponse { public void setDetails(Map details) { this.details = details; } + + public void addTag(ResourceTagResponse tag){ + this.resourceTags.add(tag); + } } diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 6539289dd4a..fa397ed3249 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -1688,4 +1688,8 @@ public class ApiDBUtils { public static boolean isAdmin(Account account) { return _accountService.isAdmin(account.getType()); } + + public static List listResourceTagViewByResourceUUID(String resourceUUID, TaggedResourceType resourceType){ + return _tagJoinDao.listBy(resourceUUID, resourceType); + } } diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index e65a8b8a286..b464e9e5cdb 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -26,7 +26,6 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; -import com.cloud.network.dao.NetworkDetailsDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -142,6 +141,7 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.UnsupportedServiceException; import com.cloud.ha.HighAvailabilityManager; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.security.SecurityGroupVMMapVO; import com.cloud.network.security.dao.SecurityGroupVMMapDao; import com.cloud.org.Grouping; @@ -168,6 +168,8 @@ import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDetailsDao; +import com.cloud.tags.ResourceTagVO; +import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -179,6 +181,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.Filter; +import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; @@ -335,6 +338,9 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { @Inject NetworkDetailsDao _networkDetailsDao; + + @Inject + ResourceTagDao _resourceTagDao; /* * (non-Javadoc) @@ -2375,8 +2381,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { isAscending = (isAscending == null ? true : isAscending); Filter searchFilter = new Filter(ServiceOfferingJoinVO.class, "sortKey", isAscending, cmd.getStartIndex(), cmd.getPageSizeVal()); - SearchCriteria sc = _srvOfferingJoinDao.createSearchCriteria(); - + Account caller = CallContext.current().getCallingAccount(); Object name = cmd.getServiceOfferingName(); Object id = cmd.getId(); @@ -2385,6 +2390,22 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Long domainId = cmd.getDomainId(); Boolean isSystem = cmd.getIsSystem(); String vmTypeStr = cmd.getSystemVmType(); + Map resourceTags = cmd.getResourceTags(); + + SearchBuilder sb = _srvOfferingJoinDao.createSearchBuilder(); + if (resourceTags != null && !resourceTags.isEmpty()) { + SearchBuilder tagSearch = _resourceTagDao.createSearchBuilder(); + for (int count=0; count < resourceTags.size(); count++) { + tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ); + tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ); + tagSearch.cp(); + } + tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ); + sb.groupBy(sb.entity().getId()); + sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); + } + + SearchCriteria sc = sb.create(); if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && isSystem) { throw new InvalidParameterValueException("Only ROOT admins can access system's offering"); @@ -2483,9 +2504,19 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { if (vmTypeStr != null) { sc.addAnd("vm_type", SearchCriteria.Op.EQ, vmTypeStr); } + + + if (resourceTags != null && !resourceTags.isEmpty()) { + int count = 0; + sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.ServiceOffering.toString()); + for (String key : resourceTags.keySet()) { + sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key); + sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), resourceTags.get(key)); + count++; + } + } return _srvOfferingJoinDao.searchAndCount(sc, searchFilter); - } @Override diff --git a/server/src/com/cloud/api/query/dao/ResourceTagJoinDao.java b/server/src/com/cloud/api/query/dao/ResourceTagJoinDao.java index 57fc130de55..627033c274d 100644 --- a/server/src/com/cloud/api/query/dao/ResourceTagJoinDao.java +++ b/server/src/com/cloud/api/query/dao/ResourceTagJoinDao.java @@ -22,6 +22,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse; import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.server.ResourceTag; +import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.utils.db.GenericDao; public interface ResourceTagJoinDao extends GenericDao { @@ -31,4 +32,6 @@ public interface ResourceTagJoinDao extends GenericDao ResourceTagJoinVO newResourceTagView(ResourceTag vr); List searchByIds(Long... ids); + + List listBy(String resourceUUID, TaggedResourceType resourceType); } diff --git a/server/src/com/cloud/api/query/dao/ResourceTagJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/ResourceTagJoinDaoImpl.java index 06821db99cd..f0ddaa6964f 100644 --- a/server/src/com/cloud/api/query/dao/ResourceTagJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/ResourceTagJoinDaoImpl.java @@ -24,16 +24,17 @@ import javax.inject.Inject; import org.apache.cloudstack.api.response.ResourceTagResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; - import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.api.ApiResponseHelper; import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.server.ResourceTag; +import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; @Component @Local(value={ResourceTagJoinDao.class}) @@ -46,6 +47,9 @@ public class ResourceTagJoinDaoImpl extends GenericDaoBase tagSearch; private final SearchBuilder tagIdSearch; + + private final SearchBuilder AllFieldsSearch; + protected ResourceTagJoinDaoImpl() { @@ -58,12 +62,14 @@ public class ResourceTagJoinDaoImpl extends GenericDaoBase listBy(String resourceUUID, TaggedResourceType resourceType) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("uuid", resourceUUID); + sc.setParameters("resourceType", resourceType); + return listBy(sc); + } @Override diff --git a/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java index 945e67b406b..8c32be3d13d 100644 --- a/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/ServiceOfferingJoinDaoImpl.java @@ -17,22 +17,22 @@ package com.cloud.api.query.dao; import java.util.List; -import java.util.Map; import javax.ejb.Local; +import org.apache.cloudstack.api.response.ResourceTagResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.ServiceOfferingJoinVO; -import org.apache.cloudstack.api.response.ServiceOfferingResponse; - import com.cloud.offering.ServiceOffering; -import com.cloud.offering.NetworkOffering.Detail; +import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import org.springframework.stereotype.Component; @Component @Local(value={ServiceOfferingJoinDao.class}) @@ -48,7 +48,7 @@ public class ServiceOfferingJoinDaoImpl extends GenericDaoBase resourceTags = ApiDBUtils.listResourceTagViewByResourceUUID(offering.getUuid(), TaggedResourceType.ServiceOffering); + for (ResourceTagJoinVO resourceTag : resourceTags) { + ResourceTagResponse tagResponse = ApiDBUtils.newResourceTagResponse(resourceTag, false); + offeringResponse.addTag(tagResponse); } return offeringResponse; } diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java index 795a9706478..79aba6340d9 100644 --- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java +++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java @@ -25,16 +25,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.vm.dao.NicDao; -import com.cloud.network.vpc.NetworkACLItemDao; - +import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.context.CallContext; - import com.cloud.api.query.dao.ResourceTagJoinDao; +import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.Domain; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; @@ -47,12 +43,14 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.security.dao.SecurityGroupDao; +import com.cloud.network.vpc.NetworkACLItemDao; import com.cloud.network.vpc.dao.StaticRouteDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.projects.dao.ProjectDao; import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.server.TaggedResourceService; +import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; @@ -70,6 +68,7 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.uuididentity.dao.IdentityDao; +import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @@ -128,6 +127,8 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso NetworkACLItemDao _networkACLItemDao; @Inject DataCenterDao _dataCenterDao; + @Inject + ServiceOfferingDao _serviceOffDao; @Override @@ -151,6 +152,7 @@ public class TaggedResourceManagerImpl extends ManagerBase implements TaggedReso _daoMap.put(TaggedResourceType.VMSnapshot, _vmSnapshotDao); _daoMap.put(TaggedResourceType.RemoteAccessVpn, _vpnDao); _daoMap.put(TaggedResourceType.Zone, _dataCenterDao); + _daoMap.put(TaggedResourceType.ServiceOffering, _serviceOffDao); return true; } diff --git a/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java b/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java index c6fd8c17c9c..18b7d8be186 100644 --- a/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java +++ b/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java @@ -110,7 +110,9 @@ public class IdentityDaoImpl extends GenericDaoBase implements pstmt.setLong(1, identityId); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { - domainId = rs.getLong(1); + if (rs.getLong(1) != 0) { + domainId = rs.getLong(1); + } } } catch (SQLException e) { } @@ -125,7 +127,9 @@ public class IdentityDaoImpl extends GenericDaoBase implements pstmt.setLong(1, identityId); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { - accountId = rs.getLong(1); + if (rs.getLong(1) != 0) { + accountId = rs.getLong(1); + } } } catch (SQLException e) { }