diff --git a/api/src/com/cloud/server/ResourceMetaDataService.java b/api/src/com/cloud/server/ResourceMetaDataService.java index 56fe1045ab3..113dc0703b3 100644 --- a/api/src/com/cloud/server/ResourceMetaDataService.java +++ b/api/src/com/cloud/server/ResourceMetaDataService.java @@ -46,6 +46,16 @@ public interface ResourceMetaDataService { ResourceDetail getDetail(long resourceId, ResourceObjectType resourceType, String key); + /** + * List by key, value pair + * @param resourceType + * @param key + * @param value + * @param forDisplay + * @return + */ + List getDetails(ResourceObjectType resourceType, String key, String value, Boolean forDisplay); + Map getDetailsMap(long resourceId, ResourceObjectType resourceType, Boolean forDisplay); List getDetailsList(long resourceId, ResourceObjectType resourceType, Boolean forDisplay); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java index afbfb990fdf..83cb1fff901 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListResourceDetailsCmd.java @@ -44,6 +44,10 @@ public class ListResourceDetailsCmd extends BaseListProjectAndAccountResourcesCm @Parameter(name = ApiConstants.KEY, type = CommandType.STRING, description = "list by key") private String key; + @Parameter(name = ApiConstants.VALUE, type = CommandType.STRING, description = "list by key, value. Needs to be passed only along with key" , + since = "4.4", authorized = { RoleType.Admin }) + private String value; + @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "if set to true, only details marked with display=true, are returned." + " False by default", since = "4.3", authorized = { RoleType.Admin }) private Boolean forDisplay; @@ -56,6 +60,10 @@ public class ListResourceDetailsCmd extends BaseListProjectAndAccountResourcesCm return key; } + public String getValue() { + return value; + } + @Override public String getCommandName() { return s_name; diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java index 50026837915..5d2d919a685 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDao.java @@ -32,6 +32,15 @@ public interface ResourceDetailsDao extends GenericDao */ public R findDetail(long resourceId, String name); + /** + * Find details by key,value pair + * @param key + * @param value + * @param display + * @return + */ + public List findDetails(String key, String value, Boolean display); + /** * Removes all details for the resource specified * @param resourceId diff --git a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java index 60d7f162f2f..b3e7ea27587 100644 --- a/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java +++ b/engine/schema/src/org/apache/cloudstack/resourcedetail/ResourceDetailsDaoBase.java @@ -34,6 +34,7 @@ public abstract class ResourceDetailsDaoBase extends G AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), SearchCriteria.Op.EQ); AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("value", AllFieldsSearch.entity().getValue(), SearchCriteria.Op.EQ); // FIXME SnapshotDetailsVO doesn't have a display field if (_allAttributes.containsKey("display")) { AllFieldsSearch.and("display", AllFieldsSearch.entity().isDisplay(), SearchCriteria.Op.EQ); @@ -49,6 +50,25 @@ public abstract class ResourceDetailsDaoBase extends G return findOneBy(sc); } + public List findDetails(String name, String value, Boolean display) { + SearchCriteria sc = AllFieldsSearch.create(); + + if(display != null){ + sc.setParameters("display", display); + } + + if(name != null){ + sc.setParameters("name", name); + } + + if(value != null){ + sc.setParameters("value", value); + } + + List results = search(sc, null); + return results; + } + public Map listDetailsKeyPairs(long resourceId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("resourceId", resourceId); diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 6848ba03fe7..a2437b8900d 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -3895,23 +3895,40 @@ public class QueryManagerImpl extends ManagerBase implements QueryService { Boolean forDisplay = cmd.getDisplay(); ResourceTag.ResourceObjectType resourceType = cmd.getResourceType(); String resourceIdStr = cmd.getResourceId(); + String value = cmd.getValue(); Long resourceId = null; + + //Validation - 1.1 - resourceId and value cant be null. + if(resourceIdStr == null && value == null){ + throw new InvalidParameterValueException("Insufficient parameters passed for listing by resourceId OR key,value pair. Please check your params and try again."); + } + + //Validation - 1.2 - Value has to be passed along with key. + if(value != null && key == null){ + throw new InvalidParameterValueException("Listing by (key, value) but key is null. Please check the params and try again"); + } + + //Validation - 1.3 if (resourceIdStr != null) { resourceId = _taggedResourceMgr.getResourceId(resourceIdStr, resourceType); + if (resourceId == null) { + throw new InvalidParameterValueException("Cannot find resource with resourceId " + resourceIdStr + " and of resource type " + resourceType); + } } - if (resourceId == null) { - throw new InvalidParameterValueException("Cannot find resource with resourceId " + resourceIdStr + " and of resource type " + resourceType); - } + + List detailList = new ArrayList(); ResourceDetail requestedDetail = null; if (key == null) { detailList = _resourceMetaDataMgr.getDetailsList(resourceId, resourceType, forDisplay); - } else { + } else if (value == null){ requestedDetail = _resourceMetaDataMgr.getDetail(resourceId, resourceType, key); if (requestedDetail != null && forDisplay != null && requestedDetail.isDisplay() != forDisplay) { requestedDetail = null; } + }else { + detailList = _resourceMetaDataMgr.getDetails(resourceType, key, value, forDisplay); } List responseList = new ArrayList(); diff --git a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java index f7b092c5bd4..6f1f40d6480 100644 --- a/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java +++ b/server/src/com/cloud/metadata/ResourceMetaDataManagerImpl.java @@ -224,6 +224,10 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource return dao.findDetail(resourceId, key); } + private List getDetails(String key, String value, Boolean forDisplay) { + return dao.findDetails(key, value, forDisplay); + } + private void addDetail(long resourceId, String key, String value, boolean forDisplay) { dao.addDetail(resourceId, key, value, forDisplay); } @@ -257,6 +261,12 @@ public class ResourceMetaDataManagerImpl extends ManagerBase implements Resource return newDetailDaoHelper.getDetail(resourceId, key); } + @Override + public List getDetails(ResourceObjectType resourceType, String key, String value, Boolean forDisplay){ + DetailDaoHelper newDetailDaoHelper = new DetailDaoHelper(resourceType); + return newDetailDaoHelper.getDetails(key, value, forDisplay); + } + @Override public Map getDetailsMap(long resourceId, ResourceObjectType resourceType, Boolean forDisplay) { DetailDaoHelper newDetailDaoHelper = new DetailDaoHelper(resourceType);