From c40839599cfee7549198c12192e4f8d747b31c5d Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Wed, 6 Jun 2012 17:21:38 -0700 Subject: [PATCH] Initial checkin for resource tags feature --- api/src/com/cloud/api/ApiConstants.java | 2 + api/src/com/cloud/api/BaseCmd.java | 3 + api/src/com/cloud/api/ResponseGenerator.java | 10 + .../com/cloud/api/commands/CreateTagsCmd.java | 123 +++++++++ .../com/cloud/api/commands/ListTagsCmd.java | 87 ++++++ .../api/response/ResourceTagResponse.java | 94 +++++++ api/src/com/cloud/configuration/Resource.java | 16 ++ api/src/com/cloud/event/EventTypes.java | 5 + api/src/com/cloud/server/ResourceTag.java | 48 ++++ .../cloud/server/TaggedResourceService.java | 49 ++++ client/tomcatconf/commands.properties.in | 7 +- server/src/com/cloud/api/ApiDBUtils.java | 13 +- .../src/com/cloud/api/ApiResponseHelper.java | 42 ++- .../DefaultComponentLibrary.java | 14 +- server/src/com/cloud/tags/ResourceTagVO.java | 139 ++++++++++ .../cloud/tags/TaggedResourceManagerImpl.java | 251 ++++++++++++++++++ .../com/cloud/tags/dao/ResourceTagDao.java | 23 ++ .../cloud/tags/dao/ResourceTagsDaoImpl.java | 29 ++ .../cloud/uuididentity/dao/IdentityDao.java | 9 +- .../uuididentity/dao/IdentityDaoImpl.java | 66 +++-- setup/db/create-schema.sql | 18 ++ wscript | 1 + 22 files changed, 1020 insertions(+), 29 deletions(-) create mode 100644 api/src/com/cloud/api/commands/CreateTagsCmd.java create mode 100644 api/src/com/cloud/api/commands/ListTagsCmd.java create mode 100644 api/src/com/cloud/api/response/ResourceTagResponse.java create mode 100644 api/src/com/cloud/server/ResourceTag.java create mode 100644 api/src/com/cloud/server/TaggedResourceService.java create mode 100644 server/src/com/cloud/tags/ResourceTagVO.java create mode 100644 server/src/com/cloud/tags/TaggedResourceManagerImpl.java create mode 100644 server/src/com/cloud/tags/dao/ResourceTagDao.java create mode 100644 server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index d9d31cd1a5a..a936db5d669 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -353,6 +353,8 @@ public class ApiConstants { public static final String VSM_DEVICE_STATE = "vsmdevicestate"; public static final String INCL_ZONES = "includezones"; public static final String EXCL_ZONES = "excludezones"; + public static final String RESOURCE_IDS = "resourceids"; + public static final String RESOURCE_ID = "resourceid"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index d88ce7b6fe3..4110d19733c 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -45,6 +45,7 @@ import com.cloud.projects.Project; import com.cloud.projects.ProjectService; import com.cloud.resource.ResourceService; import com.cloud.server.ManagementService; +import com.cloud.server.TaggedResourceService; import com.cloud.storage.StorageService; import com.cloud.storage.snapshot.SnapshotService; import com.cloud.template.TemplateService; @@ -123,6 +124,7 @@ public abstract class BaseCmd { public static ResourceLimitService _resourceLimitService; public static IdentityService _identityService; public static StorageNetworkService _storageNetworkService; + public static TaggedResourceService _taggedResourceService; static void setComponents(ResponseGenerator generator) { ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); @@ -150,6 +152,7 @@ public abstract class BaseCmd { _resourceLimitService = locator.getManager(ResourceLimitService.class); _identityService = locator.getManager(IdentityService.class); _storageNetworkService = locator.getManager(StorageNetworkService.class); + _taggedResourceService = locator.getManager(TaggedResourceService.class); } public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; diff --git a/api/src/com/cloud/api/ResponseGenerator.java b/api/src/com/cloud/api/ResponseGenerator.java index 9bf0a1cc1e7..009b3c8fe3b 100755 --- a/api/src/com/cloud/api/ResponseGenerator.java +++ b/api/src/com/cloud/api/ResponseGenerator.java @@ -52,6 +52,7 @@ import com.cloud.api.response.ProviderResponse; import com.cloud.api.response.RemoteAccessVpnResponse; import com.cloud.api.response.ResourceCountResponse; import com.cloud.api.response.ResourceLimitResponse; +import com.cloud.api.response.ResourceTagResponse; import com.cloud.api.response.SecurityGroupResponse; import com.cloud.api.response.ServiceOfferingResponse; import com.cloud.api.response.ServiceResponse; @@ -110,6 +111,7 @@ import com.cloud.org.Cluster; import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; +import com.cloud.server.ResourceTag; import com.cloud.storage.Snapshot; import com.cloud.storage.StoragePool; import com.cloud.storage.Swift; @@ -276,4 +278,12 @@ public interface ResponseGenerator { * @return */ Long getIdentiyId(String tableName, String token); + + /** + * @param resourceTag + * @return + */ + ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag); + + } diff --git a/api/src/com/cloud/api/commands/CreateTagsCmd.java b/api/src/com/cloud/api/commands/CreateTagsCmd.java new file mode 100644 index 00000000000..c0ac9742a26 --- /dev/null +++ b/api/src/com/cloud/api/commands/CreateTagsCmd.java @@ -0,0 +1,123 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.api.commands; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.SuccessResponse; +import com.cloud.configuration.Resource; +import com.cloud.event.EventTypes; +import com.cloud.server.ResourceTag; + +/** + * @author Alena Prokharchyk + */ + +@Implementation(description = "Creates resource tag(s)", responseObject = SuccessResponse.class, since = "Burbank") +public class CreateTagsCmd extends BaseAsyncCmd{ + public static final Logger s_logger = Logger.getLogger(CreateTagsCmd.class.getName()); + + private static final String s_name = "createtagsresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.TAGS, type = CommandType.MAP, required=true, description = "Map of tags (key/value pairs)") + private Map tag; + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, required=true, description="type of the resource") + private String resourceType; + + @Parameter(name=ApiConstants.RESOURCE_IDS, type=CommandType.LIST, required=true, + collectionType=CommandType.STRING, description="list of resources to create the tags for") + private List resourceIds; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public Resource.TaggedResourceType getResourceType(){ + return _taggedResourceService.getResourceType(resourceType); + } + + public Map getTags() { + Map tagsMap = null; + if (!tag.isEmpty()) { + tagsMap = new HashMap(); + Collection servicesCollection = tag.values(); + Iterator iter = servicesCollection.iterator(); + while (iter.hasNext()) { + HashMap services = (HashMap) iter.next(); + String key = services.get("key"); + String value = services.get("value"); + tagsMap.put(key, value); + } + } + return tagsMap; + } + + public List getResourceIds() { + return resourceIds; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + //FIXME - validate the owner here + return 1; + } + + @Override + public void execute() { + List tags = _taggedResourceService.createTags(getResourceIds(), getResourceType(), getTags()); + + if (tags != null && !tags.isEmpty()) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to create tags"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_TAGS_CREATE; + } + + @Override + public String getEventDescription() { + return "creating tags"; + } +} diff --git a/api/src/com/cloud/api/commands/ListTagsCmd.java b/api/src/com/cloud/api/commands/ListTagsCmd.java new file mode 100644 index 00000000000..80e2a2a9fde --- /dev/null +++ b/api/src/com/cloud/api/commands/ListTagsCmd.java @@ -0,0 +1,87 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseListProjectAndAccountResourcesCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.response.ListResponse; +import com.cloud.api.response.ResourceTagResponse; +import com.cloud.server.ResourceTag; + +/** + * @author Alena Prokharchyk + */ + +@Implementation(description = "List resource tag(s)", responseObject = ResourceTagResponse.class, since = "Burbank") +public class ListTagsCmd extends BaseListProjectAndAccountResourcesCmd{ + private static final String s_name = "listtagsresponse"; + + @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.STRING, description="list by resource type") + private String resourceType; + + @Parameter(name=ApiConstants.RESOURCE_ID, type=CommandType.STRING, description="list by resource id") + private String resourceId; + + @Parameter(name=ApiConstants.KEY, type=CommandType.STRING, description="list by key") + private String key; + + @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, description="list by value") + private String value; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() { + + List tags = _taggedResourceService.listTags(this); + ListResponse response = new ListResponse(); + List tagResponses = new ArrayList(); + for (ResourceTag tag : tags) { + ResourceTagResponse tagResponse = _responseGenerator.createResourceTagResponse(tag); + tagResponses.add(tagResponse); + } + response.setResponses(tagResponses); + + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + + public String getResourceType() { + return resourceType; + } + + public String getResourceId() { + return resourceId; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + + @Override + public String getCommandName() { + return s_name; + } +} diff --git a/api/src/com/cloud/api/response/ResourceTagResponse.java b/api/src/com/cloud/api/response/ResourceTagResponse.java new file mode 100644 index 00000000000..fc8d43c7b60 --- /dev/null +++ b/api/src/com/cloud/api/response/ResourceTagResponse.java @@ -0,0 +1,94 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.api.response; + +import com.cloud.api.ApiConstants; +import com.cloud.serializer.Param; +import com.cloud.utils.IdentityProxy; +import com.google.gson.annotations.SerializedName; + +/** + * @author Alena Prokharchyk + */ + +@SuppressWarnings("unused") +public class ResourceTagResponse extends BaseResponse implements ControlledEntityResponse{ + @SerializedName(ApiConstants.KEY) @Param(description="tag key name") + private String key; + + @SerializedName(ApiConstants.VALUE) @Param(description="tag value") + private String value; + + @SerializedName(ApiConstants.RESOURCE_TYPE) @Param(description="resource type") + private String resourceType; + + @SerializedName(ApiConstants.RESOURCE_ID) @Param(description="id of the resource") + private String id; + + @SerializedName(ApiConstants.ACCOUNT) + @Param(description = "the account associated with the tag") + private String accountName; + + @SerializedName(ApiConstants.PROJECT_ID) @Param(description="the project id the tag belongs to") + private IdentityProxy projectId = new IdentityProxy("projects"); + + @SerializedName(ApiConstants.PROJECT) @Param(description="the project name where tag belongs to") + private String projectName; + + @SerializedName(ApiConstants.DOMAIN_ID) + @Param(description = "the ID of the domain associated with the tag") + private IdentityProxy domainId = new IdentityProxy("domain"); + + @SerializedName(ApiConstants.DOMAIN) + @Param(description = "the domain associated with the tag") + private String domainName; + + public void setKey(String key) { + this.key = key; + } + + public void setValue(String value) { + this.value = value; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public void setId(String id) { + this.id = id; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(Long domainId) { + this.domainId.setValue(domainId); + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + @Override + public void setProjectId(Long projectId) { + this.projectId.setValue(projectId); + } + + @Override + public void setProjectName(String projectName) { + this.projectName = projectName; + } + +} diff --git a/api/src/com/cloud/configuration/Resource.java b/api/src/com/cloud/configuration/Resource.java index 4c50f1e58c6..3f56369bf40 100644 --- a/api/src/com/cloud/configuration/Resource.java +++ b/api/src/com/cloud/configuration/Resource.java @@ -15,6 +15,22 @@ package com.cloud.configuration; public interface Resource { public static final short RESOURCE_UNLIMITED = -1; + + public enum TaggedResourceType { + UserVm, + Template, + ISO, + Volume, + Snapshot, + Network, + LoadBalancingRule, + PortForwardingRule, + FirewallRule, + SecurityGroup, + RemoteAccessVpn, + PublicIpAdddress, + SecondaryStorageVm + } public enum ResourceType { user_vm("user_vm", 0, ResourceOwnerType.Account, ResourceOwnerType.Domain), diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index eedf5462400..4c3e05371fc 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -255,4 +255,9 @@ public class EventTypes { public static final String EVENT_EXTERNAL_FIREWALL_DEVICE_ADD = "PHYSICAL.FIREWALL.ADD"; public static final String EVENT_EXTERNAL_FIREWALL_DEVICE_DELETE = "PHYSICAL.FIREWALL.DELETE"; public static final String EVENT_EXTERNAL_FIREWALL_DEVICE_CONFIGURE = "PHYSICAL.FIREWALL.CONFIGURE"; + + // tag related events + public static final String EVENT_TAGS_CREATE = "CREATE_TAGS"; + public static final String EVENT_TAGS_DELETE = "DELETE_TAGS"; + } diff --git a/api/src/com/cloud/server/ResourceTag.java b/api/src/com/cloud/server/ResourceTag.java new file mode 100644 index 00000000000..050c8c8b94b --- /dev/null +++ b/api/src/com/cloud/server/ResourceTag.java @@ -0,0 +1,48 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.server; + +import com.cloud.acl.ControlledEntity; +import com.cloud.configuration.Resource; + +/** + * @author Alena Prokharchyk + */ +public interface ResourceTag extends ControlledEntity{ + + /** + * @return + */ + long getId(); + + /** + * @return + */ + String getKey(); + + /** + * @return + */ + String getValue(); + + /** + * @return + */ + long getResourceId(); + + /** + * @return + */ + Resource.TaggedResourceType getResourceType(); + +} diff --git a/api/src/com/cloud/server/TaggedResourceService.java b/api/src/com/cloud/server/TaggedResourceService.java new file mode 100644 index 00000000000..9a4bd326b4b --- /dev/null +++ b/api/src/com/cloud/server/TaggedResourceService.java @@ -0,0 +1,49 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.server; + +import java.util.List; +import java.util.Map; + +import com.cloud.api.commands.ListTagsCmd; +import com.cloud.configuration.Resource; +import com.cloud.configuration.Resource.TaggedResourceType; + +/** + * @author Alena Prokharchyk + */ +public interface TaggedResourceService { + + Resource.TaggedResourceType getResourceType (String resourceTypeStr); + + /** + * @param resourceIds TODO + * @param resourceType + * @param tags + * @return + */ + List createTags(List resourceIds, TaggedResourceType resourceType, Map tags); + + /** + * @param resourceId + * @param resourceType + * @return + */ + String getUuid(String resourceId, TaggedResourceType resourceType); + + /** + * @param listTagsCmd + * @return + */ + List listTags(ListTagsCmd listTagsCmd); +} diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 3a3571895e0..fb1f236dfe6 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -328,7 +328,12 @@ deleteStorageNetworkIpRange=com.cloud.api.commands.DeleteStorageNetworkIpRangeCm listStorageNetworkIpRange=com.cloud.api.commands.listStorageNetworkIpRangeCmd;1 updateStorageNetworkIpRange=com.cloud.api.commands.UpdateStorageNetworkIpRangeCmd;1 -### Network Devices commands +#### Network Devices commands addNetworkDevice=com.cloud.api.commands.AddNetworkDeviceCmd;1 listNetworkDevice=com.cloud.api.commands.ListNetworkDeviceCmd;1 deleteNetworkDevice=com.cloud.api.commands.DeleteNetworkDeviceCmd;1 + +#### Tags commands +createTags=com.cloud.api.commands.CreateTagsCmd;15 +deleteTags=com.cloud.api.commands.DeleteTagsCmd;15 +listTags=com.cloud.api.commands.ListTagsCmd;15 diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index f4948860183..d595dc5d9fc 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -25,6 +25,7 @@ import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationService; import com.cloud.configuration.Resource.ResourceType; +import com.cloud.configuration.Resource.TaggedResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.AccountVlanMapVO; import com.cloud.dc.ClusterVO; @@ -77,6 +78,7 @@ import com.cloud.resource.ResourceManager; import com.cloud.server.Criteria; import com.cloud.server.ManagementServer; import com.cloud.server.StatsCollector; +import com.cloud.server.TaggedResourceService; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; @@ -84,6 +86,7 @@ import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageStats; @@ -91,9 +94,8 @@ import com.cloud.storage.UploadVO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateSwiftVO; import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VolumeHostVO; -import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeHostVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -188,6 +190,7 @@ public class ApiDBUtils { private static AccountDetailsDao _accountDetailsDao; private static NetworkDomainDao _networkDomainDao; private static HighAvailabilityManager _haMgr; + private static TaggedResourceService _taggedResourceService; static { _ms = (ManagementServer) ComponentLocator.getComponent(ManagementServer.Name); @@ -241,6 +244,7 @@ public class ApiDBUtils { _accountDetailsDao = locator.getDao(AccountDetailsDao.class); _networkDomainDao = locator.getDao(NetworkDomainDao.class); _haMgr = locator.getManager(HighAvailabilityManager.class); + _taggedResourceService = locator.getManager(TaggedResourceService.class); // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned _statsCollector = StatsCollector.getInstance(); @@ -748,4 +752,9 @@ public class ApiDBUtils { public static String getHaTag() { return _haMgr.getHaTag(); } + + public static String getUuid(String resourceId, TaggedResourceType resourceType) { + return _taggedResourceService.getUuid(resourceId, resourceType); + } + } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 73a9f927e03..945960d91d6 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -70,6 +70,7 @@ import com.cloud.api.response.ProviderResponse; import com.cloud.api.response.RemoteAccessVpnResponse; import com.cloud.api.response.ResourceCountResponse; import com.cloud.api.response.ResourceLimitResponse; +import com.cloud.api.response.ResourceTagResponse; import com.cloud.api.response.SecurityGroupResponse; import com.cloud.api.response.SecurityGroupResultObject; import com.cloud.api.response.SecurityGroupRuleResponse; @@ -151,6 +152,7 @@ import com.cloud.projects.Project; import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.server.Criteria; +import com.cloud.server.ResourceTag; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOSCategoryVO; @@ -2306,10 +2308,11 @@ public class ApiResponseHelper implements ResponseGenerator { boolean savedValue = SerializationContext.current().getUuidTranslation(); SerializationContext.current().setUuidTranslation(false); - jobResponse.setJobResult((ResponseObject) ApiSerializerHelper.fromSerializedString(job.getResult())); - SerializationContext.current().setUuidTranslation(savedValue); - + Object resultObject = ApiSerializerHelper.fromSerializedString(job.getResult()); + jobResponse.setJobResult((ResponseObject) resultObject); + SerializationContext.current().setUuidTranslation(savedValue); + if (resultObject != null) { Class clz = resultObject.getClass(); if (clz.isPrimitive() || clz.getSuperclass() == Number.class || clz == String.class || clz == Date.class) { @@ -3399,5 +3402,38 @@ public class ApiResponseHelper implements ResponseGenerator { public Long getIdentiyId(String tableName, String token) { return ApiDispatcher.getIdentiyId(tableName, token); } + + @Override + public ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag) { + ResourceTagResponse response = new ResourceTagResponse(); + response.setKey(resourceTag.getKey()); + response.setValue(resourceTag.getValue()); + response.setResourceType(resourceTag.getResourceType().toString()); + response.setId(ApiDBUtils.getUuid(String.valueOf(resourceTag.getResourceId()),resourceTag.getResourceType())); + Long accountId = resourceTag.getAccountId(); + Long domainId = resourceTag.getDomainId(); + if (accountId != null) { + Account account = ApiDBUtils.findAccountByIdIncludingRemoved(resourceTag.getAccountId()); + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + // find the project + Project project = ApiDBUtils.findProjectByProjectAccountId(account.getId()); + response.setProjectId(project.getId()); + response.setProjectName(project.getName()); + } else { + response.setAccountName(account.getAccountName()); + } + } + + if (domainId != null) { + response.setDomainId(domainId); + response.setDomainName(ApiDBUtils.findDomainById(domainId).getName()); + } + + response.setObjectName("tag"); + + return response; + } + + } diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index f9d74ceaa72..16cc1324f9f 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -45,6 +45,7 @@ import com.cloud.dao.EntityManagerImpl; import com.cloud.dc.ClusterDetailsDaoImpl; import com.cloud.dc.dao.AccountVlanMapDaoImpl; import com.cloud.dc.dao.ClusterDaoImpl; +import com.cloud.dc.dao.ClusterVSMMapDaoImpl; import com.cloud.dc.dao.DataCenterDaoImpl; import com.cloud.dc.dao.DataCenterIpAddressDaoImpl; import com.cloud.dc.dao.DcDetailsDaoImpl; @@ -70,11 +71,9 @@ import com.cloud.maint.dao.AgentUpgradeDaoImpl; import com.cloud.network.ExternalLoadBalancerUsageManagerImpl; import com.cloud.network.NetworkManagerImpl; import com.cloud.network.StorageNetworkManagerImpl; +import com.cloud.network.dao.CiscoNexusVSMDeviceDaoImpl; import com.cloud.network.dao.ExternalFirewallDeviceDaoImpl; import com.cloud.network.dao.ExternalLoadBalancerDeviceDaoImpl; -import com.cloud.network.dao.CiscoNexusVSMDeviceDaoImpl; -import com.cloud.dc.dao.ClusterVSMMapDaoImpl; -import com.cloud.network.dao.PortProfileDaoImpl; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; import com.cloud.network.dao.FirewallRulesDaoImpl; import com.cloud.network.dao.IPAddressDaoImpl; @@ -91,16 +90,17 @@ import com.cloud.network.dao.NetworkServiceMapDaoImpl; import com.cloud.network.dao.PhysicalNetworkDaoImpl; import com.cloud.network.dao.PhysicalNetworkServiceProviderDaoImpl; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDaoImpl; +import com.cloud.network.dao.PortProfileDaoImpl; import com.cloud.network.dao.RemoteAccessVpnDaoImpl; import com.cloud.network.dao.VirtualRouterProviderDaoImpl; import com.cloud.network.dao.VpnUserDaoImpl; +import com.cloud.network.element.CiscoNexusVSMElement; +import com.cloud.network.element.CiscoNexusVSMElementService; import com.cloud.network.element.F5ExternalLoadBalancerElement; import com.cloud.network.element.F5ExternalLoadBalancerElementService; import com.cloud.network.element.JuniperSRXExternalFirewallElement; import com.cloud.network.element.JuniperSRXFirewallElementService; import com.cloud.network.element.NetscalerElement; -import com.cloud.network.element.CiscoNexusVSMElement; -import com.cloud.network.element.CiscoNexusVSMElementService; import com.cloud.network.element.NetscalerLoadBalancerElementService; import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VirtualRouterElementService; @@ -159,6 +159,8 @@ import com.cloud.storage.snapshot.SnapshotManagerImpl; import com.cloud.storage.snapshot.SnapshotSchedulerImpl; import com.cloud.storage.swift.SwiftManagerImpl; import com.cloud.storage.upload.UploadMonitorImpl; +import com.cloud.tags.TaggedResourceManagerImpl; +import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.template.HyervisorTemplateAdapter; import com.cloud.template.TemplateAdapter; import com.cloud.template.TemplateAdapter.TemplateAdapterType; @@ -327,6 +329,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addDao("NetworkServiceMapDao", NetworkServiceMapDaoImpl.class); addDao("StorageNetworkIpAddressDao", StorageNetworkIpAddressDaoImpl.class); addDao("StorageNetworkIpRangeDao", StorageNetworkIpRangeDaoImpl.class); + addDao("TagsDao", ResourceTagsDaoImpl.class); } @Override @@ -383,6 +386,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addManager("StorageNetworkManager", StorageNetworkManagerImpl.class); addManager("ExternalLoadBalancerUsageManager", ExternalLoadBalancerUsageManagerImpl.class); addManager("HA Manager", HighAvailabilityManagerImpl.class); + addManager("TaggedResourcesManager", TaggedResourceManagerImpl.class); } @Override diff --git a/server/src/com/cloud/tags/ResourceTagVO.java b/server/src/com/cloud/tags/ResourceTagVO.java new file mode 100644 index 00000000000..74786ba2d9f --- /dev/null +++ b/server/src/com/cloud/tags/ResourceTagVO.java @@ -0,0 +1,139 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.tags; + +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.api.Identity; +import com.cloud.configuration.Resource; +import com.cloud.configuration.Resource.TaggedResourceType; +import com.cloud.server.ResourceTag; + +/** + * @author Alena Prokharchyk + */ + +@Entity +@Table(name="resource_tags") +public class ResourceTagVO implements Identity, ResourceTag{ + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="key") + private String key; + + @Column(name="value") + String value; + + @Column(name="domain_id") + long domainId; + + @Column(name="account_id") + long accountId; + + @Column(name="resource_id") + long resourceId; + + @Column(name="resource_type") + @Enumerated(value=EnumType.STRING) + private Resource.TaggedResourceType resourceType; + + + protected ResourceTagVO(){ + this.uuid = UUID.randomUUID().toString(); + } + + /** + * @param key + * @param value + * @param accountId + * @param domainId + * @param resourceId + * @param resourceType + */ + public ResourceTagVO(String key, String value, long accountId, long domainId, long resourceId, TaggedResourceType resourceType) { + super(); + this.key = key; + this.value = value; + this.domainId = domainId; + this.accountId = accountId; + this.resourceId = resourceId; + this.resourceType = resourceType; + this.uuid = UUID.randomUUID().toString(); + } + + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("Tag["); + buf.append(id).append("|key=").append(key).append("|value=").append(domainId).append("|value="). + append("|resourceType=").append(resourceType).append("|resourceId=").append(resourceId) + .append("|accountId=").append(accountId).append("]"); + return buf.toString(); + } + + @Override + public long getId() { + return id; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getValue() { + return value; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public long getResourceId() { + return resourceId; + } + + @Override + public Resource.TaggedResourceType getResourceType() { + return resourceType; + } + + @Override + public String getUuid() { + return uuid; + } +} diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java new file mode 100644 index 00000000000..7e442a91fcf --- /dev/null +++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java @@ -0,0 +1,251 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.tags; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.api.commands.ListTagsCmd; +import com.cloud.configuration.Resource; +import com.cloud.configuration.Resource.TaggedResourceType; +import com.cloud.domain.Domain; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.server.ResourceTag; +import com.cloud.server.TaggedResourceService; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.UserContext; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.Inject; +import com.cloud.utils.component.Manager; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.DbUtil; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.uuididentity.dao.IdentityDao; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.UserVmDao; + +/** + * @author Alena Prokharchyk + */ +@Local(value = { TaggedResourceService.class}) +public class TaggedResourceManagerImpl implements TaggedResourceService, Manager{ + public static final Logger s_logger = Logger.getLogger(TaggedResourceManagerImpl.class); + private String _name; + + private static Map _resourceMap= + new HashMap(); + + private static Map> _daoMap= + new HashMap>(); + + @Inject + AccountManager _accountMgr; + @Inject + ResourceTagDao _resourceTagDao; + @Inject + IdentityDao _identityDao; + @Inject + DomainManager _domainMgr; + @Inject + UserVmDao _userVmDao; + + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + _resourceMap.put(TaggedResourceType.UserVm, DbUtil.getTableName(VMInstanceVO.class)); + _daoMap.put(TaggedResourceType.UserVm, _userVmDao); + + + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + + private Long getResourceId(String resourceId, Resource.TaggedResourceType resourceType) { + String tableName = _resourceMap.get(resourceType); + + if (tableName == null) { + throw new InvalidParameterValueException("Unable to find resource of type " + resourceType + " in the database"); + } + + return _identityDao.getIdentityId(tableName, resourceId); + } + + private Pair getAccountDomain(long resourceId, Resource.TaggedResourceType resourceType) { + String tableName = _resourceMap.get(resourceType); + + if (tableName == null) { + throw new InvalidParameterValueException("Unable to find resource of type " + resourceType + " in the database"); + } + + Pair pair = _identityDao.getAccountDomainInfo(tableName, resourceId); + Long accountId = pair.first(); + Long domainId = pair.second(); + + if (accountId == null) { + accountId = Account.ACCOUNT_ID_SYSTEM; + } + + if (domainId == null) { + domainId = Domain.ROOT_DOMAIN; + } + + return new Pair(accountId, domainId); + } + + @Override + public TaggedResourceType getResourceType(String resourceTypeStr) { + Resource.TaggedResourceType resourceType = null; + try { + resourceType = Resource.TaggedResourceType.valueOf(resourceTypeStr); + } catch (IllegalArgumentException ex) { + throw new InvalidParameterValueException("Invalid resource type " + resourceType); + } + + return resourceType; + } + + @Override + @DB + public List createTags(List resourceIds, TaggedResourceType resourceType, Map tags) { + Account caller = UserContext.current().getCaller(); + + List resourceTags = new ArrayList(tags.size()); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + for (String tag : tags.keySet()) { + for (String resourceId : resourceIds) { + Long id = getResourceId(resourceId, resourceType); + + //check if object exists + if (_daoMap.get(resourceType).findById(id) == null) { + throw new InvalidParameterValueException("Unable to find resource by id " + resourceId + " and type " + resourceType); + } + + Pair accountDomainPair = getAccountDomain(id, resourceType); + Long domainId = accountDomainPair.second(); + Long accountId = accountDomainPair.first(); + if (accountId != null) { + _accountMgr.checkAccess(caller, null, false, _accountMgr.getAccount(accountId)); + } else if (domainId != null && caller.getType() != Account.ACCOUNT_TYPE_NORMAL) { + //check permissions; + _accountMgr.checkAccess(caller, _domainMgr.getDomain(domainId)); + } else { + throw new PermissionDeniedException("Account " + caller + " doesn't have permissions to create tags" + + " for resource " + tag); + } + + ResourceTagVO resourceTag = new ResourceTagVO(tag, tags.get(tag), accountDomainPair.first(), + accountDomainPair.second(), + id, resourceType); + resourceTag = _resourceTagDao.persist(resourceTag); + resourceTags.add(resourceTag); + + } + } + + txn.commit(); + + return resourceTags; + } + + @Override + public String getUuid(String resourceId, TaggedResourceType resourceType) { + return _identityDao.getIdentityUuid(_resourceMap.get(resourceType), resourceId); + } + + @Override + public List listTags(ListTagsCmd cmd) { + Account caller = UserContext.current().getCaller(); + List permittedAccounts = new ArrayList(); + String key = cmd.getKey(); + String value = cmd.getValue(); + String resourceId = cmd.getResourceId(); + String resourceType = cmd.getResourceType(); + boolean listAll = cmd.listAll(); + + Ternary domainIdRecursiveListProject = + new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); + _accountMgr.buildACLSearchParameters(caller, null, cmd.getAccountName(), + cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, false); + Long domainId = domainIdRecursiveListProject.first(); + Boolean isRecursive = domainIdRecursiveListProject.second(); + ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + Filter searchFilter = new Filter(ResourceTagVO.class, "resourceType", false, cmd.getStartIndex(), cmd.getPageSizeVal()); + + SearchBuilder sb = _resourceTagDao.createSearchBuilder(); + _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + sb.and("key", sb.entity().getKey(), SearchCriteria.Op.EQ); + sb.and("value", sb.entity().getValue(), SearchCriteria.Op.EQ); + sb.and("resourceId", sb.entity().getResourceId(), SearchCriteria.Op.EQ); + sb.and("resourceType", sb.entity().getResourceType(), SearchCriteria.Op.EQ); + + // now set the SC criteria... + SearchCriteria sc = sb.create(); + _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + if (key != null) { + sc.setParameters("key", key); + } + + if (value != null) { + sc.setParameters("value", value); + } + + if (resourceId != null) { + sc.setParameters("resourceId", resourceId); + } + + if (resourceType != null) { + sc.setParameters("resourceType", resourceType); + } + + return _resourceTagDao.search(sc, searchFilter); + } + +} diff --git a/server/src/com/cloud/tags/dao/ResourceTagDao.java b/server/src/com/cloud/tags/dao/ResourceTagDao.java new file mode 100644 index 00000000000..a2d38514188 --- /dev/null +++ b/server/src/com/cloud/tags/dao/ResourceTagDao.java @@ -0,0 +1,23 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.tags.dao; + +import com.cloud.tags.ResourceTagVO; +import com.cloud.utils.db.GenericDao; + +/** + * @author Alena Prokharchyk + */ +public interface ResourceTagDao extends GenericDao{ + +} diff --git a/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java b/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java new file mode 100644 index 00000000000..0285dad8cda --- /dev/null +++ b/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java @@ -0,0 +1,29 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.tags.dao; + +import javax.ejb.Local; + +import com.cloud.tags.ResourceTagVO; +import com.cloud.utils.db.GenericDaoBase; + +/** + * @author Alena Prokharchyk + */ + +@Local(value = { ResourceTagDao.class }) +public class ResourceTagsDaoImpl extends GenericDaoBase implements ResourceTagDao{ + + protected ResourceTagsDaoImpl() { + } +} diff --git a/server/src/com/cloud/uuididentity/dao/IdentityDao.java b/server/src/com/cloud/uuididentity/dao/IdentityDao.java index 3d1b7da341f..f963fcbc476 100644 --- a/server/src/com/cloud/uuididentity/dao/IdentityDao.java +++ b/server/src/com/cloud/uuididentity/dao/IdentityDao.java @@ -13,11 +13,18 @@ package com.cloud.uuididentity.dao; import com.cloud.api.IdentityMapper; +import com.cloud.utils.Pair; import com.cloud.utils.db.GenericDao; public interface IdentityDao extends GenericDao { Long getIdentityId(IdentityMapper mapper, String identityString); Long getIdentityId(String tableName, String identityString); String getIdentityUuid(String tableName, String identityString); - void initializeDefaultUuid(String tableName); + void initializeDefaultUuid(String tableName); + /** + * @param tableName + * @param identityId + * @return + */ + Pair getAccountDomainInfo(String tableName, Long identityId); } diff --git a/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java b/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java index e0c0ccc4da5..219ed90e28b 100644 --- a/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java +++ b/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java @@ -12,22 +12,23 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.uuididentity.dao; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import javax.ejb.Local; - -import org.apache.log4j.Logger; - -import com.cloud.api.IdentityMapper; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.Transaction; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.api.IdentityMapper; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.Pair; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.Transaction; @Local(value={IdentityDao.class}) public class IdentityDaoImpl extends GenericDaoBase implements IdentityDao { @@ -85,9 +86,40 @@ public class IdentityDaoImpl extends GenericDaoBase implements txn.close(); } return null; + } + + @DB + @Override + public Pair getAccountDomainInfo(String tableName, Long identityId) { + assert(tableName != null); + + PreparedStatement pstmt = null; + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + try { + pstmt = txn.prepareAutoCloseStatement( + String.format("SELECT account_id, domain_id FROM `%s` WHERE id=?", tableName) + ); + + pstmt.setLong(1, identityId); + + ResultSet rs = pstmt.executeQuery(); + if(rs.next()) { + return new Pair(rs.getLong(1), rs.getLong(2)); + } else { + throw new InvalidParameterValueException("Object " + tableName + "(id: " + identityId + ") does not exist."); + } + } catch (SQLException e) { + s_logger.error("Unexpected exception ", e); + } + } finally { + txn.close(); + } + return null; } - @DB + @DB + @Override public String getIdentityUuid(String tableName, String identityString) { assert(tableName != null); assert(identityString != null); diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index d7cd2d64549..3e0701be767 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -2123,4 +2123,22 @@ CREATE TABLE `cloud`.`port_profile` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `cloud`.`resource_tags` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `uuid` varchar(40), + `key` varchar(255), + `value` varchar(255), + `resource_id` bigint unsigned NOT NULL, + `resource_type` varchar(255), + `customer` varchar(255), + `domain_id` bigint unsigned NOT NULL COMMENT 'foreign key to domain id', + `account_id` bigint unsigned NOT NULL COMMENT 'owner of this network', + PRIMARY KEY (`id`), + CONSTRAINT `fk_tags__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_tags__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain`(`id`), + UNIQUE `i_tags__resource_id__resource_type__key`(`resource_id`, `resource_type`, `key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + SET foreign_key_checks = 1; diff --git a/wscript b/wscript index 4d063ad6ffe..44685d3fc31 100644 --- a/wscript +++ b/wscript @@ -4,6 +4,7 @@ # the following two variables are used by the target "waf dist" # if you change 'em here, you need to change it also in cloud.spec, add a %changelog entry there, and add an entry in debian/changelog VERSION = '3.0.3.2012-05-15T19:32:03Z' + APPNAME = 'cloud' import shutil,os