You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ab...@apache.org on 2014/10/22 01:32:44 UTC

[1/7] JCLOUDS-756. Add support for tags to CloudStack.

Repository: jclouds
Updated Branches:
  refs/heads/jclouds-756 [created] 41523c23e


http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListSecurityGroupsResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListSecurityGroupsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListSecurityGroupsResponseTest.java
index 54d06b9..cac6017 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListSecurityGroupsResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListSecurityGroupsResponseTest.java
@@ -20,6 +20,7 @@ import java.util.Set;
 
 import org.jclouds.cloudstack.domain.IngressRule;
 import org.jclouds.cloudstack.domain.SecurityGroup;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.rest.annotations.SelectJson;
 import org.testng.annotations.Test;
@@ -54,7 +55,9 @@ public class ListSecurityGroupsResponseTest extends BaseSetParserTest<SecurityGr
                                     .securityGroupName("adriancole").account("adrian").build(),
 
                               IngressRule.builder().id("6").protocol("udp").startPort(11).endPort(11).CIDR("1.1.1.1/24")
-                                    .build())).build())
+                                    .build()
+                        )
+                  ).build())
             .add(SecurityGroup.builder().id("12").name("adriancole").account("adrian").domainId("1").domain("ROOT").build())
             .add(SecurityGroup.builder().id("15").name("2").description("description").account("adrian").domainId("1")
                   .domain("ROOT").build())
@@ -62,9 +65,9 @@ public class ListSecurityGroupsResponseTest extends BaseSetParserTest<SecurityGr
             .add(SecurityGroup.builder().id("14").name("1").description("description").account("adrian").domainId("1")
                   .domain("ROOT").ingressRules(ImmutableSet.of(
 
-                  IngressRule.builder().id("7").protocol("tcp").startPort(10).endPort(10).CIDR("1.1.1.1/24").build(),
+                        IngressRule.builder().id("7").protocol("tcp").startPort(10).endPort(10).CIDR("1.1.1.1/24").build(),
 
-                  IngressRule.builder().id("8").protocol("tcp").startPort(10).endPort(10).CIDR("2.2.2.2/16").build()))
+                        IngressRule.builder().id("8").protocol("tcp").startPort(10).endPort(10).CIDR("2.2.2.2/16").build()))
                   .build())
             .add(SecurityGroup
                   .builder()
@@ -76,13 +79,25 @@ public class ListSecurityGroupsResponseTest extends BaseSetParserTest<SecurityGr
                   .domain("ROOT")
                   .ingressRules(
                         ImmutableSet.of(IngressRule.builder().id("9").protocol("icmp").ICMPType(-1).ICMPCode(-1)
-                              .securityGroupName("1").account("adrian").build(),
+                                    .securityGroupName("1").account("adrian").build(),
 
-                        IngressRule.builder().id("10").protocol("tcp").startPort(22).endPort(22).securityGroupName("1")
-                              .account("adrian").build(),
+                              IngressRule.builder().id("10").protocol("tcp").startPort(22).endPort(22).securityGroupName("1")
+                                    .account("adrian").build(),
 
-                        IngressRule.builder().id("11").protocol("tcp").startPort(22).endPort(22).securityGroupName("2")
-                              .account("adrian").build())).build()).build();
+                              IngressRule.builder().id("11").protocol("tcp").startPort(22).endPort(22).securityGroupName("2")
+                                    .account("adrian").build()
+                        )
+                  )
+                  .tags(Tag.builder()
+                        .account("adrian")
+                        .domain("ROOT")
+                        .domainId("1")
+                        .key("some-tag")
+                        .resourceId("16")
+                        .resourceType(Tag.ResourceType.SECURITY_GROUP)
+                        .value("some-value")
+                        .build())
+                  .build()).build();
 
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTagsResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTagsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTagsResponseTest.java
new file mode 100644
index 0000000..decc2f0
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTagsResponseTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.jclouds.cloudstack.parse;
+
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.json.BaseSetParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit")
+public class ListTagsResponseTest extends BaseSetParserTest<Tag> {
+
+   @Override
+   protected Injector injector() {
+      return Guice.createInjector(new GsonModule() {
+
+         @Override
+         protected void configure() {
+            bind(DateAdapter.class).to(Iso8601DateAdapter.class);
+            super.configure();
+         }
+
+      });
+   }
+
+   @Override
+   public String resource() {
+      return "/listtagsresponse.json";
+   }
+
+   @Override
+   @SelectJson("tag")
+   public Set<Tag> expected() {
+      return ImmutableSet.<Tag>of(
+            Tag.builder()
+                  .account("admin")
+                  .domain("ROOT")
+                  .domainId("79dc06c4-4432-11e4-b70d-000c29e19aa0")
+                  .key("test-tag")
+                  .resourceId("54fe1d53-5d73-4184-8b62-948b9d8e08fb")
+                  .resourceType(Tag.ResourceType.TEMPLATE)
+                  .value("true").build()
+      );
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTemplatesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTemplatesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTemplatesResponseTest.java
index bd5980e..d33a206 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTemplatesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListTemplatesResponseTest.java
@@ -18,6 +18,7 @@ package org.jclouds.cloudstack.parse;
 
 import java.util.Set;
 
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.Template;
 import org.jclouds.cloudstack.domain.Template.Format;
 import org.jclouds.cloudstack.domain.Template.Type;
@@ -72,6 +73,8 @@ public class ListTemplatesResponseTest extends BaseSetParserTest<Template> {
                   .ready(true).passwordEnabled(false).format(Format.QCOW2).featured(false).crossZones(false)
                   .OSTypeId("14").OSType("CentOS 5.4 (64-bit)").account("rs3").zoneId("2").zone("Chicago")
                   .size(10737418240l).type(Type.USER).hypervisor("KVM").domain("ROOT").domainId("1").extractable(false)
+                  .tags(ImmutableSet.of(Tag.builder().account("rs3").domain("ROOT").domainId("1").key("some-tag")
+                        .resourceId("241").resourceType(Tag.ResourceType.TEMPLATE).value("some-value").build()))
                   .build());
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponse3xTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponse3xTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponse3xTest.java
index a891f4c..28f4bbd 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponse3xTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponse3xTest.java
@@ -20,6 +20,7 @@ import java.util.Set;
 
 import org.jclouds.cloudstack.domain.GuestIPType;
 import org.jclouds.cloudstack.domain.NIC;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.TrafficType;
 import org.jclouds.cloudstack.domain.VirtualMachine;
 import org.jclouds.date.internal.SimpleDateFormatDateService;
@@ -68,9 +69,19 @@ public class ListVirtualMachinesResponse3xTest extends BaseSetParserTest<Virtual
                              .publicIP("72.52.126.110")
                              .publicIPId("e202aafb-ab41-4dc0-80e9-9fcd64fbf45c")
             .nics(ImmutableSet.of(NIC.builder().id("48640c5e-90f3-45bd-abd2-a108ca8957ac").
-                                  networkId("c0d5db5b-f7d5-44e1-b854-21ecd1a09dbf").netmask("255.255.255.0").gateway("10.1.1.1")
-                                  .IPAddress("10.1.1.227").trafficType(TrafficType.GUEST).guestIPType(GuestIPType.ISOLATED)
-                                  .isDefault(true).build())).build());
+                  networkId("c0d5db5b-f7d5-44e1-b854-21ecd1a09dbf").netmask("255.255.255.0").gateway("10.1.1.1")
+                  .IPAddress("10.1.1.227").trafficType(TrafficType.GUEST).guestIPType(GuestIPType.ISOLATED)
+                  .isDefault(true).build()))
+            .tags(Tag.builder()
+                  .account("jcloud2")
+                  .domain("jCloud")
+                  .domainId("ea66e3a5-d007-42e8-a0de-ec5ce778a1d7")
+                  .key("some-tag")
+                  .resourceId("fee2ccb3-c1f2-4e7b-8465-42b390e10dff")
+                  .resourceType(Tag.ResourceType.USER_VM)
+                  .value("some-value")
+                  .build())
+            .build());
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListZonesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListZonesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListZonesResponseTest.java
index f69213d..644fea6 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListZonesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListZonesResponseTest.java
@@ -19,6 +19,7 @@ package org.jclouds.cloudstack.parse;
 import java.util.Set;
 
 import org.jclouds.cloudstack.domain.NetworkType;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.Zone;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.rest.annotations.SelectJson;
@@ -37,8 +38,26 @@ public class ListZonesResponseTest extends BaseSetParserTest<Zone> {
    @Override
    @SelectJson("zone")
    public Set<Zone> expected() {
-      return ImmutableSet.of(Zone.builder().id("1").name("San Jose 1").networkType(NetworkType.ADVANCED)
-            .securityGroupsEnabled(false).build(),
-            Zone.builder().id("2").name("Chicago").networkType(NetworkType.ADVANCED).securityGroupsEnabled(true).build());
+      return          ImmutableSet.of(
+            Zone.builder()
+                  .id("1")
+                  .name("San Jose 1")
+                  .networkType(NetworkType.ADVANCED)
+                  .securityGroupsEnabled(false).build(),
+            Zone.builder()
+                  .id("2")
+                  .name("Chicago")
+                  .networkType(NetworkType.ADVANCED)
+                  .securityGroupsEnabled(true)
+                  .tags(Tag.builder()
+                        .account("1")
+                        .domain("ROOT")
+                        .domainId("1")
+                        .key("some-tag")
+                        .resourceId("2")
+                        .resourceType(Tag.ResourceType.ZONE)
+                        .value("some-value")
+                        .build())
+                  .build());
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/createtagsresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/createtagsresponse.json b/apis/cloudstack/src/test/resources/createtagsresponse.json
new file mode 100644
index 0000000..e930368
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/createtagsresponse.json
@@ -0,0 +1 @@
+{ "createtagsresponse" : {"jobid":"32cfab73-f221-4b2b-a728-a73e924ac95d"} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/deletetagsresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/deletetagsresponse.json b/apis/cloudstack/src/test/resources/deletetagsresponse.json
new file mode 100644
index 0000000..9603f95
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/deletetagsresponse.json
@@ -0,0 +1 @@
+{ "deletetagsresponse" : {"jobid":"32cfab73-f221-4b2b-a728-a73e924ac95d"} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json b/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json
index 3ea044d..ee677b6 100644
--- a/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json
+++ b/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json
@@ -1,2 +1,17 @@
-{ "listportforwardingrulesresponse" : { "portforwardingrule" : [
-    {"id":15,"privateport":"22","protocol":"tcp","publicport":"2022","virtualmachineid":3,"virtualmachinename":"i-3-3-VM","ipaddressid":3,"ipaddress":"72.52.126.32","state":"Active","cidrlist":"0.0.0.0/1,128.0.0.0/1"} ] } }
\ No newline at end of file
+{ "listportforwardingrulesresponse": {
+    "portforwardingrule": [
+        {
+            "id": 15,
+            "privateport": "22",
+            "protocol": "tcp",
+            "publicport": "2022",
+            "virtualmachineid": 3,
+            "virtualmachinename": "i-3-3-VM",
+            "ipaddressid": 3,
+            "ipaddress": "72.52.126.32",
+            "state": "Active",
+            "cidrlist": "0.0.0.0/1,128.0.0.0/1",
+            "tags":[{"account":1,"domain":"ROOT","domainid":1,"key":"some-tag","resourceid":15, "resourcetype":"PortForwardingRule", "value":"some-value"}]
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listegressfirewallrulesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listegressfirewallrulesresponse.json b/apis/cloudstack/src/test/resources/listegressfirewallrulesresponse.json
index c76b216..0e610ef 100644
--- a/apis/cloudstack/src/test/resources/listegressfirewallrulesresponse.json
+++ b/apis/cloudstack/src/test/resources/listegressfirewallrulesresponse.json
@@ -1,4 +1,5 @@
 { "listegressfirewallrulesresponse" : { "count":3 ,"firewallrule" : [
-    {"id":2017,"protocol":"tcp","startport":"30","endport":"35","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"},
+    {"id":2017,"protocol":"tcp","startport":"30","endport":"35","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0", "tags":[]},
     {"id":2016,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"},
-    {"id":10,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":8,"ipaddress":"10.27.27.57","state":"Active","cidrlist":"0.0.0.0/0"} ] } }
\ No newline at end of file
+    {"id":10,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":8,"ipaddress":"10.27.27.57","state":"Active","cidrlist":"0.0.0.0/0",
+        "tags":[{"account":1,"domain":"ROOT","domainid":1,"key":"some-tag","resourceid":10, "resourcetype":"FirewallRule", "value":"some-value"}]} ] } }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json b/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json
index e93d76e..3acaf19 100644
--- a/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json
+++ b/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json
@@ -1,4 +1,5 @@
 { "listfirewallrulesresponse" : { "count":3 ,"firewallrule" : [
-    {"id":2017,"protocol":"tcp","startport":"30","endport":"35","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"},
+    {"id":2017,"protocol":"tcp","startport":"30","endport":"35","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0", "tags":[]},
     {"id":2016,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"},
-    {"id":10,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":8,"ipaddress":"10.27.27.57","state":"Active","cidrlist":"0.0.0.0/0"} ] } }
\ No newline at end of file
+    {"id":10,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":8,"ipaddress":"10.27.27.57","state":"Active","cidrlist":"0.0.0.0/0",
+        "tags":[{"account":1,"domain":"ROOT","domainid":1,"key":"some-tag","resourceid":10, "resourcetype":"FirewallRule", "value":"some-value"}]} ] } }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listipforwardingrulesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listipforwardingrulesresponse.json b/apis/cloudstack/src/test/resources/listipforwardingrulesresponse.json
index 984f6ee..e26059e 100644
--- a/apis/cloudstack/src/test/resources/listipforwardingrulesresponse.json
+++ b/apis/cloudstack/src/test/resources/listipforwardingrulesresponse.json
@@ -11,7 +11,8 @@
             "ipaddress": "10.27.27.64",
             "startport": 22,
             "endport": 22,
-            "state": "Active"
+            "state": "Active",
+            "tags":[{"account":1,"domain":"ROOT","domainid":1,"key":"some-tag","resourceid":66, "resourcetype":"PortForwardingRule", "value":"some-value"}]
         }]
     }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listnetworksresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listnetworksresponse.json b/apis/cloudstack/src/test/resources/listnetworksresponse.json
index 1e5fa8d..1a4a6d8 100644
--- a/apis/cloudstack/src/test/resources/listnetworksresponse.json
+++ b/apis/cloudstack/src/test/resources/listnetworksresponse.json
@@ -1 +1,95 @@
-{ "listnetworksresponse" : { "network" : [  {"id":204,"name":"Virtual Network","displaytext":"A dedicated virtualized network for your account.  The broadcast domain is contained within a VLAN and all public network access is routed out by a virtual router.","broadcastdomaintype":"Vlan","traffictype":"Guest","zoneid":1,"networkofferingid":6,"networkofferingname":"DefaultVirtualizedNetworkOffering","networkofferingdisplaytext":"Virtual Vlan","networkofferingavailability":"Required","isshared":false,"issystem":false,"state":"Implemented","related":204,"broadcasturi":"vlan://240","dns1":"8.8.8.8","type":"Virtual","account":"adrian","domainid":1,"domain":"ROOT","isdefault":true,"service":[{"name":"Vpn","capability":[{"name":"SupportedVpnTypes","value":"pptp,l2tp,ipsec"}]},{"name":"Gateway"},{"name":"UserData"},{"name":"Dhcp"},{"name":"Firewall","capability":[{"name":"SupportedSourceNatTypes","value":"per account"},{"name":"StaticNat","value":"true"},{"name":"TrafficStatistics","value":"
 per public ip"},{"name":"PortForwarding","value":"true"},{"name":"MultipleIps","value":"true"},{"name":"SupportedProtocols","value":"tcp,udp"}]},{"name":"Dns"},{"name":"Lb","capability":[{"name":"SupportedLbAlgorithms","value":"roundrobin,leastconn,source"},{"name":"SupportedProtocols","value":"tcp, udp"}]}],"networkdomain":"cs3cloud.internal"} ] } }
\ No newline at end of file
+{ "listnetworksresponse": {
+    "network": [
+        {
+            "id": 204,
+            "name": "Virtual Network",
+            "displaytext": "A dedicated virtualized network for your account.  The broadcast domain is contained within a VLAN and all public network access is routed out by a virtual router.",
+            "broadcastdomaintype": "Vlan",
+            "traffictype": "Guest",
+            "zoneid": 1,
+            "networkofferingid": 6,
+            "networkofferingname": "DefaultVirtualizedNetworkOffering",
+            "networkofferingdisplaytext": "Virtual Vlan",
+            "networkofferingavailability": "Required",
+            "isshared": false,
+            "issystem": false,
+            "state": "Implemented",
+            "related": 204,
+            "broadcasturi": "vlan://240",
+            "dns1": "8.8.8.8",
+            "type": "Virtual",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "isdefault": true,
+            "service": [
+                {
+                    "name": "Vpn",
+                    "capability": [
+                        {
+                            "name": "SupportedVpnTypes",
+                            "value": "pptp,l2tp,ipsec"
+                        }
+                    ]
+                },
+                {
+                    "name": "Gateway"
+                },
+                {
+                    "name": "UserData"
+                },
+                {
+                    "name": "Dhcp"
+                },
+                {
+                    "name": "Firewall",
+                    "capability": [
+                        {
+                            "name": "SupportedSourceNatTypes",
+                            "value": "per account"
+                        },
+                        {
+                            "name": "StaticNat",
+                            "value": "true"
+                        },
+                        {
+                            "name": "TrafficStatistics",
+                            "value": "per public ip"
+                        },
+                        {
+                            "name": "PortForwarding",
+                            "value": "true"
+                        },
+                        {
+                            "name": "MultipleIps",
+                            "value": "true"
+                        },
+                        {
+                            "name": "SupportedProtocols",
+                            "value": "tcp,udp"
+                        }
+                    ]
+                },
+                {
+                    "name": "Dns"
+                },
+                {
+                    "name": "Lb",
+                    "capability": [
+                        {
+                            "name": "SupportedLbAlgorithms",
+                            "value": "roundrobin,leastconn,source"
+                        },
+                        {
+                            "name": "SupportedProtocols",
+                            "value": "tcp, udp"
+                        }
+                    ]
+                }
+            ],
+            "networkdomain": "cs3cloud.internal",
+            "tags":[{"account":1,"domain":"ROOT","domainid":1,"key":"some-tag","resourceid":204, "resourcetype":"Network", "value":"some-value"}]
+
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listportforwardingrulesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listportforwardingrulesresponse.json b/apis/cloudstack/src/test/resources/listportforwardingrulesresponse.json
index c385f7e..6681bcc 100644
--- a/apis/cloudstack/src/test/resources/listportforwardingrulesresponse.json
+++ b/apis/cloudstack/src/test/resources/listportforwardingrulesresponse.json
@@ -1 +1,29 @@
-{ "listportforwardingrulesresponse" : { "portforwardingrule" : [  {"id":18,"privateport":"22","protocol":"tcp","publicport":"22","virtualmachineid":89,"virtualmachinename":"i-3-89-VM","ipaddressid":34,"ipaddress":"72.52.126.63","state":"Active"}, {"id":15,"privateport":"22","protocol":"tcp","publicport":"2022","virtualmachineid":3,"virtualmachinename":"i-3-3-VM","ipaddressid":3,"ipaddress":"72.52.126.32","state":"Active","cidrlist":"0.0.0.0/1,128.0.0.0/1"} ] } }
\ No newline at end of file
+{ "listportforwardingrulesresponse": {
+    "portforwardingrule": [
+        {
+            "id": 18,
+            "privateport": "22",
+            "protocol": "tcp",
+            "publicport": "22",
+            "virtualmachineid": 89,
+            "virtualmachinename": "i-3-89-VM",
+            "ipaddressid": 34,
+            "ipaddress": "72.52.126.63",
+            "state": "Active",
+            "tags": []
+        },
+        {
+            "id": 15,
+            "privateport": "22",
+            "protocol": "tcp",
+            "publicport": "2022",
+            "virtualmachineid": 3,
+            "virtualmachinename": "i-3-3-VM",
+            "ipaddressid": 3,
+            "ipaddress": "72.52.126.32",
+            "state": "Active",
+            "cidrlist": "0.0.0.0/1,128.0.0.0/1",
+            "tags":[{"account":1,"domain":"ROOT","domainid":1,"key":"some-tag","resourceid":15, "resourcetype":"PortForwardingRule", "value":"some-value"}]
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listprojectsresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listprojectsresponse.json b/apis/cloudstack/src/test/resources/listprojectsresponse.json
index 33273ef..f2562c6 100644
--- a/apis/cloudstack/src/test/resources/listprojectsresponse.json
+++ b/apis/cloudstack/src/test/resources/listprojectsresponse.json
@@ -1 +1,35 @@
-{ "listprojectsresponse" : { "count":2 ,"project" : [  {"id":"489da162-0b77-489d-b044-ce39aa018b1f","name":"NN-HA-T1","displaytext":"","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","account":"thyde","state":"Active"}, {"id":"1c11f22c-15ac-4fa7-b833-4d748df317b7","name":"hive","displaytext":"Hive","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","account":"prasadm","state":"Active"} ] } }
\ No newline at end of file
+{ "listprojectsresponse": {
+    "count": 2,
+    "project": [
+        {
+            "id": "489da162-0b77-489d-b044-ce39aa018b1f",
+            "name": "NN-HA-T1",
+            "displaytext": "",
+            "domainid": "41a4917b-7952-499d-ba7f-4c57464d3dc8",
+            "domain": "ROOT",
+            "account": "thyde",
+            "state": "Active",
+            "tags": []
+        },
+        {
+            "id": "1c11f22c-15ac-4fa7-b833-4d748df317b7",
+            "name": "hive",
+            "displaytext": "Hive",
+            "domainid": "41a4917b-7952-499d-ba7f-4c57464d3dc8",
+            "domain": "ROOT",
+            "account": "prasadm",
+            "state": "Active",
+            "tags": [
+                {
+                    "account": "prasadm",
+                    "domain": "ROOT",
+                    "domainid": "41a4917b-7952-499d-ba7f-4c57464d3dc8",
+                    "key": "some-tag",
+                    "resourceid": "1c11f22c-15ac-4fa7-b833-4d748df317b7",
+                    "resourcetype": "Project",
+                    "value": "some-value"
+                }
+            ]
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listpublicipaddressesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listpublicipaddressesresponse.json b/apis/cloudstack/src/test/resources/listpublicipaddressesresponse.json
index 914c95a..41f0a6d 100644
--- a/apis/cloudstack/src/test/resources/listpublicipaddressesresponse.json
+++ b/apis/cloudstack/src/test/resources/listpublicipaddressesresponse.json
@@ -1 +1,31 @@
-{ "listpublicipaddressesresponse" : { "publicipaddress" : [  {"id":30,"ipaddress":"72.52.126.59","allocated":"2011-02-19T21:15:01-0800","zoneid":1,"zonename":"San Jose 1","issourcenat":false,"account":"adrian","domainid":1,"domain":"ROOT","forvirtualnetwork":true,"isstaticnat":false,"associatednetworkid":204,"networkid":200,"state":"Allocated"} ] } }
\ No newline at end of file
+{ "listpublicipaddressesresponse": {
+    "publicipaddress": [
+        {
+            "id": 30,
+            "ipaddress": "72.52.126.59",
+            "allocated": "2011-02-19T21:15:01-0800",
+            "zoneid": 1,
+            "zonename": "San Jose 1",
+            "issourcenat": false,
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "forvirtualnetwork": true,
+            "isstaticnat": false,
+            "associatednetworkid": 204,
+            "networkid": 200,
+            "state": "Allocated",
+            "tags": [
+                {
+                    "account": "adrian",
+                    "domain": "ROOT",
+                    "domainid": 1,
+                    "key": "some-tag",
+                    "resourceid": 30,
+                    "resourcetype": "PublicIpAddress",
+                    "value": "some-value"
+                }
+            ]
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listsecuritygroupsresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listsecuritygroupsresponse.json b/apis/cloudstack/src/test/resources/listsecuritygroupsresponse.json
index 25136a3..1dfbdbd 100644
--- a/apis/cloudstack/src/test/resources/listsecuritygroupsresponse.json
+++ b/apis/cloudstack/src/test/resources/listsecuritygroupsresponse.json
@@ -1 +1,117 @@
-{ "listsecuritygroupsresponse" : { "securitygroup" : [  {"id":12,"name":"adriancole","account":"adrian","domainid":1,"domain":"ROOT"}, {"id":13,"name":"default","description":"description","account":"adrian","domainid":1,"domain":"ROOT","ingressrule":[{"ruleid":5,"protocol":"tcp","startport":22,"endport":22,"securitygroupname":"adriancole","account":"adrian"},{"ruleid":6,"protocol":"udp","startport":11,"endport":11,"cidr":"1.1.1.1/24"}]}, {"id":14,"name":"1","description":"description","account":"adrian","domainid":1,"domain":"ROOT","ingressrule":[{"ruleid":7,"protocol":"tcp","startport":10,"endport":10,"cidr":"1.1.1.1/24"},{"ruleid":8,"protocol":"tcp","startport":10,"endport":10,"cidr":"2.2.2.2/16"}]}, {"id":15,"name":"2","description":"description","account":"adrian","domainid":1,"domain":"ROOT"}, {"id":16,"name":"with1and2","description":"description","account":"adrian","domainid":1,"domain":"ROOT","ingressrule":[{"ruleid":9,"protocol":"icmp","icmptype":-1,"icmpcode":-1,"security
 groupname":"1","account":"adrian"},{"ruleid":10,"protocol":"tcp","startport":22,"endport":22,"securitygroupname":"1","account":"adrian"},{"ruleid":11,"protocol":"tcp","startport":22,"endport":22,"securitygroupname":"2","account":"adrian"}]} ] } }
\ No newline at end of file
+{ "listsecuritygroupsresponse": {
+    "securitygroup": [
+        {
+            "id": 12,
+            "name": "adriancole",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "tags":[]
+        },
+        {
+            "id": 13,
+            "name": "default",
+            "description": "description",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "ingressrule": [
+                {
+                    "ruleid": 5,
+                    "protocol": "tcp",
+                    "startport": 22,
+                    "endport": 22,
+                    "securitygroupname": "adriancole",
+                    "account": "adrian"
+                },
+                {
+                    "ruleid": 6,
+                    "protocol": "udp",
+                    "startport": 11,
+                    "endport": 11,
+                    "cidr": "1.1.1.1/24"
+                }
+            ],
+            "tags": []
+        },
+        {
+            "id": 14,
+            "name": "1",
+            "description": "description",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "ingressrule": [
+                {
+                    "ruleid": 7,
+                    "protocol": "tcp",
+                    "startport": 10,
+                    "endport": 10,
+                    "cidr": "1.1.1.1/24"
+                },
+                {
+                    "ruleid": 8,
+                    "protocol": "tcp",
+                    "startport": 10,
+                    "endport": 10,
+                    "cidr": "2.2.2.2/16"
+                }
+            ],
+            "tags": []
+        },
+        {
+            "id": 15,
+            "name": "2",
+            "description": "description",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "tags": []
+        },
+        {
+            "id": 16,
+            "name": "with1and2",
+            "description": "description",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "ingressrule": [
+                {
+                    "ruleid": 9,
+                    "protocol": "icmp",
+                    "icmptype": -1,
+                    "icmpcode": -1,
+                    "securitygroupname": "1",
+                    "account": "adrian"
+                },
+                {
+                    "ruleid": 10,
+                    "protocol": "tcp",
+                    "startport": 22,
+                    "endport": 22,
+                    "securitygroupname": "1",
+                    "account": "adrian"
+                },
+                {
+                    "ruleid": 11,
+                    "protocol": "tcp",
+                    "startport": 22,
+                    "endport": 22,
+                    "securitygroupname": "2",
+                    "account": "adrian"
+                }
+            ],
+            "tags": [
+                {
+                    "account": "adrian",
+                    "domain": "ROOT",
+                    "domainid": 1,
+                    "key": "some-tag",
+                    "resourceid": 16,
+                    "resourcetype": "SecurityGroup",
+                    "value": "some-value"
+                }
+            ]
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listtagsresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listtagsresponse.json b/apis/cloudstack/src/test/resources/listtagsresponse.json
new file mode 100644
index 0000000..535cc13
--- /dev/null
+++ b/apis/cloudstack/src/test/resources/listtagsresponse.json
@@ -0,0 +1,16 @@
+{
+    "listtagsresponse": {
+        "count": 1,
+        "tag": [
+            {
+                "key": "test-tag",
+                "value": "true",
+                "resourcetype": "Template",
+                "resourceid": "54fe1d53-5d73-4184-8b62-948b9d8e08fb",
+                "account": "admin",
+                "domainid": "79dc06c4-4432-11e4-b70d-000c29e19aa0",
+                "domain": "ROOT"
+            }
+        ]
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listtemplatesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listtemplatesresponse.json b/apis/cloudstack/src/test/resources/listtemplatesresponse.json
index 140e8ca..928d2f8 100644
--- a/apis/cloudstack/src/test/resources/listtemplatesresponse.json
+++ b/apis/cloudstack/src/test/resources/listtemplatesresponse.json
@@ -1 +1,129 @@
-{ "listtemplatesresponse" : { "template" : [  {"id":2,"name":"CentOS 5.3(64-bit) no GUI (XenServer)","displaytext":"CentOS 5.3(64-bit) no GUI (XenServer)","ispublic":true,"created":"2011-03-20T19:17:48-0700","isready":false,"passwordenabled":false,"format":"VHD","isfeatured":true,"crossZones":true,"ostypeid":11,"ostypename":"CentOS 5.3 (32-bit)","account":"system","zoneid":2,"zonename":"Chicago","templatetype":"BUILTIN","hypervisor":"XenServer","domain":"ROOT","domainid":1,"isextractable":true}, {"id":4,"name":"CentOS 5.5(64-bit) no GUI (KVM)","displaytext":"CentOS 5.5(64-bit) no GUI (KVM)","ispublic":true,"created":"2011-03-20T19:17:48-0700","isready":true,"passwordenabled":false,"format":"QCOW2","isfeatured":true,"crossZones":true,"ostypeid":112,"ostypename":"CentOS 5.5 (64-bit)","account":"system","zoneid":2,"zonename":"Chicago","size":8589934592,"templatetype":"BUILTIN","hypervisor":"KVM","domain":"ROOT","domainid":1,"isextractable":true}, {"id":203,"name":"Windows 7 KVM","displ
 aytext":"Windows 7 KVM","ispublic":true,"created":"2011-03-20T22:02:18-0700","isready":true,"passwordenabled":false,"format":"QCOW2","isfeatured":true,"crossZones":false,"ostypeid":48,"ostypename":"Windows 7 (32-bit)","account":"admin","zoneid":2,"zonename":"Chicago","size":17179869184,"templatetype":"USER","hypervisor":"KVM","domain":"ROOT","domainid":1,"isextractable":false}, {"id":7,"name":"CentOS 5.3(64-bit) no GUI (vSphere)","displaytext":"CentOS 5.3(64-bit) no GUI (vSphere)","ispublic":true,"created":"2011-03-20T19:17:48-0700","isready":false,"passwordenabled":false,"format":"OVA","isfeatured":true,"crossZones":true,"ostypeid":12,"ostypename":"CentOS 5.3 (64-bit)","account":"system","zoneid":2,"zonename":"Chicago","templatetype":"BUILTIN","hypervisor":"VMware","domain":"ROOT","domainid":1,"isextractable":true}, {"id":241,"name":"kvmdev4","displaytext":"v5.6.28_Dev4","ispublic":true,"created":"2011-04-21T09:43:25-0700","isready":true,"passwordenabled":false,"format":"QCOW2","is
 featured":false,"crossZones":false,"ostypeid":14,"ostypename":"CentOS 5.4 (64-bit)","account":"rs3","zoneid":2,"zonename":"Chicago","size":10737418240,"templatetype":"USER","hypervisor":"KVM","domain":"ROOT","domainid":1,"isextractable":false} ] } }
\ No newline at end of file
+{ "listtemplatesresponse": {
+    "template": [
+        {
+            "id": 2,
+            "name": "CentOS 5.3(64-bit) no GUI (XenServer)",
+            "displaytext": "CentOS 5.3(64-bit) no GUI (XenServer)",
+            "ispublic": true,
+            "created": "2011-03-20T19:17:48-0700",
+            "isready": false,
+            "passwordenabled": false,
+            "format": "VHD",
+            "isfeatured": true,
+            "crossZones": true,
+            "ostypeid": 11,
+            "ostypename": "CentOS 5.3 (32-bit)",
+            "account": "system",
+            "zoneid": 2,
+            "zonename": "Chicago",
+            "templatetype": "BUILTIN",
+            "hypervisor": "XenServer",
+            "domain": "ROOT",
+            "domainid": 1,
+            "isextractable": true,
+            "tags": []
+        },
+        {
+            "id": 4,
+            "name": "CentOS 5.5(64-bit) no GUI (KVM)",
+            "displaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
+            "ispublic": true,
+            "created": "2011-03-20T19:17:48-0700",
+            "isready": true,
+            "passwordenabled": false,
+            "format": "QCOW2",
+            "isfeatured": true,
+            "crossZones": true,
+            "ostypeid": 112,
+            "ostypename": "CentOS 5.5 (64-bit)",
+            "account": "system",
+            "zoneid": 2,
+            "zonename": "Chicago",
+            "size": 8589934592,
+            "templatetype": "BUILTIN",
+            "hypervisor": "KVM",
+            "domain": "ROOT",
+            "domainid": 1,
+            "isextractable": true
+        },
+        {
+            "id": 203,
+            "name": "Windows 7 KVM",
+            "displaytext": "Windows 7 KVM",
+            "ispublic": true,
+            "created": "2011-03-20T22:02:18-0700",
+            "isready": true,
+            "passwordenabled": false,
+            "format": "QCOW2",
+            "isfeatured": true,
+            "crossZones": false,
+            "ostypeid": 48,
+            "ostypename": "Windows 7 (32-bit)",
+            "account": "admin",
+            "zoneid": 2,
+            "zonename": "Chicago",
+            "size": 17179869184,
+            "templatetype": "USER",
+            "hypervisor": "KVM",
+            "domain": "ROOT",
+            "domainid": 1,
+            "isextractable": false
+        },
+        {
+            "id": 7,
+            "name": "CentOS 5.3(64-bit) no GUI (vSphere)",
+            "displaytext": "CentOS 5.3(64-bit) no GUI (vSphere)",
+            "ispublic": true,
+            "created": "2011-03-20T19:17:48-0700",
+            "isready": false,
+            "passwordenabled": false,
+            "format": "OVA",
+            "isfeatured": true,
+            "crossZones": true,
+            "ostypeid": 12,
+            "ostypename": "CentOS 5.3 (64-bit)",
+            "account": "system",
+            "zoneid": 2,
+            "zonename": "Chicago",
+            "templatetype": "BUILTIN",
+            "hypervisor": "VMware",
+            "domain": "ROOT",
+            "domainid": 1,
+            "isextractable": true
+        },
+        {
+            "id": 241,
+            "name": "kvmdev4",
+            "displaytext": "v5.6.28_Dev4",
+            "ispublic": true,
+            "created": "2011-04-21T09:43:25-0700",
+            "isready": true,
+            "passwordenabled": false,
+            "format": "QCOW2",
+            "isfeatured": false,
+            "crossZones": false,
+            "ostypeid": 14,
+            "ostypename": "CentOS 5.4 (64-bit)",
+            "account": "rs3",
+            "zoneid": 2,
+            "zonename": "Chicago",
+            "size": 10737418240,
+            "templatetype": "USER",
+            "hypervisor": "KVM",
+            "domain": "ROOT",
+            "domainid": 1,
+            "isextractable": false,
+            "tags": [
+                {
+                    "account": "rs3",
+                    "domain": "ROOT",
+                    "domainid": 1,
+                    "key": "some-tag",
+                    "resourceid": 241,
+                    "resourcetype": "Template",
+                    "value": "some-value"
+                }
+            ]
+        }
+    ]
+} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listvirtualmachinesresponse3x.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listvirtualmachinesresponse3x.json b/apis/cloudstack/src/test/resources/listvirtualmachinesresponse3x.json
index 5a41ac6..b6d4dde 100644
--- a/apis/cloudstack/src/test/resources/listvirtualmachinesresponse3x.json
+++ b/apis/cloudstack/src/test/resources/listvirtualmachinesresponse3x.json
@@ -1 +1,56 @@
-{ "listvirtualmachinesresponse" : { "count":1 ,"virtualmachine" : [  {"id":"fee2ccb3-c1f2-4e7b-8465-42b390e10dff","name":"cloudstack-r-611","displayname":"cloudstack-r-611","account":"jcloud2","domainid":"ea66e3a5-d007-42e8-a0de-ec5ce778a1d7","domain":"jCloud","created":"2012-05-22T09:18:28-0700","state":"Running","haenable":false,"zoneid":"1","zonename":"Santa Clara Zone","templateid":"5c65f152-a4bc-4405-a756-fd10841a9aa7","templatename":"jclouds-6d4bdc29","templatedisplaytext":"jclouds live testCreateTemplate","passwordenabled":false,"serviceofferingid":"5305750d-df71-4da9-8cd0-e23c2236a6e2","serviceofferingname":"Micro Instance","cpunumber":1,"cpuspeed":500,"memory":256,"guestosid":"6dcd58ce-1ec6-432c-af0b-9ab4ca9207d9","rootdeviceid":0,"rootdevicetype":"IscsiLUN","securitygroup":[],"nic":[{"id":"48640c5e-90f3-45bd-abd2-a108ca8957ac","networkid":"c0d5db5b-f7d5-44e1-b854-21ecd1a09dbf","netmask":"255.255.255.0","gateway":"10.1.1.1","ipaddress":"10.1.1.227","traffictype":"Guest","ty
 pe":"Isolated","isdefault":true}],"publicipid":"e202aafb-ab41-4dc0-80e9-9fcd64fbf45c","publicip":"72.52.126.110"} ] } }"
+{ "listvirtualmachinesresponse": {
+    "count": 1,
+    "virtualmachine": [
+        {
+            "id": "fee2ccb3-c1f2-4e7b-8465-42b390e10dff",
+            "name": "cloudstack-r-611",
+            "displayname": "cloudstack-r-611",
+            "account": "jcloud2",
+            "domainid": "ea66e3a5-d007-42e8-a0de-ec5ce778a1d7",
+            "domain": "jCloud",
+            "created": "2012-05-22T09:18:28-0700",
+            "state": "Running",
+            "haenable": false,
+            "zoneid": "1",
+            "zonename": "Santa Clara Zone",
+            "templateid": "5c65f152-a4bc-4405-a756-fd10841a9aa7",
+            "templatename": "jclouds-6d4bdc29",
+            "templatedisplaytext": "jclouds live testCreateTemplate",
+            "passwordenabled": false,
+            "serviceofferingid": "5305750d-df71-4da9-8cd0-e23c2236a6e2",
+            "serviceofferingname": "Micro Instance",
+            "cpunumber": 1,
+            "cpuspeed": 500,
+            "memory": 256,
+            "guestosid": "6dcd58ce-1ec6-432c-af0b-9ab4ca9207d9",
+            "rootdeviceid": 0,
+            "rootdevicetype": "IscsiLUN",
+            "securitygroup": [],
+            "nic": [
+                {
+                    "id": "48640c5e-90f3-45bd-abd2-a108ca8957ac",
+                    "networkid": "c0d5db5b-f7d5-44e1-b854-21ecd1a09dbf",
+                    "netmask": "255.255.255.0",
+                    "gateway": "10.1.1.1",
+                    "ipaddress": "10.1.1.227",
+                    "traffictype": "Guest",
+                    "type": "Isolated",
+                    "isdefault": true
+                }
+            ],
+            "publicipid": "e202aafb-ab41-4dc0-80e9-9fcd64fbf45c",
+            "publicip": "72.52.126.110",
+            "tags": [
+                {
+                    "account": "jcloud2",
+                    "domain": "jCloud",
+                    "domainid": "ea66e3a5-d007-42e8-a0de-ec5ce778a1d7",
+                    "key": "some-tag",
+                    "resourceid": "fee2ccb3-c1f2-4e7b-8465-42b390e10dff",
+                    "resourcetype": "UserVm",
+                    "value": "some-value"
+                }
+            ]
+        }
+    ]
+} }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listvolumesreponse-imageextension.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listvolumesreponse-imageextension.json b/apis/cloudstack/src/test/resources/listvolumesreponse-imageextension.json
deleted file mode 100644
index 420f365..0000000
--- a/apis/cloudstack/src/test/resources/listvolumesreponse-imageextension.json
+++ /dev/null
@@ -1,2 +0,0 @@
-{ "listvolumesresponse" : { "count":1 ,"volume" : [
-{"id":"fe1ada16-57a0-40ae-b577-01a153690fb4","name":"ROOT-69942","zoneid":"1","zonename":"San Jose 1","type":"ROOT","deviceid":0,"virtualmachineid":"3239ade9-fd25-405c-8eda-59f0313a3fb0","vmname":"apb-cent32-bld","vmdisplayname":"apb-cent32-bld","vmstate":"Stopped","size":139264,"created":"2013-04-16T16:25:57-0700","state":"Ready","account":"andrew","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","storagetype":"local","hypervisor":"KVM","storage":"c2422.halxg.cloudera.com","destroyed":false,"serviceofferingid":"7cc4f8c3-7c56-4155-9916-9f42072ea712","serviceofferingname":"Tiny","serviceofferingdisplaytext":"Tiny (1 core, 1GB RAM)","isextractable":false} ] } }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/resources/listzonesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listzonesresponse.json b/apis/cloudstack/src/test/resources/listzonesresponse.json
index 4714b86..bf05a8c 100644
--- a/apis/cloudstack/src/test/resources/listzonesresponse.json
+++ b/apis/cloudstack/src/test/resources/listzonesresponse.json
@@ -1 +1,29 @@
-{ "listzonesresponse" : { "zone" : [  {"id":1,"name":"San Jose 1","networktype":"Advanced","securitygroupsenabled":false}, {"id":2,"name":"Chicago","networktype":"Advanced","securitygroupsenabled":true} ] } }
\ No newline at end of file
+{ "listzonesresponse": {
+    "zone": [
+        {
+            "id": 1,
+            "name": "San Jose 1",
+            "networktype": "Advanced",
+            "securitygroupsenabled": false,
+            "tags": []
+        },
+        {
+            "id": 2,
+            "name": "Chicago",
+            "networktype": "Advanced",
+            "securitygroupsenabled": true,
+            "tags": [
+                {
+                    "account": 1,
+                    "domain": "ROOT",
+                    "domainid": 1,
+                    "key": "some-tag",
+                    "resourceid": 2,
+                    "resourcetype": "Zone",
+                    "value": "some-value"
+                }
+            ]
+
+        }
+    ]
+} }
\ No newline at end of file


[6/7] git commit: CloudStack doesn't do empty tag values

Posted by ab...@apache.org.
CloudStack doesn't do empty tag values


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/2ac80c09
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/2ac80c09
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/2ac80c09

Branch: refs/heads/jclouds-756
Commit: 2ac80c09495f24fe53be9449618c0d5fbaefd620
Parents: e3b78b7
Author: Andrew Bayer <an...@gmail.com>
Authored: Tue Oct 21 15:20:38 2014 -0700
Committer: Andrew Bayer <an...@gmail.com>
Committed: Tue Oct 21 15:20:38 2014 -0700

----------------------------------------------------------------------
 .../compute/functions/VirtualMachineToNodeMetadata.java      | 8 ++++++--
 .../compute/strategy/CloudStackComputeServiceAdapter.java    | 8 +++++++-
 .../cloudstack/parse/ListVirtualMachinesResponseTest.java    | 2 +-
 .../src/test/resources/listvirtualmachinesresponse.json      | 2 +-
 4 files changed, 15 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/2ac80c09/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
index 5421396..a9596e3 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
@@ -17,10 +17,12 @@
 package org.jclouds.cloudstack.compute.functions;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.base.Predicates.not;
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Maps.filterValues;
 import static com.google.common.collect.Sets.newHashSet;
-import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
 import static org.jclouds.location.predicates.LocationPredicates.idEquals;
 import static org.jclouds.util.InetAddresses2.isPrivateIPAddress;
 
@@ -126,7 +128,9 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
             tagsBuilder.put(tag.getKey(), tag.getValue());
          }
 
-         addMetadataAndParseTagsFromValuesOfEmptyString(builder, tagsBuilder.build());
+         Map<String, String> tagMap = tagsBuilder.build();
+         builder.tags(filterValues(tagMap, equalTo("jclouds-empty-tag-placeholder")).keySet())
+               .userMetadata(filterValues(tagMap, not(equalTo("jclouds-empty-tag-placeholder"))));
       }
 
       builder.hardware(new HardwareBuilder()

http://git-wip-us.apache.org/repos/asf/jclouds/blob/2ac80c09/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
index 3e666a7..9387844 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
@@ -40,6 +40,7 @@ import java.util.Set;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
 import com.google.common.collect.Sets;
@@ -244,7 +245,12 @@ public class CloudStackComputeServiceAdapter implements
       }
 
       try {
-         Map<String, String> common = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
+         ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder();
+         builder.putAll(template.getOptions().getUserMetadata());
+         for (String tag : template.getOptions().getTags())
+            builder.put(tag, "jclouds-empty-tag-placeholder");
+         Map<String, String> common = builder.build();
+
          if (!common.isEmpty()) {
             logger.debug(">> adding tags %s to virtualmachine(%s)", common, vm.getId());
             CreateTagsOptions tagOptions = CreateTagsOptions.Builder.resourceIds(vm.getId())

http://git-wip-us.apache.org/repos/asf/jclouds/blob/2ac80c09/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
index 4b0094b..8d2d8e6 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
@@ -85,7 +85,7 @@ public class ListVirtualMachinesResponseTest extends BaseSetParserTest<VirtualMa
                         .resourceId("54")
                         .resourceType(Tag.ResourceType.USER_VM)
                         .key("another-tag")
-                        .value("")
+                        .value("jclouds-empty-tag-placeholder")
                         .domain("ROOT")
                         .domainId("1")
                         .build()))

http://git-wip-us.apache.org/repos/asf/jclouds/blob/2ac80c09/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json b/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
index f5c0b04..a623589 100644
--- a/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
+++ b/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
@@ -57,7 +57,7 @@
                     "key": "another-tag",
                     "resourceid": "54",
                     "resourcetype": "UserVm",
-                    "value": ""
+                    "value": "jclouds-empty-tag-placeholder"
                 }
 
             ]


[3/7] JCLOUDS-756. Add support for tags to CloudStack.

Posted by ab...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/VirtualMachine.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/VirtualMachine.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/VirtualMachine.java
index 0e23a38..920914c 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/VirtualMachine.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/VirtualMachine.java
@@ -111,6 +111,7 @@ public class VirtualMachine {
       protected Set<NIC> nics = ImmutableSet.of();
       protected String hypervisor;
       protected Set<SecurityGroup> securityGroups = ImmutableSet.of();
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see VirtualMachine#getId()
@@ -464,12 +465,24 @@ public class VirtualMachine {
          return securityGroups(ImmutableSet.copyOf(in));
       }
 
+      /**
+       * @see VirtualMachine#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public VirtualMachine build() {
          return new VirtualMachine(id, account, cpuCount, cpuSpeed, cpuUsed, displayName, created, domain, domainId,
                usesVirtualNetwork, group, groupId, guestOSId, HAEnabled, hostId, hostname, IPAddress, ISODisplayText, ISOId,
                ISOName, jobId, jobStatus, memory, name, networkKbsRead, networkKbsWrite, password, passwordEnabled, publicIP,
                publicIPId, rootDeviceId, rootDeviceType, serviceOfferingId, serviceOfferingName, state, templateDisplayText,
-               templateId, templateName, zoneId, zoneName, nics, hypervisor, securityGroups);
+               templateId, templateName, zoneId, zoneName, nics, hypervisor, securityGroups, tags);
       }
 
       public T fromVirtualMachine(VirtualMachine in) {
@@ -516,7 +529,8 @@ public class VirtualMachine {
                .zoneName(in.getZoneName())
                .nics(in.getNICs())
                .hypervisor(in.getHypervisor())
-               .securityGroups(in.getSecurityGroups());
+               .securityGroups(in.getSecurityGroups())
+               .tags(in.getTags());
       }
    }
 
@@ -570,9 +584,10 @@ public class VirtualMachine {
    private final Set<NIC> nics;
    private final String hypervisor;
    private final Set<SecurityGroup> securityGroups;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "account", "cpunumber", "cpuspeed", "cpuused", "displayname", "created", "domain", "domainid", "forvirtualnetwork", "group", "groupid", "guestosid", "haenable", "hostid", "hostname", "ipaddress", "isodisplaytext", "isoid", "isoname", "jobid", "jobstatus", "memory", "name", "networkkbsread", "networkkbswrite", "password", "passwordenabled", "publicip", "publicipid", "rootdeviceid", "rootdevicetype", "serviceofferingid", "serviceofferingname", "state", "templatedisplaytext", "templateid", "templatename", "zoneid", "zonename", "nic", "hypervisor", "securitygroup"
+         "id", "account", "cpunumber", "cpuspeed", "cpuused", "displayname", "created", "domain", "domainid", "forvirtualnetwork", "group", "groupid", "guestosid", "haenable", "hostid", "hostname", "ipaddress", "isodisplaytext", "isoid", "isoname", "jobid", "jobstatus", "memory", "name", "networkkbsread", "networkkbswrite", "password", "passwordenabled", "publicip", "publicipid", "rootdeviceid", "rootdevicetype", "serviceofferingid", "serviceofferingname", "state", "templatedisplaytext", "templateid", "templatename", "zoneid", "zonename", "nic", "hypervisor", "securitygroup", "tags"
    })
    protected VirtualMachine(String id, @Nullable String account, long cpuCount, long cpuSpeed, @Nullable String cpuUsed,
                             @Nullable String displayName, @Nullable Date created, @Nullable String domain, @Nullable String domainId,
@@ -584,7 +599,7 @@ public class VirtualMachine {
                             @Nullable String rootDeviceType, @Nullable String serviceOfferingId, @Nullable String serviceOfferingName,
                             @Nullable VirtualMachine.State state, @Nullable String templateDisplayText, @Nullable String templateId,
                             @Nullable String templateName, @Nullable String zoneId, @Nullable String zoneName, @Nullable Set<NIC> nics,
-                            @Nullable String hypervisor, @Nullable Set<SecurityGroup> securityGroups) {
+                            @Nullable String hypervisor, @Nullable Set<SecurityGroup> securityGroups, @Nullable Set<Tag> tags) {
       Preconditions.checkArgument(Strings.isNullOrEmpty(cpuUsed) || cpuUsed.matches("^[0-9\\.|,\\-]+%$"), "cpuUsed value should be a decimal number followed by %");
       this.id = checkNotNull(id, "id");
       this.account = account;
@@ -629,6 +644,7 @@ public class VirtualMachine {
       this.nics = nics == null ? ImmutableSet.<NIC>of() : ImmutableSet.copyOf(nics);
       this.hypervisor = hypervisor;
       this.securityGroups = securityGroups == null ? ImmutableSet.<SecurityGroup>of() : ImmutableSet.copyOf(securityGroups);
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    /**
@@ -971,9 +987,16 @@ public class VirtualMachine {
       return this.securityGroups;
    }
 
+   /**
+    * @return the tags for the virtual machine
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, account, cpuCount, cpuSpeed, cpuUsed, displayName, created, domain, domainId, usesVirtualNetwork, group, groupId, guestOSId, HAEnabled, hostId, hostname, IPAddress, ISODisplayText, ISOId, ISOName, jobId, jobStatus, memory, name, networkKbsRead, networkKbsWrite, password, passwordEnabled, publicIP, publicIPId, rootDeviceId, rootDeviceType, serviceOfferingId, serviceOfferingName, state, templateDisplayText, templateId, templateName, zoneId, zoneName, nics, hypervisor, securityGroups);
+      return Objects.hashCode(id, account, cpuCount, cpuSpeed, cpuUsed, displayName, created, domain, domainId, usesVirtualNetwork, group, groupId, guestOSId, HAEnabled, hostId, hostname, IPAddress, ISODisplayText, ISOId, ISOName, jobId, jobStatus, memory, name, networkKbsRead, networkKbsWrite, password, passwordEnabled, publicIP, publicIPId, rootDeviceId, rootDeviceType, serviceOfferingId, serviceOfferingName, state, templateDisplayText, templateId, templateName, zoneId, zoneName, nics, hypervisor, securityGroups, tags);
    }
 
    @Override
@@ -1023,7 +1046,8 @@ public class VirtualMachine {
             && Objects.equal(this.zoneName, that.zoneName)
             && Objects.equal(this.nics, that.nics)
             && Objects.equal(this.hypervisor, that.hypervisor)
-            && Objects.equal(this.securityGroups, that.securityGroups);
+            && Objects.equal(this.securityGroups, that.securityGroups)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -1038,7 +1062,8 @@ public class VirtualMachine {
             .add("publicIP", publicIP).add("publicIPId", publicIPId).add("rootDeviceId", rootDeviceId).add("rootDeviceType", rootDeviceType)
             .add("serviceOfferingId", serviceOfferingId).add("serviceOfferingName", serviceOfferingName).add("state", state)
             .add("templateDisplayText", templateDisplayText).add("templateId", templateId).add("templateName", templateName)
-            .add("zoneId", zoneId).add("zoneName", zoneName).add("nics", nics).add("hypervisor", hypervisor).add("securityGroups", securityGroups);
+            .add("zoneId", zoneId).add("zoneName", zoneName).add("nics", nics).add("hypervisor", hypervisor).add("securityGroups", securityGroups)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Volume.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Volume.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Volume.java
index 563c0cc..30e3a4f 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Volume.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Volume.java
@@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.beans.ConstructorProperties;
 import java.util.Date;
 import java.util.Map;
+import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 
@@ -152,6 +153,7 @@ public class Volume {
       protected VirtualMachine.State vmState;
       protected String zoneId;
       protected String zoneName;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see Volume#getId()
@@ -401,8 +403,20 @@ public class Volume {
          return self();
       }
 
+      /**
+       * @see Volume#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public Volume build() {
-         return new Volume(id, account, attached, created, destroyed, deviceId, diskOfferingDisplayText, diskOfferingId, diskOfferingName, domain, domainId, hypervisor, isExtractable, jobId, jobStatus, name, serviceOfferingDisplayText, serviceOfferingId, serviceOfferingName, size, snapshotId, state, storage, storageType, type, virtualMachineId, vmDisplayName, vmName, vmState, zoneId, zoneName);
+         return new Volume(id, account, attached, created, destroyed, deviceId, diskOfferingDisplayText, diskOfferingId, diskOfferingName, domain, domainId, hypervisor, isExtractable, jobId, jobStatus, name, serviceOfferingDisplayText, serviceOfferingId, serviceOfferingName, size, snapshotId, state, storage, storageType, type, virtualMachineId, vmDisplayName, vmName, vmState, zoneId, zoneName, tags);
       }
 
       public T fromVolume(Volume in) {
@@ -437,7 +451,8 @@ public class Volume {
                .vmName(in.getVmName())
                .vmState(in.getVmState())
                .zoneId(in.getZoneId())
-               .zoneName(in.getZoneName());
+               .zoneName(in.getZoneName())
+               .tags(in.getTags());
       }
    }
 
@@ -479,9 +494,10 @@ public class Volume {
    private final VirtualMachine.State vmState;
    private final String zoneId;
    private final String zoneName;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "account", "attached", "created", "destroyed", "deviceid", "diskofferingdisplaytext", "diskofferingid", "diskofferingname", "domain", "domainid", "hypervisor", "isextractable", "jobid", "jobstatus", "name", "serviceofferingdisplaytext", "serviceofferingid", "serviceofferingname", "size", "snapshotid", "state", "storage", "storagetype", "type", "virtualmachineid", "vmdisplayname", "vmname", "vmstate", "zoneid", "zonename"
+         "id", "account", "attached", "created", "destroyed", "deviceid", "diskofferingdisplaytext", "diskofferingid", "diskofferingname", "domain", "domainid", "hypervisor", "isextractable", "jobid", "jobstatus", "name", "serviceofferingdisplaytext", "serviceofferingid", "serviceofferingname", "size", "snapshotid", "state", "storage", "storagetype", "type", "virtualmachineid", "vmdisplayname", "vmname", "vmstate", "zoneid", "zonename", "tags"
    })
    protected Volume(String id, @Nullable String account, @Nullable Date attached, @Nullable Date created, boolean destroyed,
                     @Nullable String deviceId, @Nullable String diskOfferingDisplayText, @Nullable String diskOfferingId,
@@ -491,7 +507,7 @@ public class Volume {
                     long size, @Nullable String snapshotId, @Nullable Volume.State state, @Nullable String storage,
                     @Nullable String storageType, @Nullable Volume.Type type, @Nullable String virtualMachineId,
                     @Nullable String vmDisplayName, @Nullable String vmName, @Nullable VirtualMachine.State vmState,
-                    @Nullable String zoneId, @Nullable String zoneName) {
+                    @Nullable String zoneId, @Nullable String zoneName, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.attached = attached;
@@ -523,6 +539,7 @@ public class Volume {
       this.vmState = vmState;
       this.zoneId = zoneId;
       this.zoneName = zoneName;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    public String getId() {
@@ -676,9 +693,16 @@ public class Volume {
       return this.zoneName;
    }
 
+   /**
+    * @return the tags for the volume
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, account, attached, created, destroyed, deviceId, diskOfferingDisplayText, diskOfferingId, diskOfferingName, domain, domainId, hypervisor, isExtractable, jobId, jobStatus, name, serviceOfferingDisplayText, serviceOfferingId, serviceOfferingName, size, snapshotId, state, storage, storageType, type, virtualMachineId, vmDisplayName, vmName, vmState, zoneId, zoneName);
+      return Objects.hashCode(id, account, attached, created, destroyed, deviceId, diskOfferingDisplayText, diskOfferingId, diskOfferingName, domain, domainId, hypervisor, isExtractable, jobId, jobStatus, name, serviceOfferingDisplayText, serviceOfferingId, serviceOfferingName, size, snapshotId, state, storage, storageType, type, virtualMachineId, vmDisplayName, vmName, vmState, zoneId, zoneName, tags);
    }
 
    @Override
@@ -716,7 +740,8 @@ public class Volume {
             && Objects.equal(this.vmName, that.vmName)
             && Objects.equal(this.vmState, that.vmState)
             && Objects.equal(this.zoneId, that.zoneId)
-            && Objects.equal(this.zoneName, that.zoneName);
+            && Objects.equal(this.zoneName, that.zoneName)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -728,7 +753,8 @@ public class Volume {
             .add("serviceOfferingDisplayText", serviceOfferingDisplayText).add("serviceOfferingId", serviceOfferingId)
             .add("serviceOfferingName", serviceOfferingName).add("size", size).add("snapshotId", snapshotId).add("state", state)
             .add("storage", storage).add("storageType", storageType).add("type", type).add("virtualMachineId", virtualMachineId)
-            .add("vmDisplayName", vmDisplayName).add("vmName", vmName).add("vmState", vmState).add("zoneId", zoneId).add("zoneName", zoneName);
+            .add("vmDisplayName", vmDisplayName).add("vmName", vmName).add("vmState", vmState).add("zoneId", zoneId).add("zoneName", zoneName)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Zone.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Zone.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Zone.java
index 81cec1e..1548507 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Zone.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Zone.java
@@ -20,7 +20,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
 import java.util.List;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.MoreObjects;
@@ -58,6 +60,7 @@ public class Zone implements Comparable<Zone> {
       protected AllocationState allocationState;
       protected String dhcpProvider;
       protected String zoneToken;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see Zone#getId()
@@ -181,9 +184,21 @@ public class Zone implements Comparable<Zone> {
          return self();
       }
 
+      /**
+       * @see Zone#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public Zone build() {
          return new Zone(id, description, displayText, DNS1, DNS2, domain, domainId, guestCIDRAddress, internalDNS1, internalDNS2,
-               name, networkType, VLAN, securityGroupsEnabled, allocationState, dhcpProvider, zoneToken);
+               name, networkType, VLAN, securityGroupsEnabled, allocationState, dhcpProvider, zoneToken, tags);
       }
 
       public T fromZone(Zone in) {
@@ -202,7 +217,8 @@ public class Zone implements Comparable<Zone> {
                .securityGroupsEnabled(in.isSecurityGroupsEnabled())
                .allocationState(in.getAllocationState())
                .dhcpProvider(in.getDhcpProvider())
-               .zoneToken(in.getZoneToken());
+               .zoneToken(in.getZoneToken())
+               .tags(in.getTags());
       }
    }
 
@@ -230,15 +246,16 @@ public class Zone implements Comparable<Zone> {
    private final AllocationState allocationState;
    private final String dhcpProvider;
    private final String zoneToken;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "description", "displaytext", "dns1", "dns2", "domain", "domainid", "guestcidraddress", "internaldns1", "internaldns2", "name", "networktype", "vlan", "securitygroupsenabled", "allocationstate", "dhcpprovider", "zonetoken"
+         "id", "description", "displaytext", "dns1", "dns2", "domain", "domainid", "guestcidraddress", "internaldns1", "internaldns2", "name", "networktype", "vlan", "securitygroupsenabled", "allocationstate", "dhcpprovider", "zonetoken", "tags"
    })
    protected Zone(String id, @Nullable String description, @Nullable String displayText, @Nullable String DNS1, @Nullable String DNS2,
                   @Nullable String domain, @Nullable String domainId, @Nullable String guestCIDRAddress, @Nullable String internalDNS1,
                   @Nullable String internalDNS2, @Nullable String name, @Nullable NetworkType networkType, @Nullable String VLAN,
                   boolean securityGroupsEnabled, @Nullable AllocationState allocationState, @Nullable String dhcpProvider,
-                  @Nullable String zoneToken) {
+                  @Nullable String zoneToken, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.description = description;
       this.displayText = displayText;
@@ -256,6 +273,7 @@ public class Zone implements Comparable<Zone> {
       this.allocationState = allocationState;
       this.dhcpProvider = dhcpProvider;
       this.zoneToken = zoneToken;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    /**
@@ -384,10 +402,17 @@ public class Zone implements Comparable<Zone> {
       return this.zoneToken;
    }
 
+   /**
+    * @return the tags for the zone
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
       return Objects.hashCode(id, description, displayText, DNS1, DNS2, domain, domainId, guestCIDRAddress, internalDNS1,
-            internalDNS2, name, networkType, VLAN, securityGroupsEnabled, allocationState, dhcpProvider, zoneToken);
+            internalDNS2, name, networkType, VLAN, securityGroupsEnabled, allocationState, dhcpProvider, zoneToken, tags);
    }
 
    @Override
@@ -411,7 +436,8 @@ public class Zone implements Comparable<Zone> {
             && Objects.equal(this.securityGroupsEnabled, that.securityGroupsEnabled)
             && Objects.equal(this.allocationState, that.allocationState)
             && Objects.equal(this.dhcpProvider, that.dhcpProvider)
-            && Objects.equal(this.zoneToken, that.zoneToken);
+            && Objects.equal(this.zoneToken, that.zoneToken)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -420,7 +446,7 @@ public class Zone implements Comparable<Zone> {
             .add("domain", domain).add("domainId", domainId).add("guestCIDRAddress", guestCIDRAddress).add("internalDNS1", internalDNS1)
             .add("internalDNS2", internalDNS2).add("name", name).add("networkType", networkType).add("VLAN", VLAN)
             .add("securityGroupsEnabled", securityGroupsEnabled).add("allocationState", allocationState).add("dhcpProvider", dhcpProvider)
-            .add("zoneToken", zoneToken);
+            .add("zoneToken", zoneToken).add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TagApi.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TagApi.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TagApi.java
new file mode 100644
index 0000000..96e9f36
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/TagApi.java
@@ -0,0 +1,89 @@
+/*
+ * 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 org.jclouds.cloudstack.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.core.MediaType;
+import java.util.Set;
+
+import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.cloudstack.filters.AuthenticationFilter;
+import org.jclouds.cloudstack.options.CreateTagsOptions;
+import org.jclouds.cloudstack.options.DeleteTagsOptions;
+import org.jclouds.cloudstack.options.ListTagsOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Unwrap;
+
+/**
+ * Provides synchronous access to cloudstack via their REST API.
+ * <p/>
+ * 
+ * @see <a href="http://cloudstack.apache.org/docs/api/apidocs-4.3/TOC_Root_Admin.html" />
+ */
+@RequestFilters(AuthenticationFilter.class)
+@QueryParams(keys = "response", values = "json")
+public interface TagApi {
+
+   /**
+    * Lists tags
+    * 
+    * @param options
+    *           if present, how to constrain the list.
+    * @return tags matching query, or empty set, if no tags are found
+    */
+   @Named("listTags")
+   @GET
+   @QueryParams(keys = { "command", "listAll" }, values = { "listTags", "true" })
+   @SelectJson("tag")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptySetOnNotFoundOr404.class)
+   Set<Tag> listTags(ListTagsOptions... options);
+
+   /**
+    * Creates one or more tags on the specified resources.
+    *
+    * @param options arguments
+    * @return an asynchronous job structure
+    */
+   @Named("createTags")
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "command", values = "createTags")
+   @Unwrap
+   AsyncCreateResponse createTags(CreateTagsOptions options);
+
+   /**
+    * Deletes one or more tags from the specified resources.
+    *
+    * @param options arguments
+    * @return an asynchronous job structure
+    */
+   @Named("deleteTags")
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "command", values = "deleteTags")
+   @Unwrap
+   AsyncCreateResponse deleteTags(DeleteTagsOptions options);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateTagsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateTagsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateTagsOptions.java
new file mode 100644
index 0000000..4263dbe
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateTagsOptions.java
@@ -0,0 +1,124 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options used to control how tags are created.
+ *
+ * @see <a
+ *      href="http://cloudstack.apache.org/docs/api/apidocs-4.3/root_admin/createTags.html"
+ *      />
+ */
+public class CreateTagsOptions extends BaseHttpRequestOptions {
+
+   public static final CreateTagsOptions NONE = new CreateTagsOptions();
+
+   /**
+    * Customer - optional
+    */
+   public CreateTagsOptions customer(String customer) {
+      this.queryParameters.replaceValues("customer", ImmutableSet.of(customer));
+      return this;
+   }
+
+   /**
+    * Resource ID(s) to tag
+    */
+   public CreateTagsOptions resourceIds(Set<String> resourceIds) {
+      this.queryParameters.replaceValues("resourceids", ImmutableSet.of(Joiner.on(",").join(resourceIds)));
+      return this;
+   }
+
+   /**
+    * Resource ID(s) to tag
+    */
+   public CreateTagsOptions resourceIds(String... resourceIds) {
+      this.queryParameters.replaceValues("resourceids", ImmutableSet.of(Joiner.on(",").join(resourceIds)));
+      return this;
+   }
+
+   /**
+    * Resource type
+    */
+   public CreateTagsOptions resourceType(String resourceType) {
+      this.queryParameters.replaceValues("resourcetype", ImmutableSet.of(resourceType));
+      return this;
+   }
+
+   /**
+    * Resource type
+    */
+   public CreateTagsOptions resourceType(Tag.ResourceType resourceType) {
+      this.queryParameters.replaceValues("resourcetype", ImmutableSet.of(resourceType.toString()));
+      return this;
+   }
+
+   /**
+    * Tags to create
+    */
+   public CreateTagsOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
+   public static class Builder {
+
+      public static CreateTagsOptions customer(String customer) {
+         CreateTagsOptions options = new CreateTagsOptions();
+         return options.customer(customer);
+      }
+
+      public static CreateTagsOptions resourceIds(Set<String> resourceIds) {
+         CreateTagsOptions options = new CreateTagsOptions();
+         return options.resourceIds(resourceIds);
+      }
+
+      public static CreateTagsOptions resourceIds(String... resourceIds) {
+         CreateTagsOptions options = new CreateTagsOptions();
+         return options.resourceIds(resourceIds);
+      }
+
+      public static CreateTagsOptions resourceType(String resourceType) {
+         CreateTagsOptions options = new CreateTagsOptions();
+         return options.resourceType(resourceType);
+      }
+
+      public static CreateTagsOptions resourceType(Tag.ResourceType resourceType) {
+         CreateTagsOptions options = new CreateTagsOptions();
+         return options.resourceType(resourceType);
+      }
+
+      public static CreateTagsOptions tags(Map<String, String> tags) {
+         CreateTagsOptions options = new CreateTagsOptions();
+         return options.tags(tags);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteTagsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteTagsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteTagsOptions.java
new file mode 100644
index 0000000..83c7c3f
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteTagsOptions.java
@@ -0,0 +1,111 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options used to control how tags are created.
+ *
+ * @see <a
+ *      href="http://cloudstack.apache.org/docs/api/apidocs-4.3/root_admin/createTags.html"
+ *      />
+ */
+public class DeleteTagsOptions extends BaseHttpRequestOptions {
+
+   public static final DeleteTagsOptions NONE = new DeleteTagsOptions();
+
+   /**
+    * Resource ID(s) to un-tag
+    */
+   public DeleteTagsOptions resourceIds(Set<String> resourceIds) {
+      this.queryParameters.replaceValues("resourceids", ImmutableSet.of(Joiner.on(",").join(resourceIds)));
+      return this;
+   }
+
+   /**
+    * Resource ID(s) to un-tag
+    */
+   public DeleteTagsOptions resourceIds(String... resourceIds) {
+      this.queryParameters.replaceValues("resourceids", ImmutableSet.of(Joiner.on(",").join(resourceIds)));
+      return this;
+   }
+
+   /**
+    * Resource type
+    */
+   public DeleteTagsOptions resourceType(String resourceType) {
+      this.queryParameters.replaceValues("resourcetype", ImmutableSet.of(resourceType));
+      return this;
+   }
+
+   /**
+    * Resource type
+    */
+   public DeleteTagsOptions resourceType(Tag.ResourceType resourceType) {
+      this.queryParameters.replaceValues("resourcetype", ImmutableSet.of(resourceType.toString()));
+      return this;
+   }
+
+   /**
+    * Tags to delete
+    */
+   public DeleteTagsOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
+   public static class Builder {
+
+      public static DeleteTagsOptions resourceIds(Set<String> resourceIds) {
+         DeleteTagsOptions options = new DeleteTagsOptions();
+         return options.resourceIds(resourceIds);
+      }
+
+      public static DeleteTagsOptions resourceIds(String... resourceIds) {
+         DeleteTagsOptions options = new DeleteTagsOptions();
+         return options.resourceIds(resourceIds);
+      }
+
+      public static DeleteTagsOptions resourceType(String resourceType) {
+         DeleteTagsOptions options = new DeleteTagsOptions();
+         return options.resourceType(resourceType);
+      }
+
+      public static DeleteTagsOptions resourceType(Tag.ResourceType resourceType) {
+         DeleteTagsOptions options = new DeleteTagsOptions();
+         return options.resourceType(resourceType);
+      }
+
+      public static DeleteTagsOptions tags(Map<String, String> tags) {
+         DeleteTagsOptions options = new DeleteTagsOptions();
+         return options.tags(tags);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListEgressFirewallRulesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListEgressFirewallRulesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListEgressFirewallRulesOptions.java
index 2f2ce02..5d8537c 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListEgressFirewallRulesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListEgressFirewallRulesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -84,6 +86,22 @@ public class ListEgressFirewallRulesOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListEgressFirewallRulesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
+
    public static class Builder {
 
       /**
@@ -158,6 +176,13 @@ public class ListEgressFirewallRulesOptions extends AccountInDomainOptions {
          return options.domainId(id);
       }
 
+      /**
+       * @see ListEgressFirewallRulesOptions#tags
+       */
+      public static ListEgressFirewallRulesOptions tags(Map<String, String> tags) {
+         ListEgressFirewallRulesOptions options = new ListEgressFirewallRulesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java
index 7f83213..8a8925d 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -75,6 +77,22 @@ public class ListFirewallRulesOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListFirewallRulesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
+
    public static class Builder {
 
       /**
@@ -141,6 +159,13 @@ public class ListFirewallRulesOptions extends AccountInDomainOptions {
          return options.domainId(id);
       }
 
+      /**
+       * @see ListFirewallRulesOptions#tags
+       */
+      public static ListFirewallRulesOptions tags(Map<String, String> tags) {
+         ListFirewallRulesOptions options = new ListFirewallRulesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptions.java
index a55936e..a6a3dcf 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -68,6 +70,22 @@ public class ListIPForwardingRulesOptions extends AccountInDomainOptions {
 
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListIPForwardingRulesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
+
    public static class Builder {
 
       /**
@@ -117,6 +135,14 @@ public class ListIPForwardingRulesOptions extends AccountInDomainOptions {
          ListIPForwardingRulesOptions options = new ListIPForwardingRulesOptions();
          return options.projectId(projectId);
       }
+
+      /**
+       * @see ListIPForwardingRulesOptions#tags
+       */
+      public static ListIPForwardingRulesOptions tags(Map<String, String> tags) {
+         ListIPForwardingRulesOptions options = new ListIPForwardingRulesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListISOsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListISOsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListISOsOptions.java
index 0659d51..d0f9b26 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListISOsOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListISOsOptions.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
 import java.util.Set;
 
 import org.jclouds.cloudstack.domain.ISO;
@@ -138,6 +139,21 @@ public class ListISOsOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListISOsOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
       /**
        * @param account the account of the ISO file. Must be used with the domainId parameter.
@@ -243,5 +259,12 @@ public class ListISOsOptions extends AccountInDomainOptions {
       public static ListISOsOptions zoneId(String zoneId) {
          return new ListISOsOptions().zoneId(zoneId);
       }
+
+      /**
+       * @param tags
+       */
+      public static ListISOsOptions tags(Map<String, String> tags) {
+         return new ListISOsOptions().tags(tags);
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListNetworksOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListNetworksOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListNetworksOptions.java
index 94e9de7..2691107 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListNetworksOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListNetworksOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import org.jclouds.cloudstack.domain.NetworkType;
 import org.jclouds.cloudstack.domain.TrafficType;
 
@@ -33,8 +35,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    public static final ListNetworksOptions NONE = new ListNetworksOptions();
 
    /**
-    * @param isDefault
-    *           true if network is default, false otherwise
+    * @param isDefault true if network is default, false otherwise
     */
    public ListNetworksOptions isDefault(boolean isDefault) {
       this.queryParameters.replaceValues("isdefault", ImmutableSet.of(isDefault + ""));
@@ -42,8 +43,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param isShared
-    *           true if network is shared, false otherwise
+    * @param isShared true if network is shared, false otherwise
     */
    public ListNetworksOptions isShared(boolean isShared) {
       this.queryParameters.replaceValues("isshared", ImmutableSet.of(isShared + ""));
@@ -51,8 +51,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param isSystem
-    *           true if network is system, false otherwise
+    * @param isSystem true if network is system, false otherwise
     */
    public ListNetworksOptions isSystem(boolean isSystem) {
       this.queryParameters.replaceValues("issystem", ImmutableSet.of(isSystem + ""));
@@ -60,8 +59,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param type
-    *           the type of the network
+    * @param type the type of the network
     */
    public ListNetworksOptions type(NetworkType type) {
       this.queryParameters.replaceValues("type", ImmutableSet.of(type.toString()));
@@ -69,8 +67,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param id
-    *           list networks by id
+    * @param id list networks by id
     */
    public ListNetworksOptions id(String id) {
       this.queryParameters.replaceValues("id", ImmutableSet.of(id + ""));
@@ -78,8 +75,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param zoneId
-    *           the Zone ID of the network
+    * @param zoneId the Zone ID of the network
     */
    public ListNetworksOptions zoneId(String zoneId) {
       this.queryParameters.replaceValues("zoneid", ImmutableSet.of(zoneId + ""));
@@ -88,8 +84,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param projectId
-    *           the project ID of the network
+    * @param projectId the project ID of the network
     */
    public ListNetworksOptions projectId(String projectId) {
       this.queryParameters.replaceValues("projectid", ImmutableSet.of(projectId + ""));
@@ -98,8 +93,7 @@ public class ListNetworksOptions extends AccountInDomainOptions {
    }
 
    /**
-    * @param trafficType
-    *           type of the traffic
+    * @param trafficType type of the traffic
     */
    public ListNetworksOptions trafficType(TrafficType trafficType) {
       this.queryParameters.replaceValues("traffictype", ImmutableSet.of(trafficType.toString()));
@@ -122,6 +116,21 @@ public class ListNetworksOptions extends AccountInDomainOptions {
       return ListNetworksOptions.class.cast(super.domainId(domainId));
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListNetworksOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
       /**
        * @see ListNetworksOptions#isDefault
@@ -202,6 +211,15 @@ public class ListNetworksOptions extends AccountInDomainOptions {
          ListNetworksOptions options = new ListNetworksOptions();
          return options.domainId(domainId);
       }
-   }
 
+      /**
+       * @see ListNetworksOptions#tags
+       */
+      public static ListNetworksOptions tags(Map<String, String> tags) {
+         ListNetworksOptions options = new ListNetworksOptions();
+         return options.tags(tags);
+      }
+   }
 }
+
+

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java
index b551f05..3ccbd69 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -57,6 +59,22 @@ public class ListPortForwardingRulesOptions extends AccountInDomainOptions {
       return this;
 
    }
+
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListPortForwardingRulesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -98,8 +116,17 @@ public class ListPortForwardingRulesOptions extends AccountInDomainOptions {
          ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions();
          return options.domainId(id);
       }
+
+      /**
+       * @see ListPortForwardingRulesOptions#tags
+       */
+      public static ListPortForwardingRulesOptions tags(Map<String, String> tags) {
+         ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions();
+         return options.tags(tags);
+      }
    }
 
+
    /**
     * {@inheritDoc}
     */

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListProjectsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListProjectsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListProjectsOptions.java
index 7b0b2ff..0eeaf80 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListProjectsOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListProjectsOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -85,6 +87,21 @@ public class ListProjectsOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListProjectsOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -150,6 +167,14 @@ public class ListProjectsOptions extends AccountInDomainOptions {
          ListProjectsOptions options = new ListProjectsOptions();
          return options.recursive(recursive);
       }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListProjectsOptions#tags
+       */
+      public static ListProjectsOptions tags(Map<String, String> tags) {
+         ListProjectsOptions options = new ListProjectsOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptions.java
index 0cb38e9..2609d87 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -106,6 +108,21 @@ public class ListPublicIPAddressesOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListPublicIPAddressesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -187,6 +204,14 @@ public class ListPublicIPAddressesOptions extends AccountInDomainOptions {
          ListPublicIPAddressesOptions options = new ListPublicIPAddressesOptions();
          return options.usesVirtualNetwork(usesVirtualNetwork);
       }
+
+      /**
+       * @see ListPublicIPAddressesOptions#tags
+       */
+      public static ListPublicIPAddressesOptions tags(Map<String, String> tags) {
+         ListPublicIPAddressesOptions options = new ListPublicIPAddressesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptions.java
index d9e22c3..32d6113 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -68,6 +70,21 @@ public class ListSecurityGroupsOptions extends AssociateIPAddressOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListSecurityGroupsOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -103,7 +120,7 @@ public class ListSecurityGroupsOptions extends AssociateIPAddressOptions {
       }
 
       /**
-       * @see DeployVirtualMachineOptions#accountInDomain
+       * @see ListSecurityGroupsOptions#accountInDomain
        */
       public static ListSecurityGroupsOptions accountInDomain(String account, String domain) {
          ListSecurityGroupsOptions options = new ListSecurityGroupsOptions();
@@ -111,12 +128,20 @@ public class ListSecurityGroupsOptions extends AssociateIPAddressOptions {
       }
 
       /**
-       * @see DeployVirtualMachineOptions#domainId
+       * @see ListSecurityGroupsOptions#domainId
        */
       public static ListSecurityGroupsOptions domainId(String domainId) {
          ListSecurityGroupsOptions options = new ListSecurityGroupsOptions();
          return options.domainId(domainId);
       }
+
+      /**
+       * @see ListSecurityGroupsOptions#tags
+       */
+      public static ListSecurityGroupsOptions tags(Map<String, String> tags) {
+         ListSecurityGroupsOptions options = new ListSecurityGroupsOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java
index fa366d0..35a076a 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import org.jclouds.cloudstack.domain.Snapshot;
 
 import com.google.common.collect.ImmutableSet;
@@ -94,6 +96,21 @@ public class ListSnapshotsOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListSnapshotsOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -166,6 +183,13 @@ public class ListSnapshotsOptions extends AccountInDomainOptions {
       public static ListSnapshotsOptions projectId(String projectId) {
          return new ListSnapshotsOptions().projectId(projectId);
       }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListSnapshotsOptions#tags(java.util.Map)
+       */
+      public static ListSnapshotsOptions tags(Map<String, String> tags) {
+         return new ListSnapshotsOptions().tags(tags);
+      }
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTagsOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTagsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTagsOptions.java
new file mode 100644
index 0000000..19e01bd
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTagsOptions.java
@@ -0,0 +1,247 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Tag;
+
+/**
+ * Options used to control what tags are returned
+ * 
+ * @see <a href=
+ *      "http://cloudstack.apache.org/docs/api/apidocs-4.3/root_admin/listTags.html"
+ *      />
+ */
+public class ListTagsOptions extends AccountInDomainOptions {
+
+   public static final ListTagsOptions NONE = new ListTagsOptions();
+
+   /**
+    * @param customer
+    *    list by customer
+    */
+   public ListTagsOptions customer(String customer) {
+      this.queryParameters.replaceValues("customer", ImmutableSet.of(customer));
+      return this;
+   }
+
+   /**
+    * @param isRecursive
+    *           Should we recurse on this search?
+    */
+   public ListTagsOptions isRecursive(boolean isRecursive) {
+      this.queryParameters.replaceValues("isrecursive", ImmutableSet.of(isRecursive + ""));
+      return this;
+   }
+
+   /**
+    * @param key
+    *    list by key
+    */
+   public ListTagsOptions key(String key) {
+      this.queryParameters.replaceValues("key", ImmutableSet.of(key));
+      return this;
+   }
+
+   /**
+    * @param keyword
+    *    list by keyword
+    */
+   public ListTagsOptions keyword(String keyword) {
+      this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword));
+      return this;
+   }
+
+   /**
+    * @param projectId
+    *    list by project
+    */
+   public ListTagsOptions projectId(String projectId) {
+      this.queryParameters.replaceValues("projectid", ImmutableSet.of(projectId));
+      return this;
+   }
+
+   /**
+    * @param resourceId
+    *    list by resource ID
+    */
+   public ListTagsOptions resourceId(String resourceId) {
+      this.queryParameters.replaceValues("resourceid", ImmutableSet.of(resourceId));
+      return this;
+   }
+
+   /**
+    * @param resourceType
+    *    list by resource type
+    */
+   public ListTagsOptions resourceType(String resourceType) {
+      this.queryParameters.replaceValues("resourcetype", ImmutableSet.of(resourceType));
+      return this;
+   }
+
+   /**
+    * @param resourceType
+    *    list by resource type
+    */
+   public ListTagsOptions resourceType(Tag.ResourceType resourceType) {
+      this.queryParameters.replaceValues("resourcetype", ImmutableSet.of(resourceType.toString()));
+      return this;
+   }
+
+   /**
+    * @param value
+    *    list by value
+    */
+   public ListTagsOptions value(String value) {
+      this.queryParameters.replaceValues("value", ImmutableSet.of(value));
+      return this;
+   }
+
+   public ListTagsOptions page(long page) {
+      this.queryParameters.replaceValues("page", ImmutableSet.of(page + ""));
+      return this;
+   }
+
+   public ListTagsOptions pageSize(long pageSize) {
+      this.queryParameters.replaceValues("pagesize", ImmutableSet.of(pageSize + ""));
+      return this;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#accountInDomain(String, String)
+       */
+      public static ListTagsOptions accountInDomain(String account, String domain) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.accountInDomain(account, domain);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#accountInDomain(String, String)
+       */
+      public static ListTagsOptions domainId(String domainId) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.domainId(domainId);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#customer(String)
+       */
+      public static ListTagsOptions customer(String customer) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.customer(customer);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#isRecursive(boolean)
+       */
+      public static ListTagsOptions isRecursive(boolean isRecursive) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.isRecursive(isRecursive);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#key(String)
+       */
+      public static ListTagsOptions key(String key) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.key(key);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#keyword
+       */
+      public static ListTagsOptions keyword(String keyword) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.keyword(keyword);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#projectId(String)
+       */
+      public static ListTagsOptions projectId(String projectId) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.projectId(projectId);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#resourceId(String)
+       */
+      public static ListTagsOptions resourceId(String resourceId) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.resourceId(resourceId);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#resourceType(String)
+       */
+      public static ListTagsOptions resourceType(String resourceType) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.resourceType(resourceType);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#resourceType(org.jclouds.cloudstack.domain.Tag.ResourceType)
+       */
+      public static ListTagsOptions resourceType(Tag.ResourceType resourceType) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.resourceType(resourceType);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#value(String)
+       */
+      public static ListTagsOptions value(String value) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.value(value);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#page
+       */
+      public static ListTagsOptions page(long page) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.page(page);
+      }
+
+      /**
+       * @see org.jclouds.cloudstack.options.ListTagsOptions#pageSize
+       */
+      public static ListTagsOptions pageSize(long pageSize) {
+         ListTagsOptions options = new ListTagsOptions();
+         return options.pageSize(pageSize);
+      }
+   }
+
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public ListTagsOptions accountInDomain(String account, String domain) {
+      return ListTagsOptions.class.cast(super.accountInDomain(account, domain));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public ListTagsOptions domainId(String domainId) {
+      return ListTagsOptions.class.cast(super.domainId(domainId));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTemplatesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTemplatesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTemplatesOptions.java
index 4769920..f73c2e6 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTemplatesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListTemplatesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import org.jclouds.cloudstack.domain.TemplateFilter;
 
 import com.google.common.collect.ImmutableSet;
@@ -90,6 +92,21 @@ public class ListTemplatesOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListTemplatesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -155,6 +172,14 @@ public class ListTemplatesOptions extends AccountInDomainOptions {
          ListTemplatesOptions options = new ListTemplatesOptions();
          return options.hypervisor(hypervisor);
       }
+
+      /**
+       * @see ListTemplatesOptions#tags
+       */
+      public static ListTemplatesOptions tags(Map<String, String> tags) {
+         ListTemplatesOptions options = new ListTemplatesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptions.java
index 4d1c7d6..294f32b 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -126,6 +128,21 @@ public class ListVirtualMachinesOptions extends AccountInDomainOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListVirtualMachinesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
+
    public static class Builder {
 
       /**
@@ -223,6 +240,14 @@ public class ListVirtualMachinesOptions extends AccountInDomainOptions {
          ListVirtualMachinesOptions options = new ListVirtualMachinesOptions();
          return options.usesVirtualNetwork(usesVirtualNetwork);
       }
+
+      /**
+       * @see ListVirtualMachinesOptions#tags
+       */
+      public static ListVirtualMachinesOptions tags(Map<String, String> tags) {
+         ListVirtualMachinesOptions options = new ListVirtualMachinesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVolumesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVolumesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVolumesOptions.java
index fb11c3b..0d27b08 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVolumesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListVolumesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import org.jclouds.cloudstack.domain.Volume;
 
 import com.google.common.collect.ImmutableSet;
@@ -114,6 +116,20 @@ public class ListVolumesOptions extends AccountInDomainOptions {
 
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListVolumesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
 
    public static class Builder {
 
@@ -213,6 +229,14 @@ public class ListVolumesOptions extends AccountInDomainOptions {
          ListVolumesOptions options = new ListVolumesOptions();
          return options.projectId(id);
       }
+
+      /**
+       * @see ListVolumesOptions#tags
+       */
+      public static ListVolumesOptions tags(Map<String, String> tags) {
+         ListVolumesOptions options = new ListVolumesOptions();
+         return options.tags(tags);
+      }
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListZonesOptions.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListZonesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListZonesOptions.java
index db7dfb2..cd071c4 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListZonesOptions.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListZonesOptions.java
@@ -16,6 +16,8 @@
  */
 package org.jclouds.cloudstack.options;
 
+import java.util.Map;
+
 import org.jclouds.http.options.BaseHttpRequestOptions;
 
 import com.google.common.collect.ImmutableSet;
@@ -61,6 +63,20 @@ public class ListZonesOptions extends BaseHttpRequestOptions {
       return this;
    }
 
+   /**
+    * @param tags
+    *           Key/value pairs for tags that need to be matched.
+    */
+   public ListZonesOptions tags(Map<String, String> tags) {
+      int count = 0;
+      for (Map.Entry<String, String> entry : tags.entrySet()) {
+         this.queryParameters.replaceValues(String.format("tags[%d].key", count), ImmutableSet.of(entry.getKey()));
+         this.queryParameters.replaceValues(String.format("tags[%d].value", count),
+               ImmutableSet.of(entry.getValue()));
+         count += 1;
+      }
+      return this;
+   }
    public static class Builder {
 
       /**
@@ -87,5 +103,12 @@ public class ListZonesOptions extends BaseHttpRequestOptions {
          return options.id(id);
       }
 
+      /**
+       * @see ListZonesOptions#tags
+       */
+      public static ListZonesOptions tags(Map<String, String> tags) {
+         ListZonesOptions options = new ListZonesOptions();
+         return options.tags(tags);
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallApiExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallApiExpectTest.java
index fdc2544..db6dbc5 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallApiExpectTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallApiExpectTest.java
@@ -22,17 +22,17 @@ import static org.testng.Assert.assertNull;
 import java.net.URI;
 import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.jclouds.cloudstack.CloudStackContext;
 import org.jclouds.cloudstack.domain.AsyncCreateResponse;
 import org.jclouds.cloudstack.domain.FirewallRule;
 import org.jclouds.cloudstack.domain.PortForwardingRule;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.internal.BaseCloudStackExpectTest;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableSet;
-
 /**
  * Test the CloudStack FirewallApi
  */
@@ -64,7 +64,8 @@ public class FirewallApiExpectTest extends BaseCloudStackExpectTest<FirewallApi>
                .CIDRs(CIDRs).build(),
             FirewallRule.builder().id("10").protocol(FirewallRule.Protocol.TCP).startPort(22)
             .endPort(22).ipAddressId("8").ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE)
-               .CIDRs(CIDRs).build()
+               .CIDRs(CIDRs).tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("10")
+                  .resourceType(Tag.ResourceType.FIREWALL_RULE).value("some-value").build()).build()
          ));
    }
 
@@ -173,13 +174,16 @@ public class FirewallApiExpectTest extends BaseCloudStackExpectTest<FirewallApi>
       Set<String> cidrs = ImmutableSet.of("0.0.0.0/1", "128.0.0.0/1");
 
       assertEquals(client.listPortForwardingRules(),
-         ImmutableSet.<PortForwardingRule>of(
-            PortForwardingRule.builder().id("15").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
-               .publicPort(2022).virtualMachineId("3").virtualMachineName("i-3-3-VM").IPAddressId("3")
-               .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE).CIDRs(cidrs).build(),
-            PortForwardingRule.builder().id("18").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
-               .publicPort(22).virtualMachineId("89").virtualMachineName("i-3-89-VM").IPAddressId("34")
-               .IPAddress("72.52.126.63").state(PortForwardingRule.State.ACTIVE).build())
+            ImmutableSet.<PortForwardingRule>of(
+                  PortForwardingRule.builder().id("18").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
+                        .publicPort(22).virtualMachineId("89").virtualMachineName("i-3-89-VM").IPAddressId("34")
+                        .IPAddress("72.52.126.63").state(PortForwardingRule.State.ACTIVE).build(),
+                  PortForwardingRule.builder().id("15").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
+                        .publicPort(2022).virtualMachineId("3").virtualMachineName("i-3-3-VM").IPAddressId("3")
+                        .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE)
+                        .CIDRs(cidrs).tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("15")
+                        .resourceType(Tag.ResourceType.PORT_FORWARDING_RULE).value("some-value").build()).build()
+                  )
       );
    }
 
@@ -216,9 +220,11 @@ public class FirewallApiExpectTest extends BaseCloudStackExpectTest<FirewallApi>
       Set<String> cidrs = ImmutableSet.of("0.0.0.0/1", "128.0.0.0/1");
 
       assertEquals(client.getPortForwardingRule("15"),
-         PortForwardingRule.builder().id("15").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
-            .publicPort(2022).virtualMachineId("3").virtualMachineName("i-3-3-VM").IPAddressId("3")
-            .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE).CIDRs(cidrs).build());
+            PortForwardingRule.builder().id("15").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
+                  .publicPort(2022).virtualMachineId("3").virtualMachineName("i-3-3-VM").IPAddressId("3")
+                  .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE)
+                  .CIDRs(cidrs).tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("15")
+                  .resourceType(Tag.ResourceType.PORT_FORWARDING_RULE).value("some-value").build()).build());
    }
 
    public void testGetPortForwardingRuleWhenResponseIs404() {
@@ -296,15 +302,16 @@ public class FirewallApiExpectTest extends BaseCloudStackExpectTest<FirewallApi>
       Set<String> CIDRs  = ImmutableSet.of("0.0.0.0/0");
       assertEquals(client.listEgressFirewallRules(),
               ImmutableSet.of(
-                      FirewallRule.builder().id("2017").protocol(FirewallRule.Protocol.TCP).startPort(30)
-                              .endPort(35).ipAddressId("2").ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE)
-                              .CIDRs(CIDRs).build(),
-                      FirewallRule.builder().id("2016").protocol(FirewallRule.Protocol.TCP).startPort(22)
-                              .endPort(22).ipAddressId("2").ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE)
-                              .CIDRs(CIDRs).build(),
-                      FirewallRule.builder().id("10").protocol(FirewallRule.Protocol.TCP).startPort(22)
-                              .endPort(22).ipAddressId("8").ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE)
-                              .CIDRs(CIDRs).build()
+                    FirewallRule.builder().id("2017").protocol(FirewallRule.Protocol.TCP).startPort(30)
+                          .endPort(35).ipAddressId("2").ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE)
+                          .CIDRs(CIDRs).build(),
+                    FirewallRule.builder().id("2016").protocol(FirewallRule.Protocol.TCP).startPort(22)
+                          .endPort(22).ipAddressId("2").ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE)
+                          .CIDRs(CIDRs).build(),
+                    FirewallRule.builder().id("10").protocol(FirewallRule.Protocol.TCP).startPort(22)
+                          .endPort(22).ipAddressId("8").ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE)
+                          .CIDRs(CIDRs).tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("10")
+                          .resourceType(Tag.ResourceType.FIREWALL_RULE).value("some-value").build()).build()
               ));
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ProjectApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ProjectApiExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ProjectApiExpectTest.java
index b7665be..3bf640f 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ProjectApiExpectTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ProjectApiExpectTest.java
@@ -22,6 +22,7 @@ import java.util.Set;
 
 import org.jclouds.cloudstack.CloudStackContext;
 import org.jclouds.cloudstack.domain.Project;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.internal.BaseCloudStackExpectTest;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
@@ -50,22 +51,32 @@ public class ProjectApiExpectTest extends BaseCloudStackExpectTest<ProjectApi> {
             .build());
 
       Set<Project> projects = ImmutableSet.of(
-              Project.builder()
-                      .id("489da162-0b77-489d-b044-ce39aa018b1f")
-                      .account("thyde")
-                      .displayText("")
-                      .domain("ROOT")
-                      .domainId("41a4917b-7952-499d-ba7f-4c57464d3dc8")
-                      .name("NN-HA-T1")
-                      .state(Project.State.ACTIVE).build(),
-              Project.builder()
-                      .id("1c11f22c-15ac-4fa7-b833-4d748df317b7")
-                      .account("prasadm")
-                      .displayText("Hive")
-                      .domain("ROOT")
-                      .domainId("41a4917b-7952-499d-ba7f-4c57464d3dc8")
-                      .name("hive")
-                      .state(Project.State.ACTIVE).build());
+            Project.builder()
+                  .id("489da162-0b77-489d-b044-ce39aa018b1f")
+                  .account("thyde")
+                  .displayText("")
+                  .domain("ROOT")
+                  .domainId("41a4917b-7952-499d-ba7f-4c57464d3dc8")
+                  .name("NN-HA-T1")
+                  .state(Project.State.ACTIVE).build(),
+            Project.builder()
+                  .id("1c11f22c-15ac-4fa7-b833-4d748df317b7")
+                  .account("prasadm")
+                  .displayText("Hive")
+                  .domain("ROOT")
+                  .domainId("41a4917b-7952-499d-ba7f-4c57464d3dc8")
+                  .name("hive")
+                  .state(Project.State.ACTIVE)
+                  .tags(Tag.builder()
+                        .account("prasadm")
+                        .domain("ROOT")
+                        .domainId("41a4917b-7952-499d-ba7f-4c57464d3dc8")
+                        .key("some-tag")
+                        .resourceId("1c11f22c-15ac-4fa7-b833-4d748df317b7")
+                        .resourceType(Tag.ResourceType.PROJECT)
+                        .value("some-value")
+                        .build())
+                  .build());
 
       assertEquals(client.listProjects(), projects);
    }


[7/7] git commit: Actually get tags to work, and get template spec creds to overrule in-built ones.

Posted by ab...@apache.org.
Actually get tags to work, and get template spec creds to overrule in-built ones.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/41523c23
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/41523c23
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/41523c23

Branch: refs/heads/jclouds-756
Commit: 41523c23e3f921f8495ae5f687b34895de806939
Parents: 2ac80c0
Author: Andrew Bayer <an...@gmail.com>
Authored: Tue Oct 21 16:32:15 2014 -0700
Committer: Andrew Bayer <an...@gmail.com>
Committed: Tue Oct 21 16:32:15 2014 -0700

----------------------------------------------------------------------
 .../functions/VirtualMachineToNodeMetadata.java |  1 -
 .../CloudStackComputeServiceAdapter.java        | 30 +++++++++++++-------
 2 files changed, 19 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/41523c23/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
index a9596e3..c234f9c 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
@@ -136,7 +136,6 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
       builder.hardware(new HardwareBuilder()
         .ids(from.getServiceOfferingId() + "")
         .name(from.getServiceOfferingName() + "")
-         // .tags() TODO
         .processors(ImmutableList.of(new Processor(from.getCpuCount(), from.getCpuSpeed())))
         .ram((int)from.getMemory())//
         .hypervisor(from.getHypervisor())//

http://git-wip-us.apache.org/repos/asf/jclouds/blob/41523c23/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
index 9387844..e723f7f 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
@@ -26,7 +26,6 @@ import static org.jclouds.cloudstack.options.DeployVirtualMachineOptions.Builder
 import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.id;
 import static org.jclouds.cloudstack.predicates.TemplatePredicates.isReady;
 import static org.jclouds.cloudstack.predicates.ZonePredicates.supportsSecurityGroups;
-import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsValuesOfEmptyString;
 import static org.jclouds.ssh.SshKeys.fingerprintPrivateKey;
 
 import javax.annotation.Resource;
@@ -76,6 +75,7 @@ import org.jclouds.cloudstack.options.ListTemplatesOptions;
 import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.config.GetLoginForProviderFromPropertiesAndStoreCredentialsOrReturnNull;
 import org.jclouds.compute.functions.GroupNamingConvention;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.domain.Credentials;
@@ -109,6 +109,7 @@ public class CloudStackComputeServiceAdapter implements
    private final LoadingCache<ZoneAndName, SecurityGroup> securityGroupCache;
    private final LoadingCache<String, SshKeyPair> keyPairCache;
    private final GroupNamingConvention.Factory namingConvention;
+   private final GetLoginForProviderFromPropertiesAndStoreCredentialsOrReturnNull credentialsProvider;
 
    @Inject
    public CloudStackComputeServiceAdapter(CloudStackApi client, Predicate<String> jobComplete,
@@ -124,7 +125,8 @@ public class CloudStackComputeServiceAdapter implements
                                           Supplier<LoadingCache<String, Zone>> zoneIdToZone,
                                           LoadingCache<ZoneAndName, SecurityGroup> securityGroupCache,
                                           LoadingCache<String, SshKeyPair> keyPairCache,
-                                          GroupNamingConvention.Factory namingConvention) {
+                                          GroupNamingConvention.Factory namingConvention,
+                                          GetLoginForProviderFromPropertiesAndStoreCredentialsOrReturnNull credentialsProvider) {
       this.client = checkNotNull(client, "client");
       this.jobComplete = checkNotNull(jobComplete, "jobComplete");
       this.networkSupplier = checkNotNull(networkSupplier, "networkSupplier");
@@ -141,6 +143,7 @@ public class CloudStackComputeServiceAdapter implements
       this.optionsConverters = optionsConverters;
       this.zoneIdToZone = zoneIdToZone;
       this.namingConvention = namingConvention;
+      this.credentialsProvider = credentialsProvider;
    }
 
    @Override
@@ -235,17 +238,21 @@ public class CloudStackComputeServiceAdapter implements
          templateId, options);
       VirtualMachine vm = blockUntilJobCompletesAndReturnResult.<VirtualMachine>apply(job);
       logger.debug("--- virtualmachine: %s", vm);
-      LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder();
-      if (templateOptions.getKeyPair() != null) {
-         SshKeyPair keyPair = keyPairCache.getUnchecked(templateOptions.getKeyPair());
-         credentialsBuilder.privateKey(keyPair.getPrivateKey());
-      } else if (vm.isPasswordEnabled()) {
-         assert vm.getPassword() != null : vm;
-         credentialsBuilder.password(vm.getPassword());
+      LoginCredentials credentials = credentialsProvider.get();
+      if (credentials == null || credentials.getUser() == null) {
+         LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder();
+         if (templateOptions.getKeyPair() != null) {
+            SshKeyPair keyPair = keyPairCache.getUnchecked(templateOptions.getKeyPair());
+            credentialsBuilder.privateKey(keyPair.getPrivateKey());
+         } else if (vm.isPasswordEnabled()) {
+            assert vm.getPassword() != null : vm;
+            credentialsBuilder.password(vm.getPassword());
+         }
+         credentials = credentialsBuilder.build();
       }
 
       try {
-         ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String> builder();
+         ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
          builder.putAll(template.getOptions().getUserMetadata());
          for (String tag : template.getOptions().getTags())
             builder.put(tag, "jclouds-empty-tag-placeholder");
@@ -259,6 +266,7 @@ public class CloudStackComputeServiceAdapter implements
             AsyncCreateResponse tagJob = client.getTagApi().createTags(tagOptions);
             awaitCompletion(tagJob.getJobId());
             logger.debug("<< tags added");
+            vm = client.getVirtualMachineApi().getVirtualMachine(vm.getId());
          }
          if (templateOptions.shouldSetupStaticNat()) {
              Capabilities capabilities = client.getConfigurationApi().listCapabilities();
@@ -289,7 +297,7 @@ public class CloudStackComputeServiceAdapter implements
           }
           throw re;
       }
-      return new NodeAndInitialCredentials<VirtualMachine>(vm, vm.getId() + "", credentialsBuilder.build());
+      return new NodeAndInitialCredentials<VirtualMachine>(vm, vm.getId() + "", credentials);
    }
 
    @Override


[4/7] git commit: JCLOUDS-756. Add support for tags to CloudStack.

Posted by ab...@apache.org.
JCLOUDS-756. Add support for tags to CloudStack.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/43bb86f0
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/43bb86f0
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/43bb86f0

Branch: refs/heads/jclouds-756
Commit: 43bb86f0858ccacb16ef8dbdcad823a948887854
Parents: b220d88
Author: Andrew Bayer <an...@gmail.com>
Authored: Tue Oct 21 14:18:12 2014 -0700
Committer: Andrew Bayer <an...@gmail.com>
Committed: Tue Oct 21 14:18:12 2014 -0700

----------------------------------------------------------------------
 .../org/jclouds/cloudstack/CloudStackApi.java   |   7 +
 .../jclouds/cloudstack/domain/FirewallRule.java |  41 ++-
 .../cloudstack/domain/IPForwardingRule.java     |  41 ++-
 .../java/org/jclouds/cloudstack/domain/ISO.java |  43 ++-
 .../jclouds/cloudstack/domain/IngressRule.java  |  46 ++-
 .../org/jclouds/cloudstack/domain/Network.java  |  45 ++-
 .../cloudstack/domain/PortForwardingRule.java   |  43 ++-
 .../org/jclouds/cloudstack/domain/Project.java  |  52 ++-
 .../cloudstack/domain/PublicIPAddress.java      |  40 ++-
 .../cloudstack/domain/SecurityGroup.java        |  39 +-
 .../org/jclouds/cloudstack/domain/Snapshot.java |  41 ++-
 .../java/org/jclouds/cloudstack/domain/Tag.java | 352 +++++++++++++++++++
 .../org/jclouds/cloudstack/domain/Template.java |  47 ++-
 .../cloudstack/domain/VirtualMachine.java       |  39 +-
 .../org/jclouds/cloudstack/domain/Volume.java   |  40 ++-
 .../org/jclouds/cloudstack/domain/Zone.java     |  40 ++-
 .../org/jclouds/cloudstack/features/TagApi.java |  89 +++++
 .../cloudstack/options/CreateTagsOptions.java   | 124 +++++++
 .../cloudstack/options/DeleteTagsOptions.java   | 111 ++++++
 .../options/ListEgressFirewallRulesOptions.java |  25 ++
 .../options/ListFirewallRulesOptions.java       |  25 ++
 .../options/ListIPForwardingRulesOptions.java   |  26 ++
 .../cloudstack/options/ListISOsOptions.java     |  23 ++
 .../cloudstack/options/ListNetworksOptions.java |  52 ++-
 .../options/ListPortForwardingRulesOptions.java |  27 ++
 .../cloudstack/options/ListProjectsOptions.java |  25 ++
 .../options/ListPublicIPAddressesOptions.java   |  25 ++
 .../options/ListSecurityGroupsOptions.java      |  29 +-
 .../options/ListSnapshotsOptions.java           |  24 ++
 .../cloudstack/options/ListTagsOptions.java     | 247 +++++++++++++
 .../options/ListTemplatesOptions.java           |  25 ++
 .../options/ListVirtualMachinesOptions.java     |  25 ++
 .../cloudstack/options/ListVolumesOptions.java  |  24 ++
 .../cloudstack/options/ListZonesOptions.java    |  23 ++
 .../features/FirewallApiExpectTest.java         |  51 +--
 .../features/ProjectApiExpectTest.java          |  43 ++-
 .../cloudstack/features/TagApiExpectTest.java   | 153 ++++++++
 .../cloudstack/features/TagApiLiveTest.java     | 147 ++++++++
 .../jclouds/cloudstack/features/TagApiTest.java | 123 +++++++
 .../cloudstack/features/ZoneApiExpectTest.java  |  19 +-
 .../options/CreateTagsOptionsTest.java          | 102 ++++++
 .../options/DeleteTagsOptionsTest.java          |  91 +++++
 .../ListIPForwardingRulesOptionsTest.java       |  19 +
 .../cloudstack/options/ListISOsOptionsTest.java |  19 +
 .../options/ListNetworksOptionsTest.java        |  19 +
 .../ListPortForwardingRulesOptionsTest.java     |  18 +
 .../ListPublicIPAddressesOptionsTest.java       |  18 +
 .../options/ListSecurityGroupsOptionsTest.java  |  18 +
 .../cloudstack/options/ListTagsOptionsTest.java | 152 ++++++++
 .../options/ListTemplatesOptionsTest.java       |  18 +
 .../options/ListVirtualMachesOptionsTest.java   | 152 --------
 .../options/ListVirtualMachinesOptionsTest.java | 170 +++++++++
 .../options/ListZonesOptionsTest.java           |  18 +
 .../parse/ListFirewallRulesResponseTest.java    |   7 +-
 .../ListIPForwardingRulesResponseTest.java      |   9 +-
 .../parse/ListNetworksResponseTest.java         |  11 +-
 .../ListPortForwardingRulesResponseTest.java    |  15 +-
 .../ListPublicIPAddressesResponseTest.java      |  13 +-
 .../parse/ListSecurityGroupsResponseTest.java   |  31 +-
 .../cloudstack/parse/ListTagsResponseTest.java  |  66 ++++
 .../parse/ListTemplatesResponseTest.java        |   3 +
 .../ListVirtualMachinesResponse3xTest.java      |  17 +-
 .../cloudstack/parse/ListZonesResponseTest.java |  25 +-
 .../src/test/resources/createtagsresponse.json  |   1 +
 .../src/test/resources/deletetagsresponse.json  |   1 +
 .../getportforwardingrulesresponse.json         |  19 +-
 .../listegressfirewallrulesresponse.json        |   5 +-
 .../resources/listfirewallrulesresponse.json    |   5 +-
 .../listipforwardingrulesresponse.json          |   3 +-
 .../test/resources/listnetworksresponse.json    |  96 ++++-
 .../listportforwardingrulesresponse.json        |  30 +-
 .../test/resources/listprojectsresponse.json    |  36 +-
 .../listpublicipaddressesresponse.json          |  32 +-
 .../resources/listsecuritygroupsresponse.json   | 118 ++++++-
 .../src/test/resources/listtagsresponse.json    |  16 +
 .../test/resources/listtemplatesresponse.json   | 130 ++++++-
 .../listvirtualmachinesresponse3x.json          |  57 ++-
 .../listvolumesreponse-imageextension.json      |   2 -
 .../src/test/resources/listzonesresponse.json   |  30 +-
 79 files changed, 3643 insertions(+), 390 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApi.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApi.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApi.java
index a873643..d333246 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApi.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApi.java
@@ -37,6 +37,7 @@ import org.jclouds.cloudstack.features.SSHKeyPairApi;
 import org.jclouds.cloudstack.features.SecurityGroupApi;
 import org.jclouds.cloudstack.features.SessionApi;
 import org.jclouds.cloudstack.features.SnapshotApi;
+import org.jclouds.cloudstack.features.TagApi;
 import org.jclouds.cloudstack.features.TemplateApi;
 import org.jclouds.cloudstack.features.VMGroupApi;
 import org.jclouds.cloudstack.features.VirtualMachineApi;
@@ -195,4 +196,10 @@ public interface CloudStackApi extends Closeable {
     */
    @Delegate
    ProjectApi getProjectApi();
+
+   /**
+    * Provides synchronous access to Tags
+    */
+   @Delegate
+   TagApi getTagApi();
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java
index 37e79e2..8c604b8 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java
@@ -100,6 +100,7 @@ public class FirewallRule implements Comparable<FirewallRule> {
       protected String ipAddressId;
       protected FirewallRule.Protocol protocol;
       protected FirewallRule.State state;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see FirewallRule#getId()
@@ -185,8 +186,20 @@ public class FirewallRule implements Comparable<FirewallRule> {
          return self();
       }
 
+      /**
+       * @see FirewallRule#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public FirewallRule build() {
-         return new FirewallRule(id, CIDRs, startPort, endPort, icmpCode, icmpType, ipAddress, ipAddressId, protocol, state);
+         return new FirewallRule(id, CIDRs, startPort, endPort, icmpCode, icmpType, ipAddress, ipAddressId, protocol, state, tags);
       }
 
       public T fromFirewallRule(FirewallRule in) {
@@ -200,7 +213,8 @@ public class FirewallRule implements Comparable<FirewallRule> {
                .ipAddress(in.getIpAddress())
                .ipAddressId(in.getIpAddressId())
                .protocol(in.getProtocol())
-               .state(in.getState());
+               .state(in.getState())
+               .tags(in.getTags());
       }
    }
 
@@ -221,14 +235,15 @@ public class FirewallRule implements Comparable<FirewallRule> {
    private final String ipAddressId;
    private final FirewallRule.Protocol protocol;
    private final FirewallRule.State state;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "cidrlist", "startport", "endport", "icmpcode", "icmptype", "ipaddress", "ipaddressid", "protocol", "state"
+         "id", "cidrlist", "startport", "endport", "icmpcode", "icmptype", "ipaddress", "ipaddressid", "protocol", "state", "tags"
    })
    private FirewallRule(String id, @Nullable String CIDRs, int startPort, int endPort, @Nullable String icmpCode,
                         @Nullable String icmpType, @Nullable String ipAddress, @Nullable String ipAddressId,
-                        @Nullable Protocol protocol, @Nullable State state) {
-      this(id, splitStringOnCommas(CIDRs), startPort, endPort, icmpCode, icmpType, ipAddress, ipAddressId, protocol, state);
+                        @Nullable Protocol protocol, @Nullable State state, @Nullable Set<Tag> tags) {
+      this(id, splitStringOnCommas(CIDRs), startPort, endPort, icmpCode, icmpType, ipAddress, ipAddressId, protocol, state, tags);
    }
 
    private static Set<String> splitStringOnCommas(String in) {
@@ -238,7 +253,7 @@ public class FirewallRule implements Comparable<FirewallRule> {
 
    protected FirewallRule(String id, @Nullable Iterable<String> CIDRs, int startPort, int endPort, @Nullable String icmpCode,
                           @Nullable String icmpType, @Nullable String ipAddress, @Nullable String ipAddressId,
-                          @Nullable FirewallRule.Protocol protocol, @Nullable FirewallRule.State state) {
+                          @Nullable FirewallRule.Protocol protocol, @Nullable FirewallRule.State state, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.CIDRs = CIDRs == null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(CIDRs);
       this.startPort = startPort;
@@ -249,6 +264,7 @@ public class FirewallRule implements Comparable<FirewallRule> {
       this.ipAddressId = ipAddressId;
       this.protocol = protocol;
       this.state = state;
+      this.tags = tags == null ? ImmutableSet.<Tag>of() : ImmutableSet.copyOf(tags);
    }
 
    public String getId() {
@@ -297,9 +313,14 @@ public class FirewallRule implements Comparable<FirewallRule> {
       return this.state;
    }
 
+   @Nullable
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, CIDRs, startPort, endPort, icmpCode, icmpType, ipAddress, ipAddressId, protocol, state);
+      return Objects.hashCode(id, CIDRs, startPort, endPort, icmpCode, icmpType, ipAddress, ipAddressId, protocol, state, tags);
    }
 
    @Override
@@ -316,13 +337,15 @@ public class FirewallRule implements Comparable<FirewallRule> {
             && Objects.equal(this.ipAddress, that.ipAddress)
             && Objects.equal(this.ipAddressId, that.ipAddressId)
             && Objects.equal(this.protocol, that.protocol)
-            && Objects.equal(this.state, that.state);
+            && Objects.equal(this.state, that.state)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this)
             .add("id", id).add("CIDRs", CIDRs).add("startPort", startPort).add("endPort", endPort).add("icmpCode", icmpCode)
-            .add("icmpType", icmpType).add("ipAddress", ipAddress).add("ipAddressId", ipAddressId).add("protocol", protocol).add("state", state);
+            .add("icmpType", icmpType).add("ipAddress", ipAddress).add("ipAddressId", ipAddressId).add("protocol", protocol).add("state", state)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IPForwardingRule.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IPForwardingRule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IPForwardingRule.java
index 6703c80..e06888b 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IPForwardingRule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IPForwardingRule.java
@@ -58,6 +58,7 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
       protected Set<String> CIDRs = ImmutableSet.of();
       protected int privateEndPort;
       protected int publicEndPort;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see IPForwardingRule#getId()
@@ -175,9 +176,21 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
          return self();
       }
 
+      /**
+       * @see IPForwardingRule#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public IPForwardingRule build() {
          return new IPForwardingRule(id, IPAddress, IPAddressId, startPort, protocol, endPort, state, virtualMachineDisplayName,
-               virtualMachineId, virtualMachineName, publicPort, CIDRs, privateEndPort, publicEndPort);
+               virtualMachineId, virtualMachineName, publicPort, CIDRs, privateEndPort, publicEndPort, tags);
       }
 
       public T fromIPForwardingRule(IPForwardingRule in) {
@@ -195,7 +208,8 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
                .publicPort(in.getPublicPort())
                .CIDRs(in.getCIDRs())
                .privateEndPort(in.getPrivateEndPort())
-               .publicEndPort(in.getPublicEndPort());
+               .publicEndPort(in.getPublicEndPort())
+               .tags(in.getTags());
       }
    }
 
@@ -220,15 +234,17 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
    private final Set<String> CIDRs;
    private final int privateEndPort;
    private final int publicEndPort;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
          "id", "ipaddress", "ipaddressid", "startport", "protocol", "endport", "state", "virtualmachinedisplayname",
-         "virtualmachineid", "virtualmachinename", "publicport", "cidrlist", "privateendport", "publicendport"
+         "virtualmachineid", "virtualmachinename", "publicport", "cidrlist", "privateendport", "publicendport", "tags"
    })
    protected IPForwardingRule(String id, String IPAddress, String IPAddressId, int startPort, @Nullable String protocol,
                               int endPort, @Nullable String state, @Nullable String virtualMachineDisplayName,
                               @Nullable String virtualMachineId, @Nullable String virtualMachineName, int publicPort,
-                              @Nullable Set<String> CIDRs, int privateEndPort, int publicEndPort) {
+                              @Nullable Set<String> CIDRs, int privateEndPort, int publicEndPort,
+                              @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.IPAddress = IPAddress;
       this.IPAddressId = IPAddressId;
@@ -243,6 +259,7 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
       this.CIDRs = CIDRs == null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(CIDRs);
       this.privateEndPort = privateEndPort;
       this.publicEndPort = publicEndPort;
+      this.tags = tags == null ? ImmutableSet.<Tag>of() : ImmutableSet.copyOf(tags);
    }
 
    /**
@@ -350,9 +367,17 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
       return this.publicEndPort;
    }
 
+   /**
+    * @return Tags on this rule
+    */
+   @Nullable
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, IPAddress, IPAddressId, startPort, protocol, endPort, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, publicPort, CIDRs, privateEndPort, publicEndPort);
+      return Objects.hashCode(id, IPAddress, IPAddressId, startPort, protocol, endPort, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, publicPort, CIDRs, privateEndPort, publicEndPort, tags);
    }
 
    @Override
@@ -373,7 +398,8 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
             && Objects.equal(this.publicPort, that.publicPort)
             && Objects.equal(this.CIDRs, that.CIDRs)
             && Objects.equal(this.privateEndPort, that.privateEndPort)
-            && Objects.equal(this.publicEndPort, that.publicEndPort);
+            && Objects.equal(this.publicEndPort, that.publicEndPort)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -381,7 +407,8 @@ public class IPForwardingRule implements Comparable<IPForwardingRule> {
             .add("id", id).add("IPAddress", IPAddress).add("IPAddressId", IPAddressId).add("startPort", startPort)
             .add("protocol", protocol).add("endPort", endPort).add("state", state).add("virtualMachineDisplayName", virtualMachineDisplayName)
             .add("virtualMachineId", virtualMachineId).add("virtualMachineName", virtualMachineName).add("publicPort", publicPort)
-            .add("CIDRs", CIDRs).add("privateEndPort", privateEndPort).add("publicEndPort", publicEndPort);
+            .add("CIDRs", CIDRs).add("privateEndPort", privateEndPort).add("publicEndPort", publicEndPort)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ISO.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ISO.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ISO.java
index 3e79b04..a93304a 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ISO.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ISO.java
@@ -20,7 +20,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.MoreObjects;
@@ -90,6 +92,7 @@ public class ISO {
       protected String templateType;
       protected String zoneId;
       protected String zoneName;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see ISO#getId()
@@ -347,11 +350,23 @@ public class ISO {
          return self();
       }
 
+      /**
+       * @see ISO#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public ISO build() {
          return new ISO(id, account, accountId, bootable, checksum, created, crossZones, displayText, domain, domainid,
                format, hostId, hostName, hypervisor, isExtractable, isFeatured, isPublic, isReady, jobId, jobStatus, name,
                osTypeId, osTypeName, passwordEnabled, removed, size, sourceTemplateId, status, templateTag, templateType,
-               zoneId, zoneName);
+               zoneId, zoneName, tags);
       }
 
       public T fromISO(ISO in) {
@@ -387,7 +402,8 @@ public class ISO {
                .templateTag(in.getTemplateTag())
                .templateType(in.getTemplateType())
                .zoneId(in.getZoneId())
-               .zoneName(in.getZoneName());
+               .zoneName(in.getZoneName())
+               .tags(in.getTags());
       }
    }
 
@@ -430,9 +446,10 @@ public class ISO {
    private final String templateType;
    private final String zoneId;
    private final String zoneName;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "account", "accountid", "bootable", "checksum", "created", "crossZones", "displaytext", "domain", "domainid", "format", "hostid", "hostname", "hypervisor", "isextractable", "isfeatured", "ispublic", "isready", "jobid", "jobstatus", "name", "ostypeid", "ostypename", "passwordenabled", "removed", "size", "sourcetemplateid", "status", "templatetag", "templatetype", "zoneid", "zonename"
+         "id", "account", "accountid", "bootable", "checksum", "created", "crossZones", "displaytext", "domain", "domainid", "format", "hostid", "hostname", "hypervisor", "isextractable", "isfeatured", "ispublic", "isready", "jobid", "jobstatus", "name", "ostypeid", "ostypename", "passwordenabled", "removed", "size", "sourcetemplateid", "status", "templatetag", "templatetype", "zoneid", "zonename", "tags"
    })
    protected ISO(String id, @Nullable String account, @Nullable String accountId, boolean bootable, @Nullable String checksum,
                  @Nullable Date created, boolean crossZones, @Nullable String displayText, @Nullable String domain,
@@ -440,7 +457,8 @@ public class ISO {
                  @Nullable String hypervisor, boolean isExtractable, boolean isFeatured, boolean isPublic, boolean isReady,
                  @Nullable String jobId, @Nullable String jobStatus, @Nullable String name, @Nullable String osTypeId,
                  @Nullable String osTypeName, boolean passwordEnabled, @Nullable Date removed, long size, @Nullable String sourceTemplateId,
-                 @Nullable String status, @Nullable String templateTag, @Nullable String templateType, @Nullable String zoneId, @Nullable String zoneName) {
+                 @Nullable String status, @Nullable String templateTag, @Nullable String templateType, @Nullable String zoneId, @Nullable String zoneName,
+                 @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.accountId = accountId;
@@ -473,6 +491,7 @@ public class ISO {
       this.templateType = templateType;
       this.zoneId = zoneId;
       this.zoneName = zoneName;
+      this.tags = tags == null ? ImmutableSet.<Tag>of() : ImmutableSet.copyOf(tags);
    }
 
    /**
@@ -701,11 +720,20 @@ public class ISO {
       return this.zoneName;
    }
 
+   /**
+    * @return Tags on this ISO
+    */
+   @Nullable
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
       return Objects.hashCode(id, account, accountId, bootable, checksum, created, crossZones, displayText, domain,
             domainid, format, hostId, hostName, hypervisor, isExtractable, isFeatured, isPublic, isReady, jobId, jobStatus,
-            name, osTypeId, osTypeName, passwordEnabled, removed, size, sourceTemplateId, status, templateTag, templateType, zoneId, zoneName);
+            name, osTypeId, osTypeName, passwordEnabled, removed, size, sourceTemplateId, status, templateTag, templateType, zoneId, zoneName,
+            tags);
    }
 
    @Override
@@ -744,7 +772,8 @@ public class ISO {
             && Objects.equal(this.templateTag, that.templateTag)
             && Objects.equal(this.templateType, that.templateType)
             && Objects.equal(this.zoneId, that.zoneId)
-            && Objects.equal(this.zoneName, that.zoneName);
+            && Objects.equal(this.zoneName, that.zoneName)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -756,7 +785,7 @@ public class ISO {
             .add("isReady", isReady).add("jobId", jobId).add("jobStatus", jobStatus).add("name", name).add("osTypeId", osTypeId)
             .add("osTypeName", osTypeName).add("passwordEnabled", passwordEnabled).add("removed", removed).add("size", size)
             .add("sourceTemplateId", sourceTemplateId).add("status", status).add("templateTag", templateTag).add("templateType", templateType)
-            .add("zoneId", zoneId).add("zoneName", zoneName);
+            .add("zoneId", zoneId).add("zoneName", zoneName).add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IngressRule.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IngressRule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IngressRule.java
index efb5ff9..df3a388 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IngressRule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/IngressRule.java
@@ -19,12 +19,13 @@ package org.jclouds.cloudstack.domain;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
-
-import org.jclouds.javax.annotation.Nullable;
+import java.util.Set;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.javax.annotation.Nullable;
 
 public class IngressRule implements Comparable<IngressRule> {
 
@@ -48,6 +49,7 @@ public class IngressRule implements Comparable<IngressRule> {
       protected String id;
       protected String securityGroupName;
       protected int startPort;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see IngressRule#getAccount()
@@ -121,8 +123,20 @@ public class IngressRule implements Comparable<IngressRule> {
          return self();
       }
 
+      /**
+       * @see IngressRule#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public IngressRule build() {
-         return new IngressRule(account, CIDR, endPort, ICMPCode, ICMPType, protocol, id, securityGroupName, startPort);
+         return new IngressRule(account, CIDR, endPort, ICMPCode, ICMPType, protocol, id, securityGroupName, startPort, tags);
       }
 
       public T fromIngressRule(IngressRule in) {
@@ -135,7 +149,8 @@ public class IngressRule implements Comparable<IngressRule> {
                .protocol(in.getProtocol())
                .id(in.getId())
                .securityGroupName(in.getSecurityGroupName())
-               .startPort(in.getStartPort());
+               .startPort(in.getStartPort())
+               .tags(in.getTags());
       }
    }
 
@@ -155,12 +170,14 @@ public class IngressRule implements Comparable<IngressRule> {
    private final String id;
    private final String securityGroupName;
    private final int startPort;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "account", "cidr", "endport", "icmpcode", "icmptype", "protocol", "ruleid", "securitygroupname", "startport"
+         "account", "cidr", "endport", "icmpcode", "icmptype", "protocol", "ruleid", "securitygroupname", "startport", "tags"
    })
    protected IngressRule(@Nullable String account, @Nullable String CIDR, int endPort, int ICMPCode, int ICMPType,
-                         @Nullable String protocol, String id, @Nullable String securityGroupName, int startPort) {
+                         @Nullable String protocol, String id, @Nullable String securityGroupName, int startPort,
+                         @Nullable Set<Tag> tags) {
       this.account = account;
       this.CIDR = CIDR;
       this.endPort = endPort;
@@ -170,6 +187,7 @@ public class IngressRule implements Comparable<IngressRule> {
       this.id = checkNotNull(id, "id");
       this.securityGroupName = securityGroupName;
       this.startPort = startPort;
+      this.tags = tags == null ? ImmutableSet.<Tag>of() : ImmutableSet.copyOf(tags);
    }
 
    /**
@@ -239,9 +257,17 @@ public class IngressRule implements Comparable<IngressRule> {
       return this.startPort;
    }
 
+   /**
+    * @return Tags on this rule
+    */
+   @Nullable
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(account, CIDR, endPort, ICMPCode, ICMPType, protocol, id, securityGroupName, startPort);
+      return Objects.hashCode(account, CIDR, endPort, ICMPCode, ICMPType, protocol, id, securityGroupName, startPort, tags);
    }
 
    @Override
@@ -257,13 +283,15 @@ public class IngressRule implements Comparable<IngressRule> {
             && Objects.equal(this.protocol, that.protocol)
             && Objects.equal(this.id, that.id)
             && Objects.equal(this.securityGroupName, that.securityGroupName)
-            && Objects.equal(this.startPort, that.startPort);
+            && Objects.equal(this.startPort, that.startPort)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this)
             .add("account", account).add("CIDR", CIDR).add("endPort", endPort).add("ICMPCode", ICMPCode)
-            .add("ICMPType", ICMPType).add("protocol", protocol).add("id", id).add("securityGroupName", securityGroupName).add("startPort", startPort);
+            .add("ICMPType", ICMPType).add("protocol", protocol).add("id", id).add("securityGroupName", securityGroupName).add("startPort", startPort)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
index a6ec5a4..bcfd411 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
@@ -76,9 +76,9 @@ public class Network {
       protected String VLAN;
       protected TrafficType trafficType;
       protected String zoneId;
-      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
       protected boolean securityGroupEnabled;
       protected Set<? extends NetworkService> services = ImmutableSortedSet.of();
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see Network#getId()
@@ -298,23 +298,6 @@ public class Network {
       }
 
       /**
-       * @see Network#getTags()
-       */
-      public T tags(Iterable<String> tags) {
-         this.tags = ImmutableSet.<String>builder().addAll(tags);
-         return self();
-      }
-      
-      /**
-       * @see Network#getTags()
-       */
-      public T tag(String tag) {
-         this.tags.add(tag);
-         return self();
-      }
-      
-
-      /**
        * @see Network#isSecurityGroupEnabled()
        */
       public T securityGroupEnabled(boolean securityGroupEnabled) {
@@ -330,8 +313,20 @@ public class Network {
          return self();
       }
 
+      /**
+       * @see Network#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public Network build() {
-         return new Network(id, account, broadcastDomainType, broadcastURI, displayText, DNS1, DNS2, domain, domainId, endIP, gateway, isDefault, isShared, isSystem, netmask, networkDomain, networkOfferingAvailability, networkOfferingDisplayText, networkOfferingId, networkOfferingName, related, startIP, name, state, guestIPType, VLAN, trafficType, zoneId, tags.build(), securityGroupEnabled, services);
+         return new Network(id, account, broadcastDomainType, broadcastURI, displayText, DNS1, DNS2, domain, domainId, endIP, gateway, isDefault, isShared, isSystem, netmask, networkDomain, networkOfferingAvailability, networkOfferingDisplayText, networkOfferingId, networkOfferingName, related, startIP, name, state, guestIPType, VLAN, trafficType, zoneId, tags, securityGroupEnabled, services);
       }
 
       public T fromNetwork(Network in) {
@@ -363,9 +358,9 @@ public class Network {
                .VLAN(in.getVLAN())
                .trafficType(in.getTrafficType())
                .zoneId(in.getZoneId())
-               .tags(in.getTags())
                .securityGroupEnabled(in.isSecurityGroupEnabled())
-               .services(in.getServices());
+               .services(in.getServices())
+               .tags(in.getTags());
       }
    }
 
@@ -404,7 +399,7 @@ public class Network {
    private final String VLAN;
    private final TrafficType trafficType;
    private final String zoneId;
-   private final Set<String> tags;
+   private final Set<Tag> tags;
    private final boolean securityGroupEnabled;
    private final Set<? extends NetworkService> services;
 
@@ -418,7 +413,7 @@ public class Network {
                      @Nullable String networkOfferingDisplayText, @Nullable String networkOfferingId, @Nullable String networkOfferingName,
                      @Nullable String related, @Nullable String startIP, @Nullable String name, @Nullable String state,
                      @Nullable GuestIPType guestIPType, @Nullable String VLAN, @Nullable TrafficType trafficType,
-                     @Nullable String zoneId, @Nullable Iterable<String> tags, boolean securityGroupEnabled, Set<? extends NetworkService> services) {
+                     @Nullable String zoneId, @Nullable Set<Tag> tags, boolean securityGroupEnabled, Set<? extends NetworkService> services) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.broadcastDomainType = broadcastDomainType;
@@ -447,7 +442,7 @@ public class Network {
       this.VLAN = VLAN;
       this.trafficType = trafficType;
       this.zoneId = zoneId;
-      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
       this.securityGroupEnabled = securityGroupEnabled;
       this.services = ImmutableSortedSet.copyOf(services);
    }
@@ -667,7 +662,7 @@ public class Network {
    /**
     * @return the tags for the Network
     */
-   public Set<String> getTags() {
+   public Set<Tag> getTags() {
       return this.tags;
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java
index 2b3fcdf..b98123f 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java
@@ -101,6 +101,7 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
       protected Set<String> CIDRs = ImmutableSet.of();
       protected int privateEndPort;
       protected int publicEndPort;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see PortForwardingRule#getId()
@@ -210,9 +211,21 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
          return self();
       }
 
+      /**
+       * @see PortForwardingRule#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public PortForwardingRule build() {
          return new PortForwardingRule(id, IPAddress, IPAddressId, privatePort, protocol, publicPort, state, virtualMachineDisplayName,
-               virtualMachineId, virtualMachineName, CIDRs, privateEndPort, publicEndPort);
+               virtualMachineId, virtualMachineName, CIDRs, privateEndPort, publicEndPort, tags);
       }
 
       public T fromPortForwardingRule(PortForwardingRule in) {
@@ -229,7 +242,8 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
                .virtualMachineName(in.getVirtualMachineName())
                .CIDRs(in.getCIDRs())
                .privateEndPort(in.getPrivateEndPort())
-               .publicEndPort(in.getPublicEndPort());
+               .publicEndPort(in.getPublicEndPort())
+               .tags(in.getTags());
       }
    }
 
@@ -253,17 +267,18 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
    private final Set<String> CIDRs;
    private final int privateEndPort;
    private final int publicEndPort;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
          "id", "ipaddress", "ipaddressid", "privateport", "protocol", "publicport", "state", "virtualmachinedisplayname",
-         "virtualmachineid", "virtualmachinename", "cidrlist", "privateendport", "publicendport"
+         "virtualmachineid", "virtualmachinename", "cidrlist", "privateendport", "publicendport", "tags"
    })
    private PortForwardingRule(String id, @Nullable String IPAddress, @Nullable String IPAddressId, int privatePort,
                               @Nullable Protocol protocol, int publicPort, @Nullable State state, @Nullable String virtualMachineDisplayName,
                               @Nullable String virtualMachineId, @Nullable String virtualMachineName, @Nullable String CIDRs,
-                              int privateEndPort, int publicEndPort) {
+                              int privateEndPort, int publicEndPort, @Nullable Set<Tag> tags) {
       this(id, IPAddress, IPAddressId, privatePort, protocol, publicPort, state, virtualMachineDisplayName, virtualMachineId,
-            virtualMachineName, splitStringOnCommas(CIDRs), privateEndPort, publicEndPort);
+            virtualMachineName, splitStringOnCommas(CIDRs), privateEndPort, publicEndPort, tags);
    }
 
    private static Set<String> splitStringOnCommas(String in) {
@@ -273,7 +288,8 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
    protected PortForwardingRule(String id, @Nullable String IPAddress, @Nullable String IPAddressId, int privatePort,
                                 @Nullable Protocol protocol, int publicPort, @Nullable State state,
                                 @Nullable String virtualMachineDisplayName, @Nullable String virtualMachineId,
-                                @Nullable String virtualMachineName, @Nullable Set<String> CIDRs, int privateEndPort, int publicEndPort) {
+                                @Nullable String virtualMachineName, @Nullable Set<String> CIDRs, int privateEndPort,
+                                int publicEndPort, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.IPAddress = IPAddress;
       this.IPAddressId = IPAddressId;
@@ -287,6 +303,7 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
       this.CIDRs = CIDRs == null ? ImmutableSet.<String>of() : ImmutableSet.copyOf(CIDRs);
       this.privateEndPort = privateEndPort;
       this.publicEndPort = publicEndPort;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    /**
@@ -387,9 +404,16 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
       return this.publicEndPort;
    }
 
+   /**
+    * @return the tags for the rule
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, IPAddress, IPAddressId, privatePort, protocol, publicPort, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, CIDRs, privateEndPort, publicEndPort);
+      return Objects.hashCode(id, IPAddress, IPAddressId, privatePort, protocol, publicPort, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, CIDRs, privateEndPort, publicEndPort, tags);
    }
 
    @Override
@@ -409,7 +433,8 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
             && Objects.equal(this.virtualMachineName, that.virtualMachineName)
             && Objects.equal(this.CIDRs, that.CIDRs)
             && Objects.equal(this.privateEndPort, that.privateEndPort)
-            && Objects.equal(this.publicEndPort, that.publicEndPort);
+            && Objects.equal(this.publicEndPort, that.publicEndPort)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -417,7 +442,7 @@ public class PortForwardingRule implements Comparable<PortForwardingRule> {
             .add("id", id).add("IPAddress", IPAddress).add("IPAddressId", IPAddressId).add("privatePort", privatePort)
             .add("protocol", protocol).add("publicPort", publicPort).add("state", state).add("virtualMachineDisplayName", virtualMachineDisplayName)
             .add("virtualMachineId", virtualMachineId).add("virtualMachineName", virtualMachineName).add("CIDRs", CIDRs)
-            .add("privateEndPort", privateEndPort).add("publicEndPort", publicEndPort);
+            .add("privateEndPort", privateEndPort).add("publicEndPort", publicEndPort).add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Project.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Project.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Project.java
index 29323a4..cecc372 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Project.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Project.java
@@ -19,7 +19,9 @@ package org.jclouds.cloudstack.domain;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.CaseFormat;
@@ -68,6 +70,7 @@ public class Project implements Comparable<Project> {
       protected String domainId;
       protected String name;
       protected State state;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see org.jclouds.cloudstack.domain.Project#getId()
@@ -125,20 +128,32 @@ public class Project implements Comparable<Project> {
          return self();
       }
 
+      /**
+       * @see Project#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
 
       public Project build() {
-         return new Project(id, account, displayText, domain, domainId, name, state);
+         return new Project(id, account, displayText, domain, domainId, name, state, tags);
       }
 
       public T fromDomain(Project in) {
          return this
-                 .id(in.getId())
-                 .account(in.getAccount())
-                 .displayText(in.getDisplayText())
-                 .domain(in.getDomain())
-                 .domainId(in.getDomainId())
-                 .name(in.getName())
-                 .state(in.getState());
+               .id(in.getId())
+               .account(in.getAccount())
+               .displayText(in.getDisplayText())
+               .domain(in.getDomain())
+               .domainId(in.getDomainId())
+               .name(in.getName())
+               .state(in.getState())
+               .tags(in.getTags());
       }
    }
 
@@ -156,12 +171,13 @@ public class Project implements Comparable<Project> {
    private final String domainId;
    private final String name;
    private final State state;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "account", "displaytext", "domain", "domainid", "name", "state"
+         "id", "account", "displaytext", "domain", "domainid", "name", "state", "tags"
    })
    protected Project(String id, String account, String displayText, String domain, String domainId,
-                     String name, State state) {
+                     String name, State state, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.displayText = displayText;
@@ -169,6 +185,7 @@ public class Project implements Comparable<Project> {
       this.domainId = domainId;
       this.name = name;
       this.state = checkNotNull(state, "state");
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    public String getId() {
@@ -204,9 +221,16 @@ public class Project implements Comparable<Project> {
       return this.state;
    }
 
+   /**
+    * @return the tags for the project
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, account, displayText, domain, domainId, name, state);
+      return Objects.hashCode(id, account, displayText, domain, domainId, name, state, tags);
    }
 
    @Override
@@ -220,13 +244,15 @@ public class Project implements Comparable<Project> {
             && Objects.equal(this.domain, that.domain)
             && Objects.equal(this.domainId, that.domainId)
             && Objects.equal(this.name, that.name)
-            && Objects.equal(this.state, that.state);
+            && Objects.equal(this.state, that.state)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this).omitNullValues()
             .add("id", id).add("account", account).add("displayText", displayText)
-              .add("domain", domain).add("domainId", domainId).add("name", name).add("state", state);
+            .add("domain", domain).add("domainId", domainId).add("name", name).add("state", state)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PublicIPAddress.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PublicIPAddress.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PublicIPAddress.java
index 1d6cff3..d6211df 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PublicIPAddress.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PublicIPAddress.java
@@ -20,7 +20,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.CaseFormat;
@@ -85,6 +87,7 @@ public class PublicIPAddress {
       protected String zoneName;
       protected String jobId;
       protected Integer jobStatus;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see PublicIPAddress#getId()
@@ -254,8 +257,20 @@ public class PublicIPAddress {
          return self();
       }
 
+      /**
+       * @see PublicIPAddress#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public PublicIPAddress build() {
-         return new PublicIPAddress(id, account, allocated, associatedNetworkId, domain, domainId, usesVirtualNetwork, IPAddress, isSourceNAT, isStaticNAT, networkId, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, VLANId, VLANName, zoneId, zoneName, jobId, jobStatus);
+         return new PublicIPAddress(id, account, allocated, associatedNetworkId, domain, domainId, usesVirtualNetwork, IPAddress, isSourceNAT, isStaticNAT, networkId, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, VLANId, VLANName, zoneId, zoneName, jobId, jobStatus, tags);
       }
 
       public T fromPublicIPAddress(PublicIPAddress in) {
@@ -280,7 +295,8 @@ public class PublicIPAddress {
                .zoneId(in.getZoneId())
                .zoneName(in.getZoneName())
                .jobId(in.getJobId())
-               .jobStatus(in.getJobStatus());
+               .jobStatus(in.getJobStatus())
+               .tags(in.getTags());
       }
    }
 
@@ -312,18 +328,19 @@ public class PublicIPAddress {
    private final String zoneName;
    private final String jobId;
    private final Integer jobStatus;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
          "id", "account", "allocated", "associatednetworkid", "domain", "domainid", "forvirtualnetwork", "ipaddress", "issourcenat",
          "isstaticnat", "networkid", "state", "virtualmachinedisplayname", "virtualmachineid", "virtualmachinename", "VLANid",
-         "VLANname", "zoneid", "zonename", "jobid", "jobstatus"
+         "VLANname", "zoneid", "zonename", "jobid", "jobstatus", "tags"
    })
    protected PublicIPAddress(String id, @Nullable String account, @Nullable Date allocated, @Nullable String associatedNetworkId,
                              @Nullable String domain, @Nullable String domainId, boolean usesVirtualNetwork, @Nullable String IPAddress,
                              boolean isSourceNAT, boolean isStaticNAT, @Nullable String networkId, @Nullable PublicIPAddress.State state,
                              @Nullable String virtualMachineDisplayName, @Nullable String virtualMachineId, @Nullable String virtualMachineName,
                              @Nullable String VLANId, @Nullable String VLANName, @Nullable String zoneId, @Nullable String zoneName,
-                             @Nullable String jobId, @Nullable Integer jobStatus) {
+                             @Nullable String jobId, @Nullable Integer jobStatus, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.allocated = allocated;
@@ -345,6 +362,7 @@ public class PublicIPAddress {
       this.zoneName = zoneName;
       this.jobId = jobId;
       this.jobStatus = jobStatus;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    /**
@@ -517,9 +535,16 @@ public class PublicIPAddress {
       return this.jobStatus;
    }
 
+   /**
+    * @return the tags for the public IP address
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, account, allocated, associatedNetworkId, domain, domainId, usesVirtualNetwork, IPAddress, isSourceNAT, isStaticNAT, networkId, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, VLANId, VLANName, zoneId, zoneName, jobId, jobStatus);
+      return Objects.hashCode(id, account, allocated, associatedNetworkId, domain, domainId, usesVirtualNetwork, IPAddress, isSourceNAT, isStaticNAT, networkId, state, virtualMachineDisplayName, virtualMachineId, virtualMachineName, VLANId, VLANName, zoneId, zoneName, jobId, jobStatus, tags);
    }
 
    @Override
@@ -547,7 +572,8 @@ public class PublicIPAddress {
             && Objects.equal(this.zoneId, that.zoneId)
             && Objects.equal(this.zoneName, that.zoneName)
             && Objects.equal(this.jobId, that.jobId)
-            && Objects.equal(this.jobStatus, that.jobStatus);
+            && Objects.equal(this.jobStatus, that.jobStatus)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
@@ -557,7 +583,7 @@ public class PublicIPAddress {
             .add("isSourceNAT", isSourceNAT).add("isStaticNAT", isStaticNAT).add("networkId", networkId).add("state", state)
             .add("virtualMachineDisplayName", virtualMachineDisplayName).add("virtualMachineId", virtualMachineId)
             .add("virtualMachineName", virtualMachineName).add("VLANId", VLANId).add("VLANName", VLANName).add("zoneId", zoneId)
-            .add("zoneName", zoneName).add("jobId", jobId).add("jobStatus", jobStatus);
+            .add("zoneName", zoneName).add("jobId", jobId).add("jobStatus", jobStatus).add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SecurityGroup.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SecurityGroup.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SecurityGroup.java
index 356fb00..b261965 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SecurityGroup.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SecurityGroup.java
@@ -54,6 +54,7 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
       protected String jobId;
       protected Integer jobStatus;
       protected Set<IngressRule> ingressRules;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see SecurityGroup#getId()
@@ -127,8 +128,20 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
          return self();
       }
 
+      /**
+       * @see SecurityGroup#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public SecurityGroup build() {
-         return new SecurityGroup(id, account, name, description, domain, domainId, jobId, jobStatus, ingressRules);
+         return new SecurityGroup(id, account, name, description, domain, domainId, jobId, jobStatus, ingressRules, tags);
       }
 
       public T fromSecurityGroup(SecurityGroup in) {
@@ -141,7 +154,8 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
                .domainId(in.getDomainId())
                .jobId(in.getJobId())
                .jobStatus(in.getJobStatus())
-               .ingressRules(in.getIngressRules());
+               .ingressRules(in.getIngressRules())
+               .tags(in.getTags());
       }
    }
 
@@ -161,13 +175,14 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
    private final String jobId;
    private final Integer jobStatus;
    private final Set<IngressRule> ingressRules;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "account", "name", "description", "domain", "domainid", "jobid", "jobstatus", "ingressrule"
+         "id", "account", "name", "description", "domain", "domainid", "jobid", "jobstatus", "ingressrule", "tags"
    })
    protected SecurityGroup(String id, @Nullable String account, @Nullable String name, @Nullable String description,
                            @Nullable String domain, @Nullable String domainId, @Nullable String jobId, @Nullable Integer jobStatus,
-                           @Nullable Set<IngressRule> ingressRules) {
+                           @Nullable Set<IngressRule> ingressRules, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.name = name;
@@ -177,6 +192,7 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
       this.jobId = jobId;
       this.jobStatus = jobStatus;
       this.ingressRules = ingressRules == null ? ImmutableSet.<IngressRule>of() : ImmutableSortedSet.copyOf(ingressRules);
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    /**
@@ -251,9 +267,16 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
       return this.ingressRules;
    }
 
+   /**
+    * @return the tags for the security group
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, account, name, description, domain, domainId, jobId, jobStatus, ingressRules);
+      return Objects.hashCode(id, account, name, description, domain, domainId, jobId, jobStatus, ingressRules, tags);
    }
 
    @Override
@@ -269,12 +292,14 @@ public class SecurityGroup implements Comparable<SecurityGroup> {
             && Objects.equal(this.domainId, that.domainId)
             && Objects.equal(this.jobId, that.jobId)
             && Objects.equal(this.jobStatus, that.jobStatus)
-            && Objects.equal(this.ingressRules, that.ingressRules);
+            && Objects.equal(this.ingressRules, that.ingressRules)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this).add("id", id).add("account", account).add("name", name).add("description", description)
-            .add("domain", domain).add("domainId", domainId).add("jobId", jobId).add("jobStatus", jobStatus).add("ingressRules", ingressRules);
+            .add("domain", domain).add("domainId", domainId).add("jobId", jobId).add("jobStatus", jobStatus).add("ingressRules", ingressRules)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java
index d832a2a..86636d0 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java
@@ -20,7 +20,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.CaseFormat;
@@ -108,6 +110,7 @@ public class Snapshot {
       protected String volumeId;
       protected String volumeName;
       protected Volume.Type volumeType;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see Snapshot#getId()
@@ -221,9 +224,21 @@ public class Snapshot {
          return self();
       }
 
+      /**
+       * @see Snapshot#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public Snapshot build() {
          return new Snapshot(id, account, created, domain, domainId, interval, jobId, jobStatus, name, snapshotType, state,
-               volumeId, volumeName, volumeType);
+               volumeId, volumeName, volumeType, tags);
       }
 
       public T fromSnapshot(Snapshot in) {
@@ -241,7 +256,8 @@ public class Snapshot {
                .state(in.getState())
                .volumeId(in.getVolumeId())
                .volumeName(in.getVolumeName())
-               .volumeType(in.getVolumeType());
+               .volumeType(in.getVolumeType())
+               .tags(in.getTags());
       }
    }
 
@@ -266,14 +282,15 @@ public class Snapshot {
    private final String volumeId;
    private final String volumeName;
    private final Volume.Type volumeType;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
-         "id", "account", "created", "domain", "domainid", "intervaltype", "jobid", "jobstatus", "name", "snapshottype", "state", "volumeid", "volumename", "volumetype"
+         "id", "account", "created", "domain", "domainid", "intervaltype", "jobid", "jobstatus", "name", "snapshottype", "state", "volumeid", "volumename", "volumetype", "tags"
    })
    protected Snapshot(String id, @Nullable String account, @Nullable Date created, @Nullable String domain, @Nullable String domainId,
                       @Nullable Snapshot.Interval interval, @Nullable String jobId, @Nullable String jobStatus, @Nullable String name,
                       @Nullable Snapshot.Type snapshotType, @Nullable Snapshot.State state, @Nullable String volumeId, @Nullable String volumeName,
-                      @Nullable Volume.Type volumeType) {
+                      @Nullable Volume.Type volumeType, @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.created = created;
@@ -288,6 +305,7 @@ public class Snapshot {
       this.volumeId = volumeId;
       this.volumeName = volumeName;
       this.volumeType = volumeType;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<Tag> of();
    }
 
    /**
@@ -401,9 +419,16 @@ public class Snapshot {
       return this.volumeType;
    }
 
+   /**
+    * @return the tags for the snapshot
+    */
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, account, created, domain, domainId, interval, jobId, jobStatus, name, snapshotType, state, volumeId, volumeName, volumeType);
+      return Objects.hashCode(id, account, created, domain, domainId, interval, jobId, jobStatus, name, snapshotType, state, volumeId, volumeName, volumeType, tags);
    }
 
    @Override
@@ -424,14 +449,16 @@ public class Snapshot {
             && Objects.equal(this.state, that.state)
             && Objects.equal(this.volumeId, that.volumeId)
             && Objects.equal(this.volumeName, that.volumeName)
-            && Objects.equal(this.volumeType, that.volumeType);
+            && Objects.equal(this.volumeType, that.volumeType)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this)
             .add("id", id).add("account", account).add("created", created).add("domain", domain).add("domainId", domainId)
             .add("interval", interval).add("jobId", jobId).add("jobStatus", jobStatus).add("name", name).add("snapshotType", snapshotType)
-            .add("state", state).add("volumeId", volumeId).add("volumeName", volumeName).add("volumeType", volumeType);
+            .add("state", state).add("volumeId", volumeId).add("volumeName", volumeName).add("volumeType", volumeType)
+            .add("tags", tags);
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Tag.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Tag.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Tag.java
new file mode 100644
index 0000000..1868c51
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Tag.java
@@ -0,0 +1,352 @@
+/*
+ * 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 org.jclouds.cloudstack.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.Map;
+
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.jclouds.javax.annotation.Nullable;
+
+/**
+ * Class Tag
+ */
+public class Tag {
+
+   /**
+    * Type of resource to update.
+    */
+   public enum ResourceType {
+      USER_VM("UserVm"),
+      TEMPLATE("Template"),
+      ISO("ISO"),
+      VOLUME("Volume"),
+      SNAPSHOT("Snapshot"),
+      NETWORK("Network"),
+      NIC("Nic"),
+      LOAD_BALANCER("LoadBalancer"),
+      PORT_FORWARDING_RULE("PortForwardingRule"),
+      FIREWALL_RULE("FirewallRule"),
+      SECURITY_GROUP("SecurityGroup"),
+      PUBLIC_IP_ADDRESS("PublicIpAddress"),
+      PROJECT("Project"),
+      VPC("Vpc"),
+      NETWORK_ACL("NetworkACL"),
+      STATIC_ROUTE("StaticRoute"),
+      VM_SNAPSHOT("VMSnapshot"),
+      REMOTE_ACCESS_VPN("RemoteAccessVpn"),
+      ZONE("Zone"),
+      SERVICE_OFFERING("ServiceOffering"),
+      STORAGE("Storage"),
+      PRIVATE_GATEWAY("PrivateGateway"),
+      NETWORK_ACL_LIST("NetworkACLList"),
+      VPN_GATEWAY("VpnGateway"),
+      CUSTOMER_GATEWAY("CustomerGateway"),
+      VPN_CONNECTION("VpnConnection"),
+      UNRECOGNIZED("");
+
+      private String code;
+
+      private static final Map<String, ResourceType> INDEX = Maps.uniqueIndex(ImmutableSet.copyOf(ResourceType.values()),
+              new Function<ResourceType, String>() {
+
+                 @Override
+                 public String apply(ResourceType input) {
+                    return input.code;
+                 }
+
+              });
+
+      ResourceType(String code) {
+         this.code = code;
+      }
+
+      public String getCode() {
+         return code;
+      }
+
+      @Override
+      public String toString() {
+         return code;
+      }
+
+      public static ResourceType fromValue(String resourceType) {
+         String code = checkNotNull(resourceType, "resourcetype");
+         return INDEX.containsKey(code) ? INDEX.get(code) : UNRECOGNIZED;
+      }
+   }
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromTag(this);
+   }
+
+   public abstract static class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String account;
+      protected String customer;
+      protected String domain;
+      protected String domainId;
+      protected String key;
+      protected String project;
+      protected String projectId;
+      protected String resourceId;
+      protected ResourceType resourceType;
+      protected String value;
+
+      /**
+       * @see Tag#getAccount()
+       */
+      public T account(String account) {
+         this.account = account;
+         return self();
+      }
+
+      /**
+       * @see Tag#getCustomer()
+       */
+      public T customer(String customer) {
+         this.customer = customer;
+         return self();
+      }
+
+      /**
+       * @see Tag#getDomain()
+       */
+      public T domain(String domain) {
+         this.domain = domain;
+         return self();
+      }
+
+      /**
+       * @see Tag#getDomainId()
+       */
+      public T domainId(String domainId) {
+         this.domainId = domainId;
+         return self();
+      }
+
+      /**
+       * @see Tag#getKey()
+       */
+      public T key(String key) {
+         this.key = key;
+         return self();
+      }
+
+      /**
+       * @see Tag#getProject()
+       */
+      public T project(String project) {
+         this.project = project;
+         return self();
+      }
+
+      /**
+       * @see Tag#getProjectId()
+       */
+      public T projectId(String projectId) {
+         this.projectId = projectId;
+         return self();
+      }
+
+      /**
+       * @see Tag#getResourceId()
+       */
+      public T resourceId(String resourceId) {
+         this.resourceId = resourceId;
+         return self();
+      }
+
+      /**
+       * @see Tag#getResourceType()
+       */
+      public T resourceType(ResourceType resourceType) {
+         this.resourceType = resourceType;
+         return self();
+      }
+
+      /**
+       * @see Tag#getValue()
+       */
+      public T value(String value) {
+         this.value = value;
+         return self();
+      }
+
+      public Tag build() {
+         return new Tag(account, customer, domain, domainId, key, project,
+                 projectId, resourceId, resourceType, value);
+      }
+
+      public T fromTag(Tag in) {
+         return this
+                 .account(in.getAccount())
+                 .customer(in.getCustomer())
+                 .domain(in.getDomain())
+                 .domainId(in.getDomainId())
+                 .key(in.getKey())
+                 .project(in.getProject())
+                 .projectId(in.getProjectId())
+                 .resourceId(in.getResourceId())
+                 .resourceType(in.getResourceType())
+                 .value(in.getValue());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final String account;
+   private final String customer;
+   private final String domain;
+   private final String domainId;
+   private final String key;
+   private final String project;
+   private final String projectId;
+   private final String resourceId;
+   private final ResourceType resourceType;
+   private final String value;
+
+   @ConstructorProperties({
+           "account", "customer", "domain", "domainid", "key", "project", "projectid", "resourceid",
+            "resourcetype", "value"
+   })
+   protected Tag(@Nullable String account, @Nullable String customer, @Nullable String domain,
+                 @Nullable String domainId, @Nullable String key, @Nullable String project,
+                 @Nullable String projectId, @Nullable String resourceId,
+                 @Nullable ResourceType resourceType, @Nullable String value) {
+      this.account = account;
+      this.customer = customer;
+      this.domain = domain;
+      this.domainId = domainId;
+      this.key = key;
+      this.project = project;
+      this.projectId = projectId;
+      this.resourceId = resourceId;
+      this.resourceType = resourceType;
+      this.value = value;
+   }
+
+   @Nullable
+   public String getAccount() {
+      return this.account;
+   }
+
+   @Nullable
+   public String getCustomer() {
+      return this.customer;
+   }
+
+   @Nullable
+   public String getDomain() {
+      return this.domain;
+   }
+
+   @Nullable
+   public String getDomainId() {
+      return this.domainId;
+   }
+
+   @Nullable
+   public String getKey() {
+      return this.key;
+   }
+
+   @Nullable
+   public String getProject() {
+      return this.project;
+   }
+
+   @Nullable
+   public String getProjectId() {
+      return this.projectId;
+   }
+
+   @Nullable
+   public String getResourceId() {
+      return this.resourceId;
+   }
+
+   @Nullable
+   public ResourceType getResourceType() {
+      return this.resourceType;
+   }
+
+   @Nullable
+   public String getValue() {
+      return this.value;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(account, customer, domain, domainId, key, project, projectId,
+              resourceId, resourceType, value);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Tag that = Tag.class.cast(obj);
+      return Objects.equal(this.account, that.account)
+              && Objects.equal(this.customer, that.customer)
+              && Objects.equal(this.domain, that.domain)
+              && Objects.equal(this.domainId, that.domainId)
+              && Objects.equal(this.key, that.key)
+              && Objects.equal(this.project, that.project)
+              && Objects.equal(this.projectId, that.projectId)
+              && Objects.equal(this.resourceId, that.resourceId)
+              && Objects.equal(this.resourceType, that.resourceType)
+              && Objects.equal(this.value, that.value);
+   }
+
+   protected ToStringHelper string() {
+      return MoreObjects.toStringHelper(this)
+              .add("account", account)
+              .add("customer", customer)
+              .add("domain", domain)
+              .add("domainId", domainId)
+              .add("key", key)
+              .add("project", project)
+              .add("projectId", projectId)
+              .add("resourceId", resourceId)
+              .add("resourceType", resourceType)
+              .add("value", value);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Template.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Template.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Template.java
index 8019579..76dce48 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Template.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Template.java
@@ -20,13 +20,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
-
-import com.google.common.base.Strings;
-import org.jclouds.javax.annotation.Nullable;
+import java.util.Set;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.javax.annotation.Nullable;
 
 public class Template implements Comparable<Template> {
    public enum Status {
@@ -166,6 +167,7 @@ public class Template implements Comparable<Template> {
       protected String hostName;
       protected String sourceTemplateId;
       protected String templateTag;
+      protected Set<Tag> tags = ImmutableSet.of();
 
       /**
        * @see Template#getId()
@@ -423,8 +425,20 @@ public class Template implements Comparable<Template> {
          return self();
       }
 
+      /**
+       * @see Template#getTags()
+       */
+      public T tags(Set<Tag> tags) {
+         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+         return self();
+      }
+
+      public T tags(Tag... in) {
+         return tags(ImmutableSet.copyOf(in));
+      }
+
       public Template build() {
-         return new Template(id, displayText, domain, domainId, account, accountId, zone, zoneId, OSType, OSTypeId, name, type, status, format, hypervisor, size, created, removed, crossZones, bootable, extractable, featured, isPublic, ready, passwordEnabled, jobId, jobStatus, checksum, hostId, hostName, sourceTemplateId, templateTag);
+         return new Template(id, displayText, domain, domainId, account, accountId, zone, zoneId, OSType, OSTypeId, name, type, status, format, hypervisor, size, created, removed, crossZones, bootable, extractable, featured, isPublic, ready, passwordEnabled, jobId, jobStatus, checksum, hostId, hostName, sourceTemplateId, templateTag, tags);
       }
 
       public T fromTemplate(Template in) {
@@ -460,7 +474,8 @@ public class Template implements Comparable<Template> {
                .hostId(in.getHostId())
                .hostName(in.getHostName())
                .sourceTemplateId(in.getSourceTemplateId())
-               .templateTag(in.getTemplateTag());
+               .templateTag(in.getTemplateTag())
+               .tags(in.getTags());
       }
    }
 
@@ -503,12 +518,13 @@ public class Template implements Comparable<Template> {
    private final String hostName;
    private final String sourceTemplateId;
    private final String templateTag;
+   private final Set<Tag> tags;
 
    @ConstructorProperties({
          "id", "displaytext", "domain", "domainid", "account", "accountid", "zonename", "zoneid", "ostypename", "ostypeid",
          "name", "templatetype", "status", "format", "hypervisor", "size", "created", "removed", "crossZones", "bootable",
          "isextractable", "isfeatured", "ispublic", "isready", "passwordenabled", "jobid", "jobstatus", "checksum", "hostId",
-         "hostname", "sourcetemplateid", "templatetag"
+         "hostname", "sourcetemplateid", "templatetag", "tags"
    })
    protected Template(String id, @Nullable String displayText, @Nullable String domain, @Nullable String domainId,
                       @Nullable String account, @Nullable String accountId, @Nullable String zone, @Nullable String zoneId,
@@ -517,7 +533,8 @@ public class Template implements Comparable<Template> {
                       @Nullable Long size, @Nullable Date created, @Nullable Date removed, boolean crossZones,
                       boolean bootable, boolean extractable, boolean featured, boolean ispublic, boolean ready, boolean passwordEnabled,
                       @Nullable String jobId, @Nullable String jobStatus, @Nullable String checksum, @Nullable String hostId,
-                      @Nullable String hostName, @Nullable String sourceTemplateId, @Nullable String templateTag) {
+                      @Nullable String hostName, @Nullable String sourceTemplateId, @Nullable String templateTag,
+                      @Nullable Set<Tag> tags) {
       this.id = checkNotNull(id, "id");
       this.displayText = displayText;
       this.domain = domain;
@@ -550,6 +567,7 @@ public class Template implements Comparable<Template> {
       this.hostName = hostName;
       this.sourceTemplateId = sourceTemplateId;
       this.templateTag = templateTag;
+      this.tags = tags == null ? ImmutableSet.<Tag>of() : ImmutableSet.copyOf(tags);
    }
 
    /**
@@ -806,9 +824,17 @@ public class Template implements Comparable<Template> {
       return this.templateTag;
    }
 
+   /**
+    * @return the tags on this template
+    */
+   @Nullable
+   public Set<Tag> getTags() {
+      return this.tags;
+   }
+
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, displayText, domain, domainId, account, accountId, zone, zoneId, OSType, OSTypeId, name, type, status, format, hypervisor, size, created, removed, crossZones, bootable, extractable, featured, ispublic, ready, passwordEnabled, jobId, jobStatus, checksum, hostId, hostName, sourceTemplateId, templateTag);
+      return Objects.hashCode(id, displayText, domain, domainId, account, accountId, zone, zoneId, OSType, OSTypeId, name, type, status, format, hypervisor, size, created, removed, crossZones, bootable, extractable, featured, ispublic, ready, passwordEnabled, jobId, jobStatus, checksum, hostId, hostName, sourceTemplateId, templateTag, tags);
    }
 
    @Override
@@ -847,12 +873,13 @@ public class Template implements Comparable<Template> {
             && Objects.equal(this.hostId, that.hostId)
             && Objects.equal(this.hostName, that.hostName)
             && Objects.equal(this.sourceTemplateId, that.sourceTemplateId)
-            && Objects.equal(this.templateTag, that.templateTag);
+            && Objects.equal(this.templateTag, that.templateTag)
+            && Objects.equal(this.tags, that.tags);
    }
 
    protected ToStringHelper string() {
       return MoreObjects.toStringHelper(this)
-            .add("id", id).add("displayText", displayText).add("domain", domain).add("domainId", domainId).add("account", account).add("accountId", accountId).add("zone", zone).add("zoneId", zoneId).add("OSType", OSType).add("OSTypeId", OSTypeId).add("name", name).add("type", type).add("status", status).add("format", format).add("hypervisor", hypervisor).add("size", size).add("created", created).add("removed", removed).add("crossZones", crossZones).add("bootable", bootable).add("extractable", extractable).add("featured", featured).add("ispublic", ispublic).add("ready", ready).add("passwordEnabled", passwordEnabled).add("jobId", jobId).add("jobStatus", jobStatus).add("checksum", checksum).add("hostId", hostId).add("hostName", hostName).add("sourceTemplateId", sourceTemplateId).add("templateTag", templateTag);
+            .add("id", id).add("displayText", displayText).add("domain", domain).add("domainId", domainId).add("account", account).add("accountId", accountId).add("zone", zone).add("zoneId", zoneId).add("OSType", OSType).add("OSTypeId", OSTypeId).add("name", name).add("type", type).add("status", status).add("format", format).add("hypervisor", hypervisor).add("size", size).add("created", created).add("removed", removed).add("crossZones", crossZones).add("bootable", bootable).add("extractable", extractable).add("featured", featured).add("ispublic", ispublic).add("ready", ready).add("passwordEnabled", passwordEnabled).add("jobId", jobId).add("jobStatus", jobStatus).add("checksum", checksum).add("hostId", hostId).add("hostName", hostName).add("sourceTemplateId", sourceTemplateId).add("templateTag", templateTag).add("tags", tags);
    }
 
    @Override


[5/7] git commit: Adding tags/userMetadata to NodeMetadata transform

Posted by ab...@apache.org.
Adding tags/userMetadata to NodeMetadata transform


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

Branch: refs/heads/jclouds-756
Commit: e3b78b7f0fa53a9278a53b1b01c8c32db53794d5
Parents: 43bb86f
Author: Andrew Bayer <an...@gmail.com>
Authored: Tue Oct 21 15:10:30 2014 -0700
Committer: Andrew Bayer <an...@gmail.com>
Committed: Tue Oct 21 15:10:30 2014 -0700

----------------------------------------------------------------------
 .../functions/VirtualMachineToNodeMetadata.java | 38 +++++++----
 .../CloudStackComputeServiceAdapter.java        | 37 +++++++----
 .../VirtualMachineToNodeMetadataTest.java       | 12 +++-
 .../parse/ListVirtualMachinesResponseTest.java  | 22 ++++++-
 .../resources/listvirtualmachinesresponse.json  | 67 +++++++++++++++++++-
 5 files changed, 145 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/e3b78b7f/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
index cb78ece..5421396 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadata.java
@@ -20,17 +20,28 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Iterables.transform;
 import static com.google.common.collect.Sets.newHashSet;
+import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromValuesOfEmptyString;
 import static org.jclouds.location.predicates.LocationPredicates.idEquals;
 import static org.jclouds.util.InetAddresses2.isPrivateIPAddress;
 
-import java.util.Map;
-import java.util.Set;
-
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import java.util.Map;
+import java.util.Set;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.UncheckedExecutionException;
 import org.jclouds.cloudstack.domain.IPForwardingRule;
 import org.jclouds.cloudstack.domain.NIC;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.VirtualMachine;
 import org.jclouds.collect.Memoized;
 import org.jclouds.compute.domain.HardwareBuilder;
@@ -44,17 +55,6 @@ import org.jclouds.domain.Location;
 import org.jclouds.rest.ResourceNotFoundException;
 import org.jclouds.util.Throwables2;
 
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.base.Throwables;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
 @Singleton
 public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, NodeMetadata> {
 
@@ -119,6 +119,16 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
          builder.operatingSystem(image.getOperatingSystem());
       }
 
+      if (!from.getTags().isEmpty()) {
+         ImmutableMap.Builder<String, String> tagsBuilder = ImmutableMap.<String, String>builder();
+
+         for (Tag tag : from.getTags()) {
+            tagsBuilder.put(tag.getKey(), tag.getValue());
+         }
+
+         addMetadataAndParseTagsFromValuesOfEmptyString(builder, tagsBuilder.build());
+      }
+
       builder.hardware(new HardwareBuilder()
         .ids(from.getServiceOfferingId() + "")
         .name(from.getServiceOfferingName() + "")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/e3b78b7f/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
index 29f5c85..3e666a7 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/compute/strategy/CloudStackComputeServiceAdapter.java
@@ -26,17 +26,24 @@ import static org.jclouds.cloudstack.options.DeployVirtualMachineOptions.Builder
 import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.id;
 import static org.jclouds.cloudstack.predicates.TemplatePredicates.isReady;
 import static org.jclouds.cloudstack.predicates.ZonePredicates.supportsSecurityGroups;
+import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsValuesOfEmptyString;
 import static org.jclouds.ssh.SshKeys.fingerprintPrivateKey;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Sets;
+import com.google.common.primitives.Ints;
 import org.jclouds.cloudstack.CloudStackApi;
 import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
 import org.jclouds.cloudstack.domain.AsyncCreateResponse;
@@ -50,6 +57,7 @@ import org.jclouds.cloudstack.domain.PublicIPAddress;
 import org.jclouds.cloudstack.domain.SecurityGroup;
 import org.jclouds.cloudstack.domain.ServiceOffering;
 import org.jclouds.cloudstack.domain.SshKeyPair;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.Template;
 import org.jclouds.cloudstack.domain.VirtualMachine;
 import org.jclouds.cloudstack.domain.Zone;
@@ -60,6 +68,7 @@ import org.jclouds.cloudstack.functions.CreateFirewallRulesForIP;
 import org.jclouds.cloudstack.functions.CreatePortForwardingRulesForIP;
 import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork;
 import org.jclouds.cloudstack.functions.StaticNATVirtualMachineInNetwork.Factory;
+import org.jclouds.cloudstack.options.CreateTagsOptions;
 import org.jclouds.cloudstack.options.DeployVirtualMachineOptions;
 import org.jclouds.cloudstack.options.ListFirewallRulesOptions;
 import org.jclouds.cloudstack.options.ListTemplatesOptions;
@@ -72,14 +81,6 @@ import org.jclouds.domain.Credentials;
 import org.jclouds.domain.LoginCredentials;
 import org.jclouds.logging.Logger;
 
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
-import com.google.common.collect.Sets;
-import com.google.common.primitives.Ints;
-
 /**
  * defines the connection between the {@link CloudStackApi} implementation
  * and the jclouds {@link ComputeService}
@@ -243,7 +244,17 @@ public class CloudStackComputeServiceAdapter implements
       }
 
       try {
-          if (templateOptions.shouldSetupStaticNat()) {
+         Map<String, String> common = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
+         if (!common.isEmpty()) {
+            logger.debug(">> adding tags %s to virtualmachine(%s)", common, vm.getId());
+            CreateTagsOptions tagOptions = CreateTagsOptions.Builder.resourceIds(vm.getId())
+                  .resourceType(Tag.ResourceType.USER_VM)
+                  .tags(common);
+            AsyncCreateResponse tagJob = client.getTagApi().createTags(tagOptions);
+            awaitCompletion(tagJob.getJobId());
+            logger.debug("<< tags added");
+         }
+         if (templateOptions.shouldSetupStaticNat()) {
              Capabilities capabilities = client.getConfigurationApi().listCapabilities();
              // TODO: possibly not all network ids, do we want to do this
              for (String networkId : options.getNetworkIds()) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/e3b78b7f/apis/cloudstack/src/test/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadataTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadataTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadataTest.java
index 6c055f7..01bf3b3 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadataTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/compute/functions/VirtualMachineToNodeMetadataTest.java
@@ -21,6 +21,7 @@ import static org.testng.Assert.assertEquals;
 import java.net.UnknownHostException;
 import java.util.Set;
 
+import com.google.common.collect.ImmutableMap;
 import org.jclouds.cloudstack.domain.GuestIPType;
 import org.jclouds.cloudstack.domain.IPForwardingRule;
 import org.jclouds.cloudstack.domain.NIC;
@@ -81,7 +82,11 @@ public class VirtualMachineToNodeMetadataTest {
                   .privateAddresses(ImmutableSet.of("10.1.1.18")).publicAddresses(ImmutableSet.of("1.1.1.1"))
                   .hardware(addHypervisor(ServiceOfferingToHardwareTest.one, "XenServer"))
                   .imageId(TemplateToImageTest.one.getId())
-                  .operatingSystem(TemplateToImageTest.one.getOperatingSystem()).build().toString());
+                  .operatingSystem(TemplateToImageTest.one.getOperatingSystem())
+                  .tags(ImmutableSet.of("another-tag"))
+                  .userMetadata(ImmutableMap.of("some-tag", "some-value"))
+                  .build().toString()
+      );
 
    }
 
@@ -177,7 +182,10 @@ public class VirtualMachineToNodeMetadataTest {
                   .privateAddresses(ImmutableSet.of("10.1.1.18"))
                   .hardware(addHypervisor(ServiceOfferingToHardwareTest.one, "XenServer"))
                   .imageId(TemplateToImageTest.one.getId())
-                  .operatingSystem(TemplateToImageTest.one.getOperatingSystem()).build().toString());
+                  .operatingSystem(TemplateToImageTest.one.getOperatingSystem())
+                  .tags(ImmutableSet.of("another-tag"))
+                  .userMetadata(ImmutableMap.of("some-tag", "some-value"))
+                  .build().toString());
    }
 
    protected Hardware addHypervisor(Hardware in, String hypervisor) {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/e3b78b7f/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
index d6b737b..4b0094b 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListVirtualMachinesResponseTest.java
@@ -20,6 +20,7 @@ import java.util.Set;
 
 import org.jclouds.cloudstack.domain.GuestIPType;
 import org.jclouds.cloudstack.domain.NIC;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.TrafficType;
 import org.jclouds.cloudstack.domain.VirtualMachine;
 import org.jclouds.date.internal.SimpleDateFormatDateService;
@@ -69,7 +70,26 @@ public class ListVirtualMachinesResponseTest extends BaseSetParserTest<VirtualMa
             .jobStatus(0)
             .nics(ImmutableSet.of(NIC.builder().id("72").networkId("204").netmask("255.255.255.0").gateway("10.1.1.1")
                   .IPAddress("10.1.1.18").trafficType(TrafficType.GUEST).guestIPType(GuestIPType.VIRTUAL)
-                  .isDefault(true).build())).hypervisor("XenServer").build());
+                  .isDefault(true).build()))
+            .hypervisor("XenServer")
+            .tags(ImmutableSet.of(
+                  Tag.builder().account("adrian")
+                        .resourceId("54")
+                        .resourceType(Tag.ResourceType.USER_VM)
+                        .key("some-tag")
+                        .value("some-value")
+                        .domain("ROOT")
+                        .domainId("1")
+                        .build(),
+                  Tag.builder().account("adrian")
+                        .resourceId("54")
+                        .resourceType(Tag.ResourceType.USER_VM)
+                        .key("another-tag")
+                        .value("")
+                        .domain("ROOT")
+                        .domainId("1")
+                        .build()))
+            .build());
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/e3b78b7f/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json b/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
index 0d27100..f5c0b04 100644
--- a/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
+++ b/apis/cloudstack/src/test/resources/listvirtualmachinesresponse.json
@@ -1 +1,66 @@
-{ "listvirtualmachinesresponse" : { "virtualmachine" : [  {"id":54,"name":"i-3-54-VM","displayname":"i-3-54-VM","account":"adrian","domainid":1,"domain":"ROOT","created":"2011-02-16T14:28:37-0800","state":"Starting","haenable":false,"zoneid":1,"zonename":"San Jose 1","templateid":2,"templatename":"CentOS 5.3(64-bit) no GUI (XenServer)","templatedisplaytext":"CentOS 5.3(64-bit) no GUI (XenServer)","passwordenabled":false,"serviceofferingid":1,"serviceofferingname":"Small Instance","cpunumber":1,"cpuspeed":500,"memory":512,"guestosid":11,"rootdeviceid":0,"rootdevicetype":"NetworkFilesystem","securitygroup":[],"jobid":63,"jobstatus":0,"nic":[{"id":72,"networkid":204,"netmask":"255.255.255.0","gateway":"10.1.1.1","ipaddress":"10.1.1.18","traffictype":"Guest","type":"Virtual","isdefault":true}],"hypervisor":"XenServer"} ] } }
\ No newline at end of file
+{ "listvirtualmachinesresponse": {
+    "virtualmachine": [
+        {
+            "id": 54,
+            "name": "i-3-54-VM",
+            "displayname": "i-3-54-VM",
+            "account": "adrian",
+            "domainid": 1,
+            "domain": "ROOT",
+            "created": "2011-02-16T14:28:37-0800",
+            "state": "Starting",
+            "haenable": false,
+            "zoneid": 1,
+            "zonename": "San Jose 1",
+            "templateid": 2,
+            "templatename": "CentOS 5.3(64-bit) no GUI (XenServer)",
+            "templatedisplaytext": "CentOS 5.3(64-bit) no GUI (XenServer)",
+            "passwordenabled": false,
+            "serviceofferingid": 1,
+            "serviceofferingname": "Small Instance",
+            "cpunumber": 1,
+            "cpuspeed": 500,
+            "memory": 512,
+            "guestosid": 11,
+            "rootdeviceid": 0,
+            "rootdevicetype": "NetworkFilesystem",
+            "securitygroup": [],
+            "jobid": 63,
+            "jobstatus": 0,
+            "nic": [
+                {
+                    "id": 72,
+                    "networkid": 204,
+                    "netmask": "255.255.255.0",
+                    "gateway": "10.1.1.1",
+                    "ipaddress": "10.1.1.18",
+                    "traffictype": "Guest",
+                    "type": "Virtual",
+                    "isdefault": true
+                }
+            ],
+            "hypervisor": "XenServer",
+            "tags": [
+                {
+                    "account": "adrian",
+                    "domain": "ROOT",
+                    "domainid": "1",
+                    "key": "some-tag",
+                    "resourceid": "54",
+                    "resourcetype": "UserVm",
+                    "value": "some-value"
+                },
+                {
+                    "account": "adrian",
+                    "domain": "ROOT",
+                    "domainid": "1",
+                    "key": "another-tag",
+                    "resourceid": "54",
+                    "resourcetype": "UserVm",
+                    "value": ""
+                }
+
+            ]
+        }
+    ]
+} }
\ No newline at end of file


[2/7] JCLOUDS-756. Add support for tags to CloudStack.

Posted by ab...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiExpectTest.java
new file mode 100644
index 0000000..a198579
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiExpectTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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 org.jclouds.cloudstack.features;
+
+import static org.jclouds.util.Strings2.urlEncode;
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.CloudStackContext;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.cloudstack.internal.BaseCloudStackExpectTest;
+import org.jclouds.cloudstack.options.CreateTagsOptions;
+import org.jclouds.cloudstack.options.DeleteTagsOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+/**
+ * Test the CloudStack TagApi
+ */
+@Test(groups = "unit", testName = "TagApiExpectTest")
+public class TagApiExpectTest extends BaseCloudStackExpectTest<TagApi> {
+
+
+   public void testListTagsWhenResponseIs2xx() {
+      TagApi client = requestSendsResponse(
+            HttpRequest.builder().method("GET")
+                  .endpoint("http://localhost:8080/client/api")
+                  .addQueryParam("response", "json")
+                  .addQueryParam("command", "listTags")
+                  .addQueryParam("listAll", "true")
+                  .addQueryParam("apiKey", "identity")
+                  .addQueryParam("signature", "amvtC2a0VHzzDF5SUAIOZpXHd0A%3D")
+                  .addHeader("Accept", "application/json")
+                  .build(),
+            HttpResponse.builder()
+                  .statusCode(200)
+                  .payload(payloadFromResource("/listtagsresponse.json"))
+                  .build()
+      );
+
+      assertEquals(client.listTags(),
+            ImmutableSet.<Tag>of(
+                  Tag.builder()
+                        .account("admin")
+                        .domain("ROOT")
+                        .domainId("79dc06c4-4432-11e4-b70d-000c29e19aa0")
+                        .key("test-tag")
+                        .resourceId("54fe1d53-5d73-4184-8b62-948b9d8e08fb")
+                        .resourceType(Tag.ResourceType.TEMPLATE)
+                        .value("true").build()
+            )
+      );
+   }
+
+   public void testListTagsWhenResponseIs404() {
+      TagApi client = requestSendsResponse(
+         HttpRequest.builder()
+            .method("GET")
+            .endpoint(
+                  URI.create("http://localhost:8080/client/api?response=json&" +
+                        "command=listTags&listAll=true&apiKey=identity&signature=amvtC2a0VHzzDF5SUAIOZpXHd0A%3D")
+            )
+            .addHeader("Accept", "application/json")
+            .build(),
+         HttpResponse.builder()
+            .statusCode(404)
+            .build());
+
+      assertEquals(client.listTags(), ImmutableSet.of());
+   }
+
+   public void testCreateTagsWhenResponseIs2xx() {
+      TagApi client = requestSendsResponse(
+            HttpRequest.builder().method("GET")
+                  .endpoint("http://localhost:8080/client/api")
+                  .addQueryParam("response", "json")
+                  .addQueryParam("command", "createTags")
+                  .addQueryParam("resourcetype", "Template")
+                  .addQueryParam("resourceids", "52d89d5d-6070-4fd4-8131-c6c9ca4b062e")
+                  .addQueryParam(urlEncode("tags[0].key"), "some-tag")
+                  .addQueryParam(urlEncode("tags[0].value"), "some-value")
+                  .addQueryParam("apiKey", "identity")
+                  .addQueryParam("signature", "HDGTKGG9kONEwh5xlLe9R72z%2B9Q%3D")
+                  .addHeader("Accept", "application/json")
+                  .build(),
+            HttpResponse.builder()
+                  .statusCode(200)
+                  .payload(payloadFromResource("/createtagsresponse.json"))
+                  .build()
+      );
+
+      AsyncCreateResponse async = client.createTags(CreateTagsOptions.Builder.resourceType("Template")
+            .resourceIds("52d89d5d-6070-4fd4-8131-c6c9ca4b062e")
+            .tags(ImmutableMap.of("some-tag", "some-value")));
+
+      assertEquals(
+            async,
+            AsyncCreateResponse.builder().jobId("32cfab73-f221-4b2b-a728-a73e924ac95d").build());
+   }
+
+   public void testDeleteTagsWhenResponseIs2xx() {
+      TagApi client = requestSendsResponse(
+            HttpRequest.builder().method("GET")
+                  .endpoint("http://localhost:8080/client/api")
+                  .addQueryParam("response", "json")
+                  .addQueryParam("command", "deleteTags")
+                  .addQueryParam("resourcetype", "Template")
+                  .addQueryParam("resourceids", "52d89d5d-6070-4fd4-8131-c6c9ca4b062e")
+                  .addQueryParam(urlEncode("tags[0].key"), "some-tag")
+                  .addQueryParam(urlEncode("tags[0].value"), "some-value")
+                  .addQueryParam("apiKey", "identity")
+                  .addQueryParam("signature", "inAqWH/GkkGipkZFG5Wfmxa8vOE%3D")
+                  .addHeader("Accept", "application/json")
+                  .build(),
+            HttpResponse.builder()
+                  .statusCode(200)
+                  .payload(payloadFromResource("/deletetagsresponse.json"))
+                  .build()
+      );
+
+      AsyncCreateResponse async = client.deleteTags(DeleteTagsOptions.Builder.resourceType("Template")
+            .resourceIds("52d89d5d-6070-4fd4-8131-c6c9ca4b062e")
+            .tags(ImmutableMap.of("some-tag", "some-value")));
+
+      assertEquals(
+            async,
+            AsyncCreateResponse.builder().jobId("32cfab73-f221-4b2b-a728-a73e924ac95d").build());
+   }
+
+   @Override
+   protected TagApi clientFrom(CloudStackContext context) {
+      return context.getApi().getTagApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiLiveTest.java
new file mode 100644
index 0000000..4f58a1e
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiLiveTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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 org.jclouds.cloudstack.features;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import javax.annotation.Resource;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.DiskOffering;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.cloudstack.domain.Volume;
+import org.jclouds.cloudstack.domain.Zone;
+import org.jclouds.cloudstack.internal.BaseCloudStackApiLiveTest;
+import org.jclouds.cloudstack.options.CreateTagsOptions;
+import org.jclouds.cloudstack.options.DeleteTagsOptions;
+import org.jclouds.cloudstack.options.ListTagsOptions;
+import org.jclouds.cloudstack.options.ListVolumesOptions;
+import org.jclouds.logging.Logger;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code TagApi}
+ */
+@Test(groups = "live", singleThreaded = true, testName = "TagApiLiveTest")
+public class TagApiLiveTest extends BaseCloudStackApiLiveTest {
+
+   @Resource Logger logger = Logger.NULL;
+
+   protected String prefix = System.getProperty("user.name") + "-" + getClass().getSimpleName();
+   protected String volumeToDelete;
+   private String zoneId;
+
+   @BeforeMethod(groups = "live")
+   public void setZoneId() {
+      Set<Zone> zones = client.getZoneApi().listZones();
+      assertNotNull(zones);
+      assertFalse(zones.isEmpty());
+      zoneId = Iterables.get(zones, 0).getId();
+   }
+
+   public void testCreateTags() {
+      createVolumeToTag();
+
+      AsyncCreateResponse job = client.getTagApi().createTags(CreateTagsOptions.Builder.resourceType("Volume")
+            .resourceIds(volumeToDelete)
+            .tags(ImmutableMap.of(prefix + "-first-tag", "first-tag-value",
+                  prefix + "-second-tag", "second-tag-value")));
+      assertTrue(jobComplete.apply(job.getJobId()));
+   }
+
+   @Test(dependsOnMethods = "testCreateTags")
+   public void testListTags() {
+      Set<Tag> tags = client.getTagApi().listTags();
+      assertNotNull(tags);
+      assertFalse(tags.isEmpty());
+
+      for (Tag tag : tags) {
+         checkTag(tag);
+      }
+   }
+
+   @Test(dependsOnMethods = "testListTags")
+   public void testListSingleTag() {
+      Set<Tag> tags = client.getTagApi().listTags(ListTagsOptions.Builder.key(prefix + "-second-tag"));
+      assertNotNull(tags);
+      assertFalse(tags.isEmpty());
+      assertEquals(1, tags.size());
+      for (Tag tag : tags) {
+         assertEquals(volumeToDelete, tag.getResourceId());
+         checkTag(tag);
+      }
+   }
+
+   @Test(dependsOnMethods = "testListSingleTag")
+   public void testListResourceByTag() {
+      Set<Volume> volumes = client.getVolumeApi().listVolumes(ListVolumesOptions.Builder.tags(ImmutableMap.of(prefix + "-second-tag", "second-tag-value")));
+      assertNotNull(volumes);
+      assertFalse(volumes.isEmpty());
+      assertEquals(1, volumes.size());
+   }
+
+   @Test(dependsOnMethods = "testListResourceByTag")
+   public void testDeleteTags() {
+      AsyncCreateResponse job = client.getTagApi().deleteTags(DeleteTagsOptions.Builder.resourceType("Volume")
+            .resourceIds(volumeToDelete)
+            .tags(ImmutableMap.of(prefix + "-first-tag", "first-tag-value",
+                  prefix + "-second-tag", "second-tag-value")));
+      assertTrue(jobComplete.apply(job.getJobId()));
+   }
+
+   static void checkTag(final Tag tag) {
+      assertNotNull(tag.getAccount());
+      assertNotNull(tag.getResourceId());
+   }
+
+   protected DiskOffering getPreferredDiskOffering() {
+      for (DiskOffering candidate : client.getOfferingApi().listDiskOfferings()) {
+         if (!candidate.isCustomized()) {
+            return candidate;
+         }
+      }
+      throw new AssertionError("No suitable DiskOffering found.");
+   }
+
+   protected void createVolumeToTag() {
+      AsyncCreateResponse job = client.getVolumeApi().createVolumeFromDiskOfferingInZone(prefix + "-jclouds-volume",
+            getPreferredDiskOffering().getId(), zoneId);
+      assertTrue(jobComplete.apply(job.getJobId()));
+      logger.info("created volume " + job.getId());
+      volumeToDelete = job.getId();
+   }
+
+   @Override
+   @AfterClass(groups = "live")
+   protected void tearDownContext() {
+      try {
+         client.getVolumeApi().deleteVolume(volumeToDelete);
+      } catch (Exception e) {
+         // Don't really care if there's an exception here
+      }
+      super.tearDownContext();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiTest.java
new file mode 100644
index 0000000..01b1fe5
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/TagApiTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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 org.jclouds.cloudstack.features;
+
+import static org.jclouds.reflect.Reflection2.method;
+import static org.jclouds.util.Strings2.urlEncode;
+
+import java.io.IOException;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.Invokable;
+import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
+import org.jclouds.cloudstack.domain.Tag;
+import org.jclouds.cloudstack.internal.BaseCloudStackApiTest;
+import org.jclouds.cloudstack.options.CreateTagsOptions;
+import org.jclouds.cloudstack.options.DeleteTagsOptions;
+import org.jclouds.cloudstack.options.ListTagsOptions;
+import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.http.functions.UnwrapOnlyJsonValue;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code TagApi}
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "TagApiTest")
+public class TagApiTest extends BaseCloudStackApiTest<TagApi> {
+   public void testListTags() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(TagApi.class, "listTags", ListTagsOptions[].class);
+      GeneratedHttpRequest httpRequest = processor.createRequest(method, ImmutableList.of());
+
+      assertRequestLineEquals(httpRequest,
+            "GET http://localhost:8080/client/api?response=json&command=listTags&listAll=true HTTP/1.1");
+      assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
+      assertPayloadEquals(httpRequest, null, null, false);
+
+      assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
+
+      checkFilters(httpRequest);
+
+   }
+
+   public void testListTagsOptions() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(TagApi.class, "listTags", ListTagsOptions[].class);
+      GeneratedHttpRequest httpRequest = processor.createRequest(method, ImmutableList.<Object> of(
+            ListTagsOptions.Builder.accountInDomain("adrian", "6").resourceType(Tag.ResourceType.TEMPLATE)));
+
+      assertRequestLineEquals(
+            httpRequest,
+            "GET http://localhost:8080/client/api?response=json&command=listTags&listAll=true&account=adrian&domainid=6&resourcetype=Template HTTP/1.1");
+      assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
+      assertPayloadEquals(httpRequest, null, null, false);
+
+      assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
+
+      checkFilters(httpRequest);
+
+   }
+
+   public void testCreateTags() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(TagApi.class, "createTags", CreateTagsOptions.class);
+      GeneratedHttpRequest httpRequest = processor.createRequest(method, ImmutableList.<Object> of(
+            CreateTagsOptions.Builder.resourceIds("1")
+                  .resourceType(Tag.ResourceType.TEMPLATE)
+                  .tags(ImmutableMap.of("some-tag", "some-value"))
+      ));
+
+      assertRequestLineEquals(httpRequest,
+            "GET http://localhost:8080/client/api?response=json&command=createTags&resourceids=1&resourcetype=Template&"
+                  + urlEncode("tags[0].key") + "=some-tag&" + urlEncode("tags[0].value") + "=some-value HTTP/1.1");
+                  assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
+      assertPayloadEquals(httpRequest, null, null, false);
+
+      assertResponseParserClassEquals(method, httpRequest, UnwrapOnlyJsonValue.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class);
+
+      checkFilters(httpRequest);
+   }
+
+   public void testDeleteTags() throws SecurityException, NoSuchMethodException, IOException {
+      Invokable<?, ?> method = method(TagApi.class, "deleteTags", DeleteTagsOptions.class);
+      GeneratedHttpRequest httpRequest = processor.createRequest(method, ImmutableList.<Object> of(
+            DeleteTagsOptions.Builder.resourceIds("1")
+                  .resourceType(Tag.ResourceType.TEMPLATE)
+                  .tags(ImmutableMap.of("some-tag", "some-value"))
+      ));
+
+      assertRequestLineEquals(httpRequest,
+            "GET http://localhost:8080/client/api?response=json&command=deleteTags&resourceids=1&resourcetype=Template&"
+                  + urlEncode("tags[0].key") + "=some-tag&" + urlEncode("tags[0].value") + "=some-value HTTP/1.1");
+      assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
+      assertPayloadEquals(httpRequest, null, null, false);
+
+      assertResponseParserClassEquals(method, httpRequest, UnwrapOnlyJsonValue.class);
+      assertSaxResponseParserClassEquals(method, null);
+      assertFallbackClassEquals(method, MapHttp4xxCodesToExceptions.class);
+
+      checkFilters(httpRequest);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ZoneApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ZoneApiExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ZoneApiExpectTest.java
index 2d709ad..6032ceb 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ZoneApiExpectTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/ZoneApiExpectTest.java
@@ -22,6 +22,7 @@ import java.net.URI;
 
 import org.jclouds.cloudstack.CloudStackContext;
 import org.jclouds.cloudstack.domain.NetworkType;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.Zone;
 import org.jclouds.cloudstack.internal.BaseCloudStackExpectTest;
 import org.jclouds.http.HttpRequest;
@@ -61,10 +62,20 @@ public class ZoneApiExpectTest extends BaseCloudStackExpectTest<ZoneApi> {
                .networkType(NetworkType.ADVANCED)
                .securityGroupsEnabled(false).build(),
             Zone.builder()
-               .id("2")
-               .name("Chicago")
-               .networkType(NetworkType.ADVANCED)
-               .securityGroupsEnabled(true).build()));
+                  .id("2")
+                  .name("Chicago")
+                  .networkType(NetworkType.ADVANCED)
+                  .securityGroupsEnabled(true)
+                  .tags(Tag.builder()
+                        .account("1")
+                        .domain("ROOT")
+                        .domainId("1")
+                        .key("some-tag")
+                        .resourceId("2")
+                        .resourceType(Tag.ResourceType.ZONE)
+                        .value("some-value")
+                        .build())
+                  .build()));
    }
 
    public void testListZonesWhenResponseIs404() {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/CreateTagsOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/CreateTagsOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/CreateTagsOptionsTest.java
new file mode 100644
index 0000000..2fbcc5d
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/CreateTagsOptionsTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import static org.jclouds.cloudstack.options.CreateTagsOptions.Builder.customer;
+import static org.jclouds.cloudstack.options.CreateTagsOptions.Builder.resourceIds;
+import static org.jclouds.cloudstack.options.CreateTagsOptions.Builder.resourceType;
+import static org.jclouds.cloudstack.options.CreateTagsOptions.Builder.tags;
+import static org.testng.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Tag;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code CreateTagsOptions}
+ */
+@Test(groups = "unit")
+public class CreateTagsOptionsTest {
+
+   public void testCustomer() {
+      CreateTagsOptions options = new CreateTagsOptions().customer("some-customer");
+      assertEquals(ImmutableList.of("some-customer"), options.buildQueryParameters().get("customer"));
+   }
+
+   public void testCustomerStatic() {
+      CreateTagsOptions options = customer("some-customer");
+      assertEquals(ImmutableList.of("some-customer"), options.buildQueryParameters().get("customer"));
+   }
+
+   public void testResourceIds() {
+      CreateTagsOptions options = new CreateTagsOptions().resourceIds("1", "2", "3");
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceIdsStatic() {
+      CreateTagsOptions options = resourceIds("1", "2", "3");
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceIdsAsSet() {
+      CreateTagsOptions options = new CreateTagsOptions().resourceIds(ImmutableSet.of("1", "2", "3"));
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceIdsAsSetStatic() {
+      CreateTagsOptions options = resourceIds(ImmutableSet.of("1", "2", "3"));
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceType() {
+      CreateTagsOptions options = new CreateTagsOptions().resourceType(Tag.ResourceType.TEMPLATE);
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeStatic() {
+      CreateTagsOptions options = resourceType(Tag.ResourceType.TEMPLATE);
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeAsString() {
+      CreateTagsOptions options = new CreateTagsOptions().resourceType("Template");
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeAsStringStatic() {
+      CreateTagsOptions options = resourceType("Template");
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testTags() {
+      CreateTagsOptions options = new CreateTagsOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      CreateTagsOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteTagsOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteTagsOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteTagsOptionsTest.java
new file mode 100644
index 0000000..c99edd6
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteTagsOptionsTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import static org.jclouds.cloudstack.options.DeleteTagsOptions.Builder.resourceIds;
+import static org.jclouds.cloudstack.options.DeleteTagsOptions.Builder.resourceType;
+import static org.jclouds.cloudstack.options.DeleteTagsOptions.Builder.tags;
+import static org.testng.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.cloudstack.domain.Tag;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code DeleteTagsOptions}
+ */
+@Test(groups = "unit")
+public class DeleteTagsOptionsTest {
+
+   public void testResourceIds() {
+      DeleteTagsOptions options = new DeleteTagsOptions().resourceIds("1", "2", "3");
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceIdsStatic() {
+      DeleteTagsOptions options = resourceIds("1", "2", "3");
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceIdsAsSet() {
+      DeleteTagsOptions options = new DeleteTagsOptions().resourceIds(ImmutableSet.of("1", "2", "3"));
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceIdsAsSetStatic() {
+      DeleteTagsOptions options = resourceIds(ImmutableSet.of("1", "2", "3"));
+      assertEquals(ImmutableList.of("1,2,3"), options.buildQueryParameters().get("resourceids"));
+   }
+
+   public void testResourceType() {
+      DeleteTagsOptions options = new DeleteTagsOptions().resourceType(Tag.ResourceType.TEMPLATE);
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeStatic() {
+      DeleteTagsOptions options = resourceType(Tag.ResourceType.TEMPLATE);
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeAsString() {
+      DeleteTagsOptions options = new DeleteTagsOptions().resourceType("Template");
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeAsStringStatic() {
+      DeleteTagsOptions options = resourceType("Template");
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testTags() {
+      DeleteTagsOptions options = new DeleteTagsOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      DeleteTagsOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptionsTest.java
index 34bc42f..0fac32b 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListIPForwardingRulesOptionsTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListIPForwardingRulesOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListIPForwardingRulesOptions.Builder.IPAddressId;
 import static org.jclouds.cloudstack.options.ListIPForwardingRulesOptions.Builder.accountInDomain;
 import static org.jclouds.cloudstack.options.ListIPForwardingRulesOptions.Builder.domainId;
@@ -23,6 +24,7 @@ import static org.jclouds.cloudstack.options.ListIPForwardingRulesOptions.Builde
 import static org.jclouds.cloudstack.options.ListIPForwardingRulesOptions.Builder.virtualMachineId;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -84,4 +86,21 @@ public class ListIPForwardingRulesOptionsTest {
       ListIPForwardingRulesOptions options = virtualMachineId("6");
       assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("virtualmachineid"));
    }
+
+   public void testTags() {
+      ListIPForwardingRulesOptions options = new ListIPForwardingRulesOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListIPForwardingRulesOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListISOsOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListISOsOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListISOsOptionsTest.java
index 2494a66..97646d3 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListISOsOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListISOsOptionsTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListISOsOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListISOsOptions.Builder.bootable;
 import static org.jclouds.cloudstack.options.ListISOsOptions.Builder.hypervisor;
 import static org.jclouds.cloudstack.options.ListISOsOptions.Builder.id;
@@ -32,6 +33,8 @@ import static org.testng.Assert.assertEquals;
 
 import java.util.Set;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import org.jclouds.cloudstack.domain.ISO;
 import org.testng.annotations.Test;
 
@@ -164,4 +167,20 @@ public class ListISOsOptionsTest {
       ListISOsOptions options = zoneId("6");
       assertEquals(ImmutableSet.of("6"), options.buildQueryParameters().get("zoneid"));
    }
+
+   public void testTags() {
+      ListISOsOptions options = new ListISOsOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListISOsOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListNetworksOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListNetworksOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListNetworksOptionsTest.java
index 0db9e5a..41e6c8f 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListNetworksOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListNetworksOptionsTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.accountInDomain;
 import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.domainId;
 import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.id;
@@ -27,6 +28,7 @@ import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.type;
 import static org.jclouds.cloudstack.options.ListNetworksOptions.Builder.zoneId;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.jclouds.cloudstack.domain.NetworkType;
 import org.jclouds.cloudstack.domain.TrafficType;
 import org.testng.annotations.Test;
@@ -139,4 +141,21 @@ public class ListNetworksOptionsTest {
       ListNetworksOptions options = type(NetworkType.ADVANCED);
       assertEquals(ImmutableList.of("Advanced"), options.buildQueryParameters().get("type"));
    }
+
+   public void testTags() {
+      ListNetworksOptions options = new ListNetworksOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListNetworksOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java
index 82402ea..677b506 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java
@@ -16,11 +16,13 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.accountInDomain;
 import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.domainId;
 import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.ipAddressId;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -63,4 +65,20 @@ public class ListPortForwardingRulesOptionsTest {
       assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
    }
 
+   public void testTags() {
+      ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListPortForwardingRulesOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptionsTest.java
index fb606ae..7077ee0 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPublicIPAddressesOptionsTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.IPAddress;
 import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.VLANId;
 import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.accountInDomain;
@@ -27,6 +28,7 @@ import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builde
 import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.zoneId;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -128,4 +130,20 @@ public class ListPublicIPAddressesOptionsTest {
       ListPublicIPAddressesOptions options = domainId("6");
       assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
    }
+
+   public void testTags() {
+      ListPublicIPAddressesOptions options = new ListPublicIPAddressesOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListPublicIPAddressesOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptionsTest.java
index 6b5a6e8..624e080 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListSecurityGroupsOptionsTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListSecurityGroupsOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListSecurityGroupsOptions.Builder.accountInDomain;
 import static org.jclouds.cloudstack.options.ListSecurityGroupsOptions.Builder.domainId;
 import static org.jclouds.cloudstack.options.ListSecurityGroupsOptions.Builder.id;
@@ -23,6 +24,7 @@ import static org.jclouds.cloudstack.options.ListSecurityGroupsOptions.Builder.n
 import static org.jclouds.cloudstack.options.ListSecurityGroupsOptions.Builder.virtualMachineId;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -82,4 +84,20 @@ public class ListSecurityGroupsOptionsTest {
       ListSecurityGroupsOptions options = virtualMachineId("6");
       assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("virtualmachineid"));
    }
+
+   public void testTags() {
+      ListSecurityGroupsOptions options = new ListSecurityGroupsOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListSecurityGroupsOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTagsOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTagsOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTagsOptionsTest.java
new file mode 100644
index 0000000..9fa59de
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTagsOptionsTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.accountInDomain;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.customer;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.domainId;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.isRecursive;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.key;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.keyword;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.projectId;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.resourceId;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.resourceType;
+import static org.jclouds.cloudstack.options.ListTagsOptions.Builder.value;
+import static org.testng.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.cloudstack.domain.Tag;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code ListTagsOptions}
+ */
+@Test(groups = "unit")
+public class ListTagsOptionsTest {
+
+   public void testCustomer() {
+      ListTagsOptions options = new ListTagsOptions().customer("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("customer"));
+   }
+
+   public void testCustomerStatic() {
+      ListTagsOptions options = customer("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("customer"));
+   }
+
+   public void testDomainId() {
+      ListTagsOptions options = new ListTagsOptions().domainId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testDomainIdStatic() {
+      ListTagsOptions options = domainId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testAccountInDomainId() {
+      ListTagsOptions options = new ListTagsOptions().accountInDomain("adrian", "6");
+      assertEquals(ImmutableList.of("adrian"), options.buildQueryParameters().get("account"));
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testAccountInDomainIdStatic() {
+      ListTagsOptions options = accountInDomain("adrian", "6");
+      assertEquals(ImmutableList.of("adrian"), options.buildQueryParameters().get("account"));
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testIsRecursive() {
+      ListTagsOptions options = new ListTagsOptions().isRecursive(true);
+      assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("isrecursive"));
+   }
+
+   public void testIsRecursiveStatic() {
+      ListTagsOptions options = isRecursive(true);
+      assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("isrecursive"));
+   }
+
+   public void testKey() {
+      ListTagsOptions options = new ListTagsOptions().key("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("key"));
+   }
+
+   public void testKeyStatic() {
+      ListTagsOptions options = key("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("key"));
+   }
+
+   public void testKeyword() {
+      ListTagsOptions options = new ListTagsOptions().keyword("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("keyword"));
+   }
+
+   public void testKeywordStatic() {
+      ListTagsOptions options = keyword("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("keyword"));
+   }
+
+   public void testProjectId() {
+      ListTagsOptions options = new ListTagsOptions().projectId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("projectid"));
+   }
+
+   public void testProjectIdStatic() {
+      ListTagsOptions options = projectId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("projectid"));
+   }
+
+   public void testResourceId() {
+      ListTagsOptions options = new ListTagsOptions().resourceId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("resourceid"));
+   }
+
+   public void testResourceIdStatic() {
+      ListTagsOptions options = resourceId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("resourceid"));
+   }
+
+   public void testResourceType() {
+      ListTagsOptions options = new ListTagsOptions().resourceType(Tag.ResourceType.TEMPLATE);
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeStatic() {
+      ListTagsOptions options = resourceType(Tag.ResourceType.TEMPLATE);
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeAsString() {
+      ListTagsOptions options = new ListTagsOptions().resourceType("Template");
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testResourceTypeAsStringStatic() {
+      ListTagsOptions options = resourceType("Template");
+      assertEquals(ImmutableList.of("Template"), options.buildQueryParameters().get("resourcetype"));
+   }
+
+   public void testValue() {
+      ListTagsOptions options = new ListTagsOptions().value("some-value");
+      assertEquals(ImmutableList.of("some-value"), options.buildQueryParameters().get("value"));
+   }
+
+   public void testValueStatic() {
+      ListTagsOptions options = value("some-value");
+      assertEquals(ImmutableList.of("some-value"), options.buildQueryParameters().get("value"));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTemplatesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTemplatesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTemplatesOptionsTest.java
index 17be0e0..c246217 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTemplatesOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListTemplatesOptionsTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.accountInDomain;
 import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.domainId;
 import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.filter;
@@ -24,6 +25,7 @@ import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.id;
 import static org.jclouds.cloudstack.options.ListTemplatesOptions.Builder.zoneId;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.jclouds.cloudstack.domain.TemplateFilter;
 import org.testng.annotations.Test;
 
@@ -111,4 +113,20 @@ public class ListTemplatesOptionsTest {
       ListTemplatesOptions options = filter(TemplateFilter.SELF_EXECUTABLE);
       assertEquals(ImmutableList.of("self-executable"), options.buildQueryParameters().get("templatefilter"));
    }
+
+   public void testTags() {
+      ListTemplatesOptions options = new ListTemplatesOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListTemplatesOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachesOptionsTest.java
deleted file mode 100644
index bb5df4c..0000000
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachesOptionsTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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 org.jclouds.cloudstack.options;
-
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.accountInDomain;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.domainId;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.groupId;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.hostId;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.id;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.networkId;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.podId;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.state;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.usesVirtualNetwork;
-import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.zoneId;
-import static org.testng.Assert.assertEquals;
-
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Tests behavior of {@code ListVirtualMachinesOptions}
- */
-@Test(groups = "unit")
-public class ListVirtualMachesOptionsTest {
-
-   public void testHostId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().hostId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("hostid"));
-   }
-
-   public void testHostIdStatic() {
-      ListVirtualMachinesOptions options = hostId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("hostid"));
-   }
-
-   public void testPodId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().podId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("podid"));
-   }
-
-   public void testPodIdStatic() {
-      ListVirtualMachinesOptions options = podId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("podid"));
-   }
-
-   public void testNetworkId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().networkId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("networkid"));
-   }
-
-   public void testNetworkIdStatic() {
-      ListVirtualMachinesOptions options = networkId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("networkid"));
-   }
-
-   public void testGroupId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().groupId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("groupid"));
-   }
-
-   public void testGroupIdStatic() {
-      ListVirtualMachinesOptions options = groupId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("groupid"));
-   }
-
-   public void testAccountInDomainId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().accountInDomain("adrian", "6");
-      assertEquals(ImmutableList.of("adrian"), options.buildQueryParameters().get("account"));
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
-   }
-
-   public void testAccountInDomainIdStatic() {
-      ListVirtualMachinesOptions options = accountInDomain("adrian", "6");
-      assertEquals(ImmutableList.of("adrian"), options.buildQueryParameters().get("account"));
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
-   }
-
-   public void testName() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().id("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
-   }
-
-   public void testNameStatic() {
-      ListVirtualMachinesOptions options = id("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
-   }
-
-   public void testZoneId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().zoneId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid"));
-   }
-
-   public void testZoneIdStatic() {
-      ListVirtualMachinesOptions options = zoneId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid"));
-   }
-
-   public void testState() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().state("state");
-      assertEquals(ImmutableList.of("state"), options.buildQueryParameters().get("state"));
-   }
-
-   public void testStateStatic() {
-      ListVirtualMachinesOptions options = state("state");
-      assertEquals(ImmutableList.of("state"), options.buildQueryParameters().get("state"));
-   }
-
-   public void testUsingVirtualNetwork() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().usesVirtualNetwork(true);
-      assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forvirtualnetwork"));
-   }
-
-   public void testUsingVirtualNetworkStatic() {
-      ListVirtualMachinesOptions options = usesVirtualNetwork(true);
-      assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forvirtualnetwork"));
-   }
-
-   public void testId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().id("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
-   }
-
-   public void testDomainId() {
-      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().domainId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
-   }
-
-   public void testIdStatic() {
-      ListVirtualMachinesOptions options = id("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
-   }
-
-   public void testDomainIdStatic() {
-      ListVirtualMachinesOptions options = domainId("6");
-      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptionsTest.java
new file mode 100644
index 0000000..5288b1a
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListVirtualMachinesOptionsTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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 org.jclouds.cloudstack.options;
+
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.tags;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.accountInDomain;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.domainId;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.groupId;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.hostId;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.id;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.networkId;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.podId;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.state;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.usesVirtualNetwork;
+import static org.jclouds.cloudstack.options.ListVirtualMachinesOptions.Builder.zoneId;
+import static org.testng.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableMap;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests behavior of {@code ListVirtualMachinesOptions}
+ */
+@Test(groups = "unit")
+public class ListVirtualMachinesOptionsTest {
+
+   public void testHostId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().hostId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("hostid"));
+   }
+
+   public void testHostIdStatic() {
+      ListVirtualMachinesOptions options = hostId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("hostid"));
+   }
+
+   public void testPodId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().podId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("podid"));
+   }
+
+   public void testPodIdStatic() {
+      ListVirtualMachinesOptions options = podId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("podid"));
+   }
+
+   public void testNetworkId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().networkId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("networkid"));
+   }
+
+   public void testNetworkIdStatic() {
+      ListVirtualMachinesOptions options = networkId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("networkid"));
+   }
+
+   public void testGroupId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().groupId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("groupid"));
+   }
+
+   public void testGroupIdStatic() {
+      ListVirtualMachinesOptions options = groupId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("groupid"));
+   }
+
+   public void testAccountInDomainId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().accountInDomain("adrian", "6");
+      assertEquals(ImmutableList.of("adrian"), options.buildQueryParameters().get("account"));
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testAccountInDomainIdStatic() {
+      ListVirtualMachinesOptions options = accountInDomain("adrian", "6");
+      assertEquals(ImmutableList.of("adrian"), options.buildQueryParameters().get("account"));
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testName() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().id("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
+   }
+
+   public void testNameStatic() {
+      ListVirtualMachinesOptions options = id("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
+   }
+
+   public void testZoneId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().zoneId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid"));
+   }
+
+   public void testZoneIdStatic() {
+      ListVirtualMachinesOptions options = zoneId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid"));
+   }
+
+   public void testState() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().state("state");
+      assertEquals(ImmutableList.of("state"), options.buildQueryParameters().get("state"));
+   }
+
+   public void testStateStatic() {
+      ListVirtualMachinesOptions options = state("state");
+      assertEquals(ImmutableList.of("state"), options.buildQueryParameters().get("state"));
+   }
+
+   public void testUsingVirtualNetwork() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().usesVirtualNetwork(true);
+      assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forvirtualnetwork"));
+   }
+
+   public void testUsingVirtualNetworkStatic() {
+      ListVirtualMachinesOptions options = usesVirtualNetwork(true);
+      assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forvirtualnetwork"));
+   }
+
+   public void testId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().id("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
+   }
+
+   public void testDomainId() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().domainId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testIdStatic() {
+      ListVirtualMachinesOptions options = id("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
+   }
+
+   public void testDomainIdStatic() {
+      ListVirtualMachinesOptions options = domainId("6");
+      assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
+   }
+
+   public void testTags() {
+      ListVirtualMachinesOptions options = new ListVirtualMachinesOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListVirtualMachinesOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListZonesOptionsTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListZonesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListZonesOptionsTest.java
index 17d1146..49ae57e 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListZonesOptionsTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListZonesOptionsTest.java
@@ -16,11 +16,13 @@
  */
 package org.jclouds.cloudstack.options;
 
+import static org.jclouds.cloudstack.options.ListZonesOptions.Builder.tags;
 import static org.jclouds.cloudstack.options.ListZonesOptions.Builder.available;
 import static org.jclouds.cloudstack.options.ListZonesOptions.Builder.domainId;
 import static org.jclouds.cloudstack.options.ListZonesOptions.Builder.id;
 import static org.testng.Assert.assertEquals;
 
+import com.google.common.collect.ImmutableMap;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -60,4 +62,20 @@ public class ListZonesOptionsTest {
       ListZonesOptions options = domainId("6");
       assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("domainid"));
    }
+
+   public void testTags() {
+      ListZonesOptions options = new ListZonesOptions().tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
+
+   public void testTagsStatic() {
+      ListZonesOptions options = tags(ImmutableMap.of("tag1", "val1", "tag2", "val2"));
+      assertEquals(ImmutableList.of("tag1"), options.buildQueryParameters().get("tags[0].key"));
+      assertEquals(ImmutableList.of("tag2"), options.buildQueryParameters().get("tags[1].key"));
+      assertEquals(ImmutableList.of("val1"), options.buildQueryParameters().get("tags[0].value"));
+      assertEquals(ImmutableList.of("val2"), options.buildQueryParameters().get("tags[1].value"));
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java
index 6af9dff..ed3b07b 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java
@@ -19,6 +19,7 @@ package org.jclouds.cloudstack.parse;
 import java.util.Set;
 
 import org.jclouds.cloudstack.domain.FirewallRule;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.json.config.GsonModule;
 import org.jclouds.rest.annotations.SelectJson;
@@ -59,8 +60,10 @@ public class ListFirewallRulesResponseTest extends BaseSetParserTest<FirewallRul
          FirewallRule.builder().id("2016").protocol(FirewallRule.Protocol.TCP).startPort(22)
             .endPort(22).ipAddressId("2").ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE).CIDRs(CIDRs).build(),
          FirewallRule.builder().id("10").protocol(FirewallRule.Protocol.TCP).startPort(22)
-            .endPort(22).ipAddressId("8").ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE).CIDRs(CIDRs).build()
-      );
+            .endPort(22).ipAddressId("8").ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE).CIDRs(CIDRs)
+            .tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("10")
+                        .resourceType(Tag.ResourceType.FIREWALL_RULE).value("some-value").build()).build()
+               );
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListIPForwardingRulesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListIPForwardingRulesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListIPForwardingRulesResponseTest.java
index 203c41e..92eee75 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListIPForwardingRulesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListIPForwardingRulesResponseTest.java
@@ -19,6 +19,7 @@ package org.jclouds.cloudstack.parse;
 import java.util.Set;
 
 import org.jclouds.cloudstack.domain.IPForwardingRule;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.rest.annotations.SelectJson;
 import org.testng.annotations.Test;
@@ -37,9 +38,11 @@ public class ListIPForwardingRulesResponseTest extends BaseSetParserTest<IPForwa
    @SelectJson("ipforwardingrule")
    public Set<IPForwardingRule> expected() {
       return ImmutableSet.<IPForwardingRule> of(
-         IPForwardingRule.builder().id("66").protocol("tcp").startPort(22).endPort(22).virtualMachineId("58")
-            .virtualMachineDisplayName("i-4-58-VM").virtualMachineName("i-4-58-VM")
-            .IPAddressId("15").IPAddress("10.27.27.64").state("Active").build());
+            IPForwardingRule.builder().id("66").protocol("tcp").startPort(22).endPort(22).virtualMachineId("58")
+                  .virtualMachineDisplayName("i-4-58-VM").virtualMachineName("i-4-58-VM")
+                  .IPAddressId("15").IPAddress("10.27.27.64").state("Active")
+                  .tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("66")
+                        .resourceType(Tag.ResourceType.PORT_FORWARDING_RULE).value("some-value").build()).build());
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListNetworksResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListNetworksResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListNetworksResponseTest.java
index 65ed915..ca0c109 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListNetworksResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListNetworksResponseTest.java
@@ -22,6 +22,7 @@ import java.util.Set;
 import org.jclouds.cloudstack.domain.GuestIPType;
 import org.jclouds.cloudstack.domain.Network;
 import org.jclouds.cloudstack.domain.NetworkService;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.cloudstack.domain.TrafficType;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.rest.annotations.SelectJson;
@@ -75,13 +76,17 @@ public class ListNetworksResponseTest extends BaseSetParserTest<Network> {
                               NetworkService.builder().name("Gateway").build(),
                               NetworkService.builder().name("UserData").build(),
                               NetworkService.builder().name("Dhcp").build(),
-                              NetworkService.builder().name("Firewall").capabilities(ImmutableSortedMap.<String, String> naturalOrder()
+                              NetworkService.builder().name("Firewall").capabilities(ImmutableSortedMap.<String, String>naturalOrder()
                                     .put("SupportedSourceNatTypes", "per account").put("StaticNat", "true")
                                     .put("TrafficStatistics", "per public ip").put("PortForwarding", "true")
                                     .put("MultipleIps", "true").put("SupportedProtocols", "tcp,udp").build()).build(),
                               NetworkService.builder().name("Dns").build(),
                               NetworkService.builder().name("Lb").capabilities(ImmutableMap.of("SupportedLbAlgorithms",
-                                    "roundrobin,leastconn,source", "SupportedProtocols", "tcp, udp")).build()))
-                  .networkDomain("cs3cloud.internal").build());
+                                    "roundrobin,leastconn,source", "SupportedProtocols", "tcp, udp")).build()
+                        )
+                  )
+                  .networkDomain("cs3cloud.internal")
+                  .tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("204")
+                        .resourceType(Tag.ResourceType.NETWORK).value("some-value").build()).build());
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java
index 6356c7d..3038977 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java
@@ -19,6 +19,7 @@ package org.jclouds.cloudstack.parse;
 import java.util.Set;
 
 import org.jclouds.cloudstack.domain.PortForwardingRule;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.json.config.GsonModule;
 import org.jclouds.rest.annotations.SelectJson;
@@ -54,12 +55,14 @@ public class ListPortForwardingRulesResponseTest extends BaseSetParserTest<PortF
    public Set<PortForwardingRule> expected() {
       Set<String> cidrs = ImmutableSet.of("0.0.0.0/1", "128.0.0.0/1");
       return ImmutableSet.<PortForwardingRule> of(
-         PortForwardingRule.builder().id("15").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
-            .publicPort(2022).virtualMachineId("3").virtualMachineName("i-3-3-VM").IPAddressId("3")
-            .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE).CIDRs(cidrs).build(),
-         PortForwardingRule.builder().id("18").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
-            .publicPort(22).virtualMachineId("89").virtualMachineName("i-3-89-VM").IPAddressId("34")
-            .IPAddress("72.52.126.63").state(PortForwardingRule.State.ACTIVE).build());
+            PortForwardingRule.builder().id("15").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
+                  .publicPort(2022).virtualMachineId("3").virtualMachineName("i-3-3-VM").IPAddressId("3")
+                  .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE)
+                  .CIDRs(cidrs).tags(Tag.builder().account("1").domain("ROOT").domainId("1").key("some-tag").resourceId("15")
+                  .resourceType(Tag.ResourceType.PORT_FORWARDING_RULE).value("some-value").build()).build(),
+            PortForwardingRule.builder().id("18").privatePort(22).protocol(PortForwardingRule.Protocol.TCP)
+                  .publicPort(22).virtualMachineId("89").virtualMachineName("i-3-89-VM").IPAddressId("34")
+                  .IPAddress("72.52.126.63").state(PortForwardingRule.State.ACTIVE).build());
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/43bb86f0/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPublicIPAddressesResponseTest.java
----------------------------------------------------------------------
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPublicIPAddressesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPublicIPAddressesResponseTest.java
index a9547d4..a6cfaf8 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPublicIPAddressesResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPublicIPAddressesResponseTest.java
@@ -19,6 +19,7 @@ package org.jclouds.cloudstack.parse;
 import java.util.Set;
 
 import org.jclouds.cloudstack.domain.PublicIPAddress;
+import org.jclouds.cloudstack.domain.Tag;
 import org.jclouds.date.internal.SimpleDateFormatDateService;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.rest.annotations.SelectJson;
@@ -41,7 +42,17 @@ public class ListPublicIPAddressesResponseTest extends BaseSetParserTest<PublicI
             .allocated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-02-19T21:15:01-0800")).zoneId("1")
             .zoneName("San Jose 1").isSourceNAT(false).account("adrian").domainId("1").domain("ROOT")
             .usesVirtualNetwork(true).isStaticNAT(false).associatedNetworkId("204").networkId("200")
-            .state(PublicIPAddress.State.ALLOCATED).build());
+            .state(PublicIPAddress.State.ALLOCATED)
+            .tags(Tag.builder()
+                  .account("adrian")
+                  .domain("ROOT")
+                  .domainId("1")
+                  .key("some-tag")
+                  .resourceId("30")
+                  .resourceType(Tag.ResourceType.PUBLIC_IP_ADDRESS)
+                  .value("some-value")
+                  .build())
+            .build());
    }
 
 }