diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 7872cba309d..54bfaff8883 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -358,6 +358,8 @@ public class ApiConstants { public static final String VSM_DEVICE_STATE = "vsmdevicestate"; public static final String ADD_VSM_FLAG = "addvsmflag"; public static final String CAN_USE_FOR_DEPLOY = "canusefordeploy"; + 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 a9b6f6074b8..0924796bb41 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -49,6 +49,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; @@ -128,6 +129,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); @@ -155,6 +157,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 5f55705981c..864a9e67188 100755 --- a/api/src/com/cloud/api/ResponseGenerator.java +++ b/api/src/com/cloud/api/ResponseGenerator.java @@ -56,6 +56,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; @@ -114,6 +115,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; @@ -280,4 +282,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 24bb669c4e2..bb2121b1cfd 100644 --- a/api/src/com/cloud/configuration/Resource.java +++ b/api/src/com/cloud/configuration/Resource.java @@ -19,6 +19,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 424ddc90a23..c42db5d5759 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -259,4 +259,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 a939eb7751a..08c175bbc52 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -331,4 +331,9 @@ updateStorageNetworkIpRange=com.cloud.api.commands.UpdateStorageNetworkIpRangeCm ### Network Devices commands addNetworkDevice=com.cloud.api.commands.AddNetworkDeviceCmd;1 listNetworkDevice=com.cloud.api.commands.ListNetworkDeviceCmd;1 -deleteNetworkDevice=com.cloud.api.commands.DeleteNetworkDeviceCmd;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 4d2eea42f77..d75ab7315e2 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; @@ -78,6 +79,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; @@ -189,6 +191,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); @@ -242,6 +245,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(); @@ -749,7 +753,13 @@ public class ApiDBUtils { public static String getHaTag() { return _haMgr.getHaTag(); } + public static boolean canUseForDeploy(Network network) { return _networkMgr.canUseForDeploy(network); } + + 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 1112dba0e1f..d3c91b8c7e2 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; @@ -2305,10 +2307,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 150d7af89b6..df833f4265e 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; @@ -92,16 +91,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; @@ -160,6 +160,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; @@ -329,6 +331,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 @@ -385,6 +388,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 f5acf71f90e..769aebfe403 100644 --- a/server/src/com/cloud/uuididentity/dao/IdentityDao.java +++ b/server/src/com/cloud/uuididentity/dao/IdentityDao.java @@ -10,14 +10,22 @@ // limitations under the License. // // Automatically generated by addcopyright.py at 04/03/2012 -package com.cloud.uuididentity.dao; -import com.cloud.api.IdentityMapper; -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); +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); -} + /** + * @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 abe20118b18..219ed90e28b 100644 --- a/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java +++ b/server/src/com/cloud/uuididentity/dao/IdentityDaoImpl.java @@ -10,8 +10,8 @@ // limitations under the License. // // Automatically generated by addcopyright.py at 04/03/2012 -package com.cloud.uuididentity.dao; - +package com.cloud.uuididentity.dao; + import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -25,147 +25,89 @@ 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 { - private static final Logger s_logger = Logger.getLogger(IdentityDaoImpl.class); - - public IdentityDaoImpl() { + +@Local(value={IdentityDao.class}) +public class IdentityDaoImpl extends GenericDaoBase implements IdentityDao { + private static final Logger s_logger = Logger.getLogger(IdentityDaoImpl.class); + + public IdentityDaoImpl() { + } + + @DB + public Long getIdentityId(IdentityMapper mapper, String identityString) { + assert(mapper.entityTableName() != null); + return getIdentityId(mapper.entityTableName(), identityString); + } + + @DB + public Long getIdentityId(String tableName, String identityString) { + assert(tableName != null); + assert(identityString != null); + + PreparedStatement pstmt = null; + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + try { + pstmt = txn.prepareAutoCloseStatement( + String.format("SELECT id FROM `%s` WHERE id=? OR uuid=?", tableName) + + // TODO : after graceful period, use following line turn on more secure check + // String.format("SELECT id FROM %s WHERE (id=? AND uuid IS NULL) OR uuid=?", mapper.entityTableName()) + ); + + long id = 0; + try { + // TODO : use regular expression to determine + id = Long.parseLong(identityString); + } catch(NumberFormatException e) { + // this could happen when it is a uuid string, so catch and ignore it + } + + pstmt.setLong(1, id); + pstmt.setString(2, identityString); + + ResultSet rs = pstmt.executeQuery(); + if(rs.next()) { + return rs.getLong(1); + } else { + if(id == -1L) + return id; + + throw new InvalidParameterValueException("Object " + tableName + "(uuid: " + identityString + ") does not exist."); + } + } catch (SQLException e) { + s_logger.error("Unexpected exception ", e); + } + } finally { + txn.close(); + } + return null; } @DB - public Long getIdentityId(IdentityMapper mapper, String identityString) { - assert(mapper.entityTableName() != null); - return getIdentityId(mapper.entityTableName(), identityString); - } - - @DB - public Long getIdentityId(String tableName, String identityString) { - assert(tableName != null); - assert(identityString != null); - - PreparedStatement pstmt = null; - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - try { - try { - pstmt = txn.prepareAutoCloseStatement( - String.format("SELECT id FROM `%s` WHERE id=? OR uuid=?", tableName) - - // TODO : after graceful period, use following line turn on more secure check - // String.format("SELECT id FROM %s WHERE (id=? AND uuid IS NULL) OR uuid=?", mapper.entityTableName()) - ); - - long id = 0; - try { - // TODO : use regular expression to determine - id = Long.parseLong(identityString); - } catch(NumberFormatException e) { - // this could happen when it is a uuid string, so catch and ignore it - } - - pstmt.setLong(1, id); - pstmt.setString(2, identityString); - - ResultSet rs = pstmt.executeQuery(); - if(rs.next()) { - return rs.getLong(1); - } else { - if(id == -1L) - return id; - - throw new InvalidParameterValueException("Object " + tableName + "(uuid: " + identityString + ") does not exist."); - } - } catch (SQLException e) { - s_logger.error("Unexpected exception ", e); - } - } finally { - txn.close(); - } - return null; - } - - @DB - public String getIdentityUuid(String tableName, String identityString) { - assert(tableName != null); - assert(identityString != null); - - PreparedStatement pstmt = null; - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - try { - try { - pstmt = txn.prepareAutoCloseStatement( - String.format("SELECT uuid FROM `%s` WHERE id=? OR uuid=?", tableName) - // String.format("SELECT uuid FROM %s WHERE (id=? AND uuid IS NULL) OR uuid=?", tableName) - ); - - long id = 0; - try { - // TODO : use regular expression to determine - id = Long.parseLong(identityString); - } catch(NumberFormatException e) { - // this could happen when it is a uuid string, so catch and ignore it - } - - pstmt.setLong(1, id); - pstmt.setString(2, identityString); - - ResultSet rs = pstmt.executeQuery(); - if(rs.next()) { - String uuid = rs.getString(1); - if(uuid != null && !uuid.isEmpty()) - return uuid; - return identityString; - } - } catch (SQLException e) { - s_logger.error("Unexpected exception ", e); - } - } finally { - txn.close(); - } - - return identityString; - } - - @DB - public void initializeDefaultUuid(String tableName) { + @Override + public Pair getAccountDomainInfo(String tableName, Long identityId) { assert(tableName != null); - List l = getNullUuidRecords(tableName); - - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - try { - try { - txn.start(); - for(Long id : l) { - setInitialUuid(tableName, id); - } - txn.commit(); - } catch (SQLException e) { - txn.rollback(); - s_logger.error("Unexpected exception ", e); - } - } finally { - txn.close(); - } - } - - @DB - List getNullUuidRecords(String tableName) { - List l = new ArrayList(); PreparedStatement pstmt = null; Transaction txn = Transaction.open(Transaction.CLOUD_DB); try { try { pstmt = txn.prepareAutoCloseStatement( - String.format("SELECT id FROM `%s` WHERE uuid IS NULL", tableName) + String.format("SELECT account_id, domain_id FROM `%s` WHERE id=?", tableName) ); + pstmt.setLong(1, identityId); + ResultSet rs = pstmt.executeQuery(); - while(rs.next()) { - l.add(rs.getLong(1)); + 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); @@ -173,20 +115,110 @@ public class IdentityDaoImpl extends GenericDaoBase implements } finally { txn.close(); } - return l; - } - + return null; + } + @DB - void setInitialUuid(String tableName, long id) throws SQLException { - Transaction txn = Transaction.currentTxn(); - - PreparedStatement pstmtUpdate = null; - pstmtUpdate = txn.prepareAutoCloseStatement( - String.format("UPDATE `%s` SET uuid=? WHERE id=?", tableName) - ); - - pstmtUpdate.setString(1, UUID.randomUUID().toString()); - pstmtUpdate.setLong(2, id); - pstmtUpdate.executeUpdate(); - } -} + @Override + public String getIdentityUuid(String tableName, String identityString) { + assert(tableName != null); + assert(identityString != null); + + PreparedStatement pstmt = null; + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + try { + pstmt = txn.prepareAutoCloseStatement( + String.format("SELECT uuid FROM `%s` WHERE id=? OR uuid=?", tableName) + // String.format("SELECT uuid FROM %s WHERE (id=? AND uuid IS NULL) OR uuid=?", tableName) + ); + + long id = 0; + try { + // TODO : use regular expression to determine + id = Long.parseLong(identityString); + } catch(NumberFormatException e) { + // this could happen when it is a uuid string, so catch and ignore it + } + + pstmt.setLong(1, id); + pstmt.setString(2, identityString); + + ResultSet rs = pstmt.executeQuery(); + if(rs.next()) { + String uuid = rs.getString(1); + if(uuid != null && !uuid.isEmpty()) + return uuid; + return identityString; + } + } catch (SQLException e) { + s_logger.error("Unexpected exception ", e); + } + } finally { + txn.close(); + } + + return identityString; + } + + @DB + public void initializeDefaultUuid(String tableName) { + assert(tableName != null); + List l = getNullUuidRecords(tableName); + + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + try { + txn.start(); + for(Long id : l) { + setInitialUuid(tableName, id); + } + txn.commit(); + } catch (SQLException e) { + txn.rollback(); + s_logger.error("Unexpected exception ", e); + } + } finally { + txn.close(); + } + } + + @DB + List getNullUuidRecords(String tableName) { + List l = new ArrayList(); + + PreparedStatement pstmt = null; + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + try { + pstmt = txn.prepareAutoCloseStatement( + String.format("SELECT id FROM `%s` WHERE uuid IS NULL", tableName) + ); + + ResultSet rs = pstmt.executeQuery(); + while(rs.next()) { + l.add(rs.getLong(1)); + } + } catch (SQLException e) { + s_logger.error("Unexpected exception ", e); + } + } finally { + txn.close(); + } + return l; + } + + @DB + void setInitialUuid(String tableName, long id) throws SQLException { + Transaction txn = Transaction.currentTxn(); + + PreparedStatement pstmtUpdate = null; + pstmtUpdate = txn.prepareAutoCloseStatement( + String.format("UPDATE `%s` SET uuid=? WHERE id=?", tableName) + ); + + pstmtUpdate.setString(1, UUID.randomUUID().toString()); + pstmtUpdate.setLong(2, id); + pstmtUpdate.executeUpdate(); + } +} diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 488fb06e9cd..afcee3f9f6f 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -2132,4 +2132,22 @@ CREATE TABLE `cloud`.`netscaler_pod_ref` ( CONSTRAINT `fk_ns_pod_ref__device_id` FOREIGN KEY (`external_load_balancer_device_id`) REFERENCES `external_load_balancer_devices`(`id`) ON DELETE CASCADE ) 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 1ead7af8061..7ff0de394c1 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