You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by pr...@apache.org on 2012/07/23 23:53:32 UTC

[2/2] git commit: Adding support in AWSAPI for CloudStack API's that implement the tags feature.

Adding support in AWSAPI for CloudStack API's that implement the tags feature.

Verified the output of,
1. ec2-create-tags for all 4 supported ec2 resources(image, instance, volume and snapshot) with and without tag-value.
2. ec2-delete-tags for all types of created tags.
3. ec2-describe-tags with and without all supported filter.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/c60e4b4a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/c60e4b4a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/c60e4b4a

Branch: refs/heads/master
Commit: c60e4b4a9e3b7403b8e04b2e2223f12a04463133
Parents: 9e5fb17
Author: Likitha Shetty <li...@citrix.com>
Authored: Thu Jul 12 17:12:23 2012 -0700
Committer: prachi <pr...@cloud.com>
Committed: Mon Jul 23 11:31:17 2012 -0700

----------------------------------------------------------------------
 .../cloud/bridge/service/EC2SoapServiceImpl.java   |  182 +++++++++++++--
 .../bridge/service/core/ec2/EC2DescribeTags.java   |   34 +++
 .../service/core/ec2/EC2DescribeTagsResponse.java  |   37 +++
 .../cloud/bridge/service/core/ec2/EC2Engine.java   |  105 +++++++++
 .../bridge/service/core/ec2/EC2ResourceTag.java    |   64 +++++
 .../bridge/service/core/ec2/EC2TagKeyValue.java    |   44 ++++
 .../bridge/service/core/ec2/EC2TagTypeId.java      |   47 ++++
 .../com/cloud/bridge/service/core/ec2/EC2Tags.java |   44 ++++
 .../bridge/service/core/ec2/EC2TagsFilterSet.java  |  107 +++++++++
 awsapi/src/com/cloud/stack/CloudStackApi.java      |   77 ++++++-
 .../src/com/cloud/stack/models/ApiConstants.java   |   10 +
 .../cloud/stack/models/CloudStackResourceTag.java  |   50 ++++
 12 files changed, 784 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java
index 9e10e09..9a8e777 100644
--- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java
+++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java
@@ -33,6 +33,7 @@ import com.cloud.bridge.service.core.ec2.EC2CreateImage;
 import com.cloud.bridge.service.core.ec2.EC2CreateImageResponse;
 import com.cloud.bridge.service.core.ec2.EC2CreateKeyPair;
 import com.cloud.bridge.service.core.ec2.EC2CreateVolume;
+import com.cloud.bridge.service.core.ec2.EC2Tags;
 import com.cloud.bridge.service.core.ec2.EC2DeleteKeyPair;
 import com.cloud.bridge.service.core.ec2.EC2DescribeAddresses;
 import com.cloud.bridge.service.core.ec2.EC2DescribeAddressesResponse;
@@ -46,10 +47,13 @@ import com.cloud.bridge.service.core.ec2.EC2DescribeInstances;
 import com.cloud.bridge.service.core.ec2.EC2DescribeInstancesResponse;
 import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairs;
 import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairsResponse;
+import com.cloud.bridge.service.core.ec2.EC2ResourceTag;
 import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroups;
 import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroupsResponse;
 import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshots;
 import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshotsResponse;
+import com.cloud.bridge.service.core.ec2.EC2DescribeTags;
+import com.cloud.bridge.service.core.ec2.EC2DescribeTagsResponse;
 import com.cloud.bridge.service.core.ec2.EC2DescribeVolumes;
 import com.cloud.bridge.service.core.ec2.EC2DescribeVolumesResponse;
 import com.cloud.bridge.service.core.ec2.EC2DisassociateAddress;
@@ -69,6 +73,8 @@ import com.cloud.bridge.service.core.ec2.EC2PasswordData;
 import com.cloud.bridge.service.core.ec2.EC2RebootInstances;
 import com.cloud.bridge.service.core.ec2.EC2RegisterImage;
 import com.cloud.bridge.service.core.ec2.EC2ReleaseAddress;
+import com.cloud.bridge.service.core.ec2.EC2TagKeyValue;
+import com.cloud.bridge.service.core.ec2.EC2TagTypeId;
 import com.cloud.bridge.service.core.ec2.EC2RunInstances;
 import com.cloud.bridge.service.core.ec2.EC2RunInstancesResponse;
 import com.cloud.bridge.service.core.ec2.EC2SSHKeyPair;
@@ -79,6 +85,7 @@ import com.cloud.bridge.service.core.ec2.EC2StartInstances;
 import com.cloud.bridge.service.core.ec2.EC2StartInstancesResponse;
 import com.cloud.bridge.service.core.ec2.EC2StopInstances;
 import com.cloud.bridge.service.core.ec2.EC2StopInstancesResponse;
+import com.cloud.bridge.service.core.ec2.EC2TagsFilterSet;
 import com.cloud.bridge.service.core.ec2.EC2Volume;
 import com.cloud.bridge.service.core.ec2.EC2VolumeFilterSet;
 import com.cloud.bridge.service.exception.EC2ServiceException;
@@ -199,6 +206,89 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
 		return toCreateVolumeResponse( engine.createVolume( request ));
 	}
 
+    public CreateTagsResponse createTags(CreateTags createTags) {
+        EC2Tags request = new EC2Tags();
+        CreateTagsType ctt = createTags.getCreateTags();
+
+        ResourceIdSetType resourceIds = ctt.getResourcesSet();
+        ResourceTagSetType resourceTags = ctt.getTagSet();
+        request = toResourceTypeAndIds(resourceIds);
+        //add resource tag's to the request
+        if (resourceTags != null) {
+            ResourceTagSetItemType[] items = resourceTags.getItem();
+            if (items != null) {
+                for( int i=0; i < items.length; i++ ) {
+                    EC2TagKeyValue param1 = new EC2TagKeyValue();
+                    param1.setKey(items[i].getKey());
+                    param1.setValue(items[i].getValue());
+                    request.addResourceTag(param1);
+                }
+            }
+        }
+        return toCreateTagsResponse( engine.modifyTags( request, "create"));
+    }
+
+    public DeleteTagsResponse deleteTags(DeleteTags deleteTags) {
+        EC2Tags request = new EC2Tags();
+        DeleteTagsType dtt = deleteTags.getDeleteTags();
+
+        ResourceIdSetType resourceIds = dtt.getResourcesSet();
+        DeleteTagsSetType resourceTags = dtt.getTagSet();
+        request = toResourceTypeAndIds(resourceIds);
+        //add resource tag's to the request
+        if (resourceTags != null) {
+            DeleteTagsSetItemType[] items = resourceTags.getItem();
+            if (items != null) {
+                for( int i=0; i < items.length; i++ ) {
+                    EC2TagKeyValue param1 = new EC2TagKeyValue();
+                    param1.setKey(items[i].getKey());
+                    if (items[i].getValue() != null)
+                        param1.setValue(items[i].getValue());
+                    request.addResourceTag(param1);
+                }
+            }
+        }
+        return toDeleteTagsResponse( engine.modifyTags( request, "delete"));
+    }
+
+    private EC2Tags toResourceTypeAndIds(ResourceIdSetType resourceIds) {
+        EC2Tags request = new EC2Tags();
+        //add resource-type and resource-id's to the request
+        if (resourceIds != null) {
+            ResourceIdSetItemType[] items = resourceIds.getItem();
+            List<String> resourceTypeList = new ArrayList<String>();
+            if (items != null) {
+                for( int i=0; i < items.length; i++ ) {
+                    String resourceType = items[i].getResourceId().split(":")[0];
+                    if (resourceTypeList.isEmpty())
+                        resourceTypeList.add(resourceType);
+                    else {
+                        Boolean existsInList = false;
+                        for (String addedResourceType : resourceTypeList) {
+                            if (addedResourceType.equalsIgnoreCase(resourceType)) {
+                                existsInList = true;
+                                break;
+                            }
+                        }
+                        if (!existsInList)
+                            resourceTypeList.add(resourceType);
+                    }
+                }
+                for (String resourceType : resourceTypeList){
+                    EC2TagTypeId param1 = new EC2TagTypeId();
+                    param1.setResourceType(resourceType);
+                    for( int i=0; i < items.length; i++ ) {
+                        String[] resourceTag = items[i].getResourceId().split(":");
+                        if (resourceType.equals(resourceTag[0]))
+                            param1.addResourceId(resourceTag[1]);
+                    }
+                    request.addResourceType(param1);
+                }
+            }
+        }
+        return request;
+    }
+
 	public DeleteSecurityGroupResponse deleteSecurityGroup(DeleteSecurityGroup deleteSecurityGroup) {
         DeleteSecurityGroupType sgt = deleteSecurityGroup.getDeleteSecurityGroup();
 		return toDeleteSecurityGroupResponse( engine.deleteSecurityGroup( sgt.getGroupName()));
@@ -434,7 +524,18 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
 		return toDescribeSnapshotsResponse(engine.handleRequest(request));
 	}
 
-	
+    public DescribeTagsResponse describeTags(DescribeTags decsribeTags) {
+        EC2DescribeTags request = new EC2DescribeTags();
+        DescribeTagsType dtt = decsribeTags.getDescribeTags();
+
+        FilterSetType fst = dtt.getFilterSet();
+
+        if (fst != null)
+            request.setFilterSet( toTagsFilterSet( fst ));
+
+        return toDescribeTagsResponse(engine.describeTags(request));
+    }
+
 	public DescribeVolumesResponse describeVolumes(DescribeVolumes describeVolumes) 
 	{
 		EC2DescribeVolumes request = new EC2DescribeVolumes();
@@ -1094,8 +1195,28 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
         }
         return azfs;
     }
-	
-	
+
+    private EC2TagsFilterSet toTagsFilterSet( FilterSetType fst ) {
+        EC2TagsFilterSet tfs = new EC2TagsFilterSet();
+
+        FilterType[] items = fst.getItem();
+        if (items != null) {
+            for (FilterType item : items) {
+                EC2Filter oneFilter = new EC2Filter();
+                String filterName = item.getName();
+                oneFilter.setName( filterName );
+
+                ValueSetType vft = item.getValueSet();
+                ValueType[] valueItems = vft.getItem();
+                for (ValueType valueItem : valueItems) {
+                    oneFilter.addValueEncoded( valueItem.getValue());
+                }
+                tfs.addFilter( oneFilter );
+            }
+        }
+        return tfs;
+    }
+
 	// toMethods
 	public static DescribeVolumesResponse toDescribeVolumesResponse( EC2DescribeVolumesResponse engineResponse ) 
 	{
@@ -1931,7 +2052,48 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
 		response.setRevokeSecurityGroupIngressResponse( param1 );
         return response;
 	}
-	
+
+    public static CreateTagsResponse toCreateTagsResponse( boolean success ) {
+        CreateTagsResponse response = new CreateTagsResponse();
+        CreateTagsResponseType param1 = new CreateTagsResponseType();
+
+        param1.set_return(success);
+        param1.setRequestId( UUID.randomUUID().toString());
+        response.setCreateTagsResponse(param1);
+        return response;
+    }
+
+    public static DeleteTagsResponse toDeleteTagsResponse( boolean success ) {
+        DeleteTagsResponse response = new DeleteTagsResponse();
+        DeleteTagsResponseType param1 = new DeleteTagsResponseType();
+
+        param1.set_return(success);
+        param1.setRequestId( UUID.randomUUID().toString());
+        response.setDeleteTagsResponse(param1);
+        return response;
+    }
+
+    public static DescribeTagsResponse toDescribeTagsResponse( EC2DescribeTagsResponse engineResponse) {
+        DescribeTagsResponse response = new DescribeTagsResponse();
+        DescribeTagsResponseType param1 = new DescribeTagsResponseType();
+
+        EC2ResourceTag[] tags = engineResponse.getTagsSet();
+        TagSetType param2 = new TagSetType();
+        for (EC2ResourceTag tag : tags) {
+            TagSetItemType param3 = new TagSetItemType();
+            param3.setResourceId(tag.getResourceId());
+            param3.setResourceType(tag.getResourceType());
+            param3.setKey(tag.getKey());
+            if (tag.getValue() != null)
+                param3.setValue(tag.getValue());
+            param2.addItem(param3);
+        }
+        param1.setTagSet(param2);
+        param1.setRequestId( UUID.randomUUID().toString());
+        response.setDescribeTagsResponse(param1);
+        return response;
+    }
+
 	public DescribeKeyPairsResponse describeKeyPairs(DescribeKeyPairs describeKeyPairs) {
 		
 		EC2DescribeKeyPairs ec2Request = new EC2DescribeKeyPairs();
@@ -2116,10 +2278,6 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
 	public CreateSubnetResponse createSubnet(CreateSubnet createSubnet) {
 		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
 	}
-	
-	public CreateTagsResponse createTags(CreateTags createTags) {
-		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
-	}
 
 	public CreateVpcResponse createVpc(CreateVpc createVpc) {
 		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
@@ -2156,10 +2314,6 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
 	public DeleteSubnetResponse deleteSubnet(DeleteSubnet deleteSubnet) {
 		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
 	}
-		
-	public DeleteTagsResponse deleteTags(DeleteTags deleteTags) {
-		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
-	}
 
 	public DeleteVpcResponse deleteVpc(DeleteVpc deleteVpc) {
 		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
@@ -2229,10 +2383,6 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface  {
 		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
 	}
 	
-	public DescribeTagsResponse describeTags(DescribeTags describeTags) {
-		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
-	}
-	
 	public DescribeVpcsResponse describeVpcs(DescribeVpcs describeVpcs) {
 		throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available");
 	}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java
new file mode 100644
index 0000000..1ce6527
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+public class EC2DescribeTags {
+
+    private EC2TagsFilterSet tfs = null;
+
+    public EC2DescribeTags() {
+    }
+
+    public EC2TagsFilterSet getFilterSet() {
+        return tfs;
+    }
+
+    public void setFilterSet( EC2TagsFilterSet param ) {
+        tfs = param;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java
new file mode 100644
index 0000000..9559e65
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java
@@ -0,0 +1,37 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EC2DescribeTagsResponse {
+
+    private List<EC2ResourceTag> tagsSet = new ArrayList<EC2ResourceTag>();
+
+    public EC2DescribeTagsResponse() {
+    }
+
+    public void addTags( EC2ResourceTag param ) {
+        tagsSet.add( param );
+    }
+
+    public EC2ResourceTag[] getTagsSet() {
+        return tagsSet.toArray(new EC2ResourceTag[0]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
index 5f45847..36d2b68 100644
--- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java
@@ -59,6 +59,7 @@ import com.cloud.stack.models.CloudStackNic;
 import com.cloud.stack.models.CloudStackOsType;
 import com.cloud.stack.models.CloudStackPasswordData;
 import com.cloud.stack.models.CloudStackResourceLimit;
+import com.cloud.stack.models.CloudStackResourceTag;
 import com.cloud.stack.models.CloudStackSecurityGroup;
 import com.cloud.stack.models.CloudStackSecurityGroupIngress;
 import com.cloud.stack.models.CloudStackServiceOffering;
@@ -1311,6 +1312,80 @@ public class EC2Engine {
 		}   	    
 	}
 
+    /**
+     * Create/Delete tags
+     *
+     * @param request
+     * @param operation
+     * @return
+     */
+    public boolean modifyTags( EC2Tags request, String operation) {
+        try {
+            List<CloudStackKeyValue> resourceTagList = new ArrayList<CloudStackKeyValue>();
+            for ( EC2TagKeyValue resourceTag : request.getResourceTags()){
+                CloudStackKeyValue pair = new CloudStackKeyValue();
+                pair.setKeyValue(resourceTag.getKey(), resourceTag.getValue());
+                resourceTagList.add(pair);
+            }
+            EC2TagTypeId[] resourceTypeSet = request.getResourceTypeSet();
+            for (EC2TagTypeId resourceType : resourceTypeSet) {
+                String cloudStackResourceType = mapToCloudStackResourceType(resourceType.getResourceType());
+                List<String> resourceIdList = new ArrayList<String>();
+                for ( String resourceId : resourceType.getResourceIds())
+                    resourceIdList.add(resourceId);
+                CloudStackInfoResponse resp = new CloudStackInfoResponse();
+                if (operation.equalsIgnoreCase("create"))
+                    resp = getApi().createTags(cloudStackResourceType, resourceIdList, resourceTagList);
+                else if(operation.equalsIgnoreCase("delete"))
+                    resp = getApi().deleteTags(cloudStackResourceType, resourceIdList, resourceTagList);
+                else
+                    throw new EC2ServiceException( ServerError.InternalError, "Unknown operation." );
+                if (resp.getSuccess() == false)
+                    return false;
+            }
+            return true;
+        } catch (Exception e){
+            logger.error( "EC2 Create/Delete Tags - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ?
+                    e.getMessage() : "An unexpected error occurred.");
+        }
+    }
+
+    /**
+     * Describe tags
+     *
+     * @param request
+     * @return
+     */
+    public EC2DescribeTagsResponse describeTags (EC2DescribeTags request) {
+        try {
+            EC2DescribeTagsResponse tagResponse = new EC2DescribeTagsResponse();
+            List<CloudStackResourceTag> resourceTagList = getApi().listTags(null, null, null, true, null);
+
+            List<EC2ResourceTag> tagList = new ArrayList<EC2ResourceTag>();
+            if (resourceTagList != null && resourceTagList.size() > 0) {
+                for (CloudStackResourceTag resourceTag: resourceTagList) {
+                    EC2ResourceTag tag = new EC2ResourceTag();
+                    tag.setResourceId(resourceTag.getResourceId());
+                    tag.setResourceType(mapToAmazonResourceType(resourceTag.getResourceType()));
+                    tag.setKey(resourceTag.getKey());
+                    if (resourceTag.getValue() != null)
+                        tag.setValue(resourceTag.getValue());
+                    tagResponse.addTags(tag);
+                 }
+            }
+
+            EC2TagsFilterSet tfs = request.getFilterSet();
+            if (tfs == null)
+                return tagResponse;
+            else
+                return tfs.evaluate(tagResponse);
+        } catch(Exception e) {
+            logger.error("EC2 DescribeTags - ", e);
+            throw new EC2ServiceException(ServerError.InternalError, e.getMessage());
+        }
+    }
+
 	/**
 	 * Reboot an instance or instances
 	 * 
@@ -2245,6 +2320,36 @@ public class EC2Engine {
 		return "error"; 
 	}
 
+    /**
+     * Map Amazon resourceType to CloudStack resourceType
+     *
+     * @param Amazon resourceType
+     * @return CloudStack resourceType
+     */
+    private String mapToCloudStackResourceType( String resourceType) {
+        if (resourceType.equalsIgnoreCase("image"))
+            return("template");
+        else if(resourceType.equalsIgnoreCase("instance"))
+            return("userVm");
+        else
+            return resourceType;
+    }
+
+    /**
+     * Map Amazon resourceType to CloudStack resourceType
+     *
+     * @param CloudStack resourceType
+     * @return Amazon resourceType
+     */
+    private String mapToAmazonResourceType( String resourceType) {
+        if (resourceType.equalsIgnoreCase("template"))
+            return("image");
+        else if(resourceType.equalsIgnoreCase("userVm"))
+            return("instance");
+        else
+            return (resourceType.toLowerCase());
+    }
+
 	/**
 	 * Stop an instance
 	 * Wait until one specific VM has stopped

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java
new file mode 100644
index 0000000..e3c5881
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+public class EC2ResourceTag {
+    private String resourceId;
+    private String resourceType;
+    private String key;
+    private String value;
+
+    public EC2ResourceTag() {
+        resourceId		= null;
+        resourceType	= null;
+        key				= null;
+        value			= null;
+    }
+
+    public void setResourceId( String resourceId ) {
+        this.resourceId = resourceId;
+    }
+
+    public String getResourceId() {
+        return this.resourceId;
+    }
+
+    public void setResourceType( String resourceType ) {
+        this.resourceType = resourceType;
+    }
+
+    public String getResourceType() {
+        return this.resourceType;
+    }
+
+    public void setKey( String key ) {
+        this.key = key;
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+
+    public void setValue( String value ) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java
new file mode 100644
index 0000000..beb2af9
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+public class EC2TagKeyValue {
+    private String key;
+    private String value;
+
+    public EC2TagKeyValue() {
+        key      = null;
+        value    = null;
+    }
+
+    public void setKey( String key ) {
+        this.key = key;
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+
+    public void setValue( String value ) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java
new file mode 100644
index 0000000..3a0666e
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EC2TagTypeId {
+
+    private String resourceType;
+    private List<String> resourceIdSet = new ArrayList<String>();
+
+    public EC2TagTypeId() {
+        resourceType = null;
+    }
+
+    public void setResourceType( String resourceType ) {
+        this.resourceType = resourceType;
+    }
+
+    public String getResourceType() {
+        return this.resourceType;
+    }
+
+    public void addResourceId( String param ) {
+        resourceIdSet.add( param );
+    }
+
+    public String[] getResourceIds() {
+        return resourceIdSet.toArray(new String[0]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java
new file mode 100644
index 0000000..80c9f8a
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EC2Tags {
+
+    private List<EC2TagTypeId> resourceTypeSet = new ArrayList<EC2TagTypeId>();
+    private List<EC2TagKeyValue> resourceTagSet = new ArrayList<EC2TagKeyValue>();
+
+    public void addResourceType( EC2TagTypeId param ) {
+        resourceTypeSet.add( param );
+    }
+
+    public EC2TagTypeId[] getResourceTypeSet() {
+        return resourceTypeSet.toArray(new EC2TagTypeId[0]);
+    }
+
+    public void addResourceTag( EC2TagKeyValue param ) {
+        resourceTagSet.add( param );
+    }
+
+    public EC2TagKeyValue[] getResourceTags() {
+        return resourceTagSet.toArray(new EC2TagKeyValue[0]);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java
new file mode 100644
index 0000000..c2d33c3
--- /dev/null
+++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java
@@ -0,0 +1,107 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.bridge.service.core.ec2;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.bridge.service.exception.EC2ServiceException;
+
+public class EC2TagsFilterSet {
+    protected final static Logger logger = Logger.getLogger(EC2TagsFilterSet.class);
+
+    protected List<EC2Filter> filterSet = new ArrayList<EC2Filter>();
+
+    private Map<String,String> filterTypes = new HashMap<String,String>();
+
+    public EC2TagsFilterSet() {
+        filterTypes.put( "resource-id", "String" );
+        filterTypes.put( "resource-type", "String" );
+        filterTypes.put( "key", "String" );
+        filterTypes.put( "value", "String" );
+    }
+
+    public void addFilter( EC2Filter param ) {
+        String filterName = param.getName();
+        String value = (String) filterTypes.get( filterName );
+
+        if (null == value)
+            throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 );
+
+        if (null != value && value.equalsIgnoreCase( "null" ))
+            throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 );
+
+        filterSet.add( param );
+    }
+
+    public EC2Filter[] getFilterSet() {
+        return filterSet.toArray(new EC2Filter[0]);
+    }
+
+    public EC2DescribeTagsResponse evaluate( EC2DescribeTagsResponse sampleList) throws ParseException	{
+        EC2DescribeTagsResponse resultList = new EC2DescribeTagsResponse();
+
+        boolean matched;
+
+        EC2ResourceTag[] tagSet = sampleList.getTagsSet();
+        EC2Filter[] filterSet = getFilterSet();
+        for (EC2ResourceTag tag : tagSet) {
+            matched = true;
+            for (EC2Filter filter : filterSet) {
+                if (!filterMatched(tag, filter)) {
+                    matched = false;
+                    break;
+                }
+            }
+            if (matched == true)
+                resultList.addTags(tag);
+        }
+        return resultList;
+    }
+
+    private boolean filterMatched( EC2ResourceTag tag, EC2Filter filter ) throws ParseException {
+        String filterName = filter.getName();
+        String[] valueSet = filter.getValueSet();
+
+        if ( filterName.equalsIgnoreCase("resource-id")) {
+            return containsString(tag.getResourceId(), valueSet);
+        } else if ( filterName.equalsIgnoreCase("resource-type")) {
+            return containsString(tag.getResourceType(), valueSet);
+        } else if ( filterName.equalsIgnoreCase("key")) {
+            return containsString(tag.getKey(), valueSet);
+        } else if ( filterName.equalsIgnoreCase("value")) {
+            return containsString(tag.getValue(), valueSet);
+        } else
+            return false;
+     }
+
+    private boolean containsString( String lookingFor, String[] set ){
+        if (lookingFor == null)
+            return false;
+
+        for (String filter: set) {
+            if (lookingFor.matches( filter )) return true;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/stack/CloudStackApi.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java
index e46ebdd..50b2b25 100644
--- a/awsapi/src/com/cloud/stack/CloudStackApi.java
+++ b/awsapi/src/com/cloud/stack/CloudStackApi.java
@@ -42,6 +42,7 @@ import com.cloud.stack.models.CloudStackOsType;
 import com.cloud.stack.models.CloudStackPasswordData;
 import com.cloud.stack.models.CloudStackPortForwardingRule;
 import com.cloud.stack.models.CloudStackResourceLimit;
+import com.cloud.stack.models.CloudStackResourceTag;
 import com.cloud.stack.models.CloudStackSecurityGroup;
 import com.cloud.stack.models.CloudStackSecurityGroupIngress;
 import com.cloud.stack.models.CloudStackServiceOffering;
@@ -973,7 +974,81 @@ public class CloudStackApi {
 		}
 		return _client.call(cmd, apiKey, secretKey, true, ApiConstants.EXTRACT_VOLUME_RESPONSE, ApiConstants.VOLUME, CloudStackExtractTemplate.class);
 	}
-	
+
+    //Tags
+    /**
+     * Create tags
+     *
+     * @param resource type
+     * @param resource id's
+     * @param tags
+     * @return
+     * @throws Exception
+     *
+     */
+    public CloudStackInfoResponse createTags(String resourceType, List<String>resourceIds,
+            List<CloudStackKeyValue> resourceTags) throws Exception {
+        CloudStackCommand cmd = new CloudStackCommand(ApiConstants.CREATE_TAGS);
+        cmd = setParams(cmd, resourceType, resourceIds, resourceTags);
+        return _client.call(cmd, apiKey, secretKey, true, ApiConstants.CREATE_TAGS_RESPONSE,
+                null, CloudStackInfoResponse.class);
+    }
+
+    /**
+     * Delete tags
+     *
+     * @param resource type
+     * @param resource id's
+     * @param tags
+     * @return
+     * @throws Exception
+     *
+     */
+    public CloudStackInfoResponse deleteTags(String resourceType, List<String>resourceIds,
+            List<CloudStackKeyValue> resourceTags) throws Exception {
+        CloudStackCommand cmd = new CloudStackCommand(ApiConstants.DELETE_TAGS);
+        cmd = setParams(cmd, resourceType, resourceIds, resourceTags);
+        return _client.call(cmd, apiKey, secretKey, true, ApiConstants.DELETE_TAGS_RESPONSE,
+                null, CloudStackInfoResponse.class);
+    }
+
+    public List<CloudStackResourceTag> listTags(String account, String domainId,
+            Boolean isRecursive, Boolean listAll, String keyWord) throws Exception {
+        CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_TAGS);
+        if (cmd != null) {
+            if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account);
+            if (domainId != null) cmd.setParam(ApiConstants.DOMAIN_ID, domainId);
+            if (isRecursive != null) cmd.setParam(ApiConstants.IS_RECURSIVE, isRecursive.toString());
+            if (listAll != null) cmd.setParam(ApiConstants.LIST_ALL, listAll.toString());
+            if (keyWord != null) cmd.setParam(ApiConstants.KEYWORD, keyWord);
+        }
+        return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_TAGS_RESPONSE,
+                ApiConstants.TAG , new TypeToken<List<CloudStackResourceTag>>() {}.getType());
+    }
+
+    private CloudStackCommand setParams(CloudStackCommand cmd, String resourceType, List<String>resourceIds,
+            List<CloudStackKeyValue> resourceTags) {
+        if (cmd != null) {
+            cmd.setParam(ApiConstants.RESOURCE_TYPE, resourceType);
+            if (resourceIds != null && resourceIds.size() > 0) {
+                String resourceIdList = resourceIds.get(0);
+                for (int i=1 ; i<resourceIds.size(); i++)
+                    resourceIdList = resourceIdList.concat(","+resourceIds.get(i));
+                cmd.setParam(ApiConstants.RESOURCE_IDS, resourceIdList);
+            }
+            if (resourceTags != null && resourceTags.size() > 0) {
+                int i=0;
+                for (CloudStackKeyValue resourceTag : resourceTags) {
+                    cmd.setParam(ApiConstants.TAGS+"["+i+"].key", resourceTag.getKey());
+                    if (resourceTag.getValue() != null)
+                        cmd.setParam(ApiConstants.TAGS+"["+i+"].value", resourceTag.getValue());
+                    i++;
+                }
+            }
+        }
+        return cmd;
+    }
+
 	// Security Groups
 	/**
 	 * Creates a security group

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/stack/models/ApiConstants.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/stack/models/ApiConstants.java b/awsapi/src/com/cloud/stack/models/ApiConstants.java
index e00a9b9..2097ab6 100644
--- a/awsapi/src/com/cloud/stack/models/ApiConstants.java
+++ b/awsapi/src/com/cloud/stack/models/ApiConstants.java
@@ -85,6 +85,8 @@ public class ApiConstants {
     public static final String CREATE_SNAPSHOT_RESPONSE = "createsnapshotresponse";
     public static final String CREATE_SSH_KEY_PAIR = "createSSHKeyPair";
     public static final String CREATE_SSH_KEY_PAIR_RESPONSE = "createsshkeypairresponse";
+    public static final String CREATE_TAGS = "createTags";
+    public static final String CREATE_TAGS_RESPONSE = "createtagsresponse";
     public static final String CREATE_TEMPLATE = "createTemplate";
     public static final String CREATE_TEMPLATE_RESPONSE = "createtemplateresponse";
     public static final String CREATE_VOLUME = "createVolume";
@@ -114,6 +116,8 @@ public class ApiConstants {
     public static final String DELETE_SNAPSHOT_RESPONSE = "deletesnapshotresponse";
     public static final String DELETE_SSH_KEY_PAIR = "deleteSSHKeyPair";
     public static final String DELETE_SSH_KEY_PAIR_RESPONSE = "deletesshkeypairresponse";
+    public static final String DELETE_TAGS = "deleteTags";
+    public static final String DELETE_TAGS_RESPONSE = "deletetagsresponse";
     public static final String DELETE_TEMPLATE = "deleteTemplate";
     public static final String DELETE_TEMPLATE_RESPONSE = "deletetemplateresponse";
     public static final String DELETE_VOLUME = "deleteVolume";
@@ -228,6 +232,7 @@ public class ApiConstants {
     public static final String ISOLATION_URI = "isolationuri";
     public static final String JOB_ID = "jobid";
     public static final String JOB_STATUS = "jobstatus";
+    public static final String KEY = "key";
     public static final String KEY_PAIR = "keypair";
     public static final String KEYWORD = "keyword";
     public static final String LASTNAME = "lastname";
@@ -290,6 +295,8 @@ public class ApiConstants {
     public static final String LIST_SSH_KEY_PAIRS = "listSSHKeyPairs";
     public static final String LIST_SSH_KEY_PAIRS_RESPONSE = "listsshkeypairsresponse";
     public static final String LIST_TEMPLATE_PERMISSIONS = "listTemplatePermissions";
+    public static final String LIST_TAGS = "listTags";
+    public static final String LIST_TAGS_RESPONSE = "listtagsresponse";
     public static final String LIST_TEMPLATE_PERMISSIONS_RESPONSE = "listtemplatepermissionsresponse";
     public static final String LIST_TEMPLATES = "listTemplates";
     public static final String LIST_TEMPLATES_RESPONSE = "listtemplatesresponse";
@@ -380,6 +387,8 @@ public class ApiConstants {
 	public static final String REQUIRES_HVM = "requireshvm";
 	public static final String RESET_PASSWORD_FOR_VIRTUAL_MACHINE = "resetPasswordForVirtualMachine";
 	public static final String RESET_PASSWORD_FOR_VIRTUAL_MACHINE_RESPONSE = "resetpasswordforvirtualmachineresponse";
+    public static final String RESOURCE_ID = "resourceid";
+    public static final String RESOURCE_IDS = "resourceIds";
 	public static final String RESOURCE_LIMIT = "resourcelimit";
 	public static final String RESOURCE_TYPE = "resourcetype";
 	public static final String RESTART_NETWORK = "restartNetwork";
@@ -433,6 +442,7 @@ public class ApiConstants {
 	public static final String STORAGE_TYPE = "storagetype";
 	public static final String SUCCESS = "success";
 	public static final String SYSTEM_VM_TYPE = "systemvmtype";
+    public static final String TAG = "tag";
 	public static final String TAGS = "tags";
 	public static final String TARGET_IQN = "targetiqn";
 	public static final String TEMPLATE = "template";

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c60e4b4a/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java b/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java
new file mode 100644
index 0000000..8dd75c5
--- /dev/null
+++ b/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java
@@ -0,0 +1,50 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package com.cloud.stack.models;
+
+import com.google.gson.annotations.SerializedName;
+
+public class CloudStackResourceTag {
+    @SerializedName(ApiConstants.RESOURCE_ID)
+    private String resourceId;
+    @SerializedName(ApiConstants.RESOURCE_TYPE)
+    private String resourceType;
+    @SerializedName(ApiConstants.KEY)
+    private String key;
+    @SerializedName(ApiConstants.VALUE)
+    private String value;
+
+    public CloudStackResourceTag() {
+    }
+
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public String getValue() {
+        return value;
+    }
+}