You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2014/10/27 18:25:48 UTC

[1/3] JCLOUDS-292: Added CloudSigma2 ComputeService

Repository: jclouds-labs
Updated Branches:
  refs/heads/master 75178c770 -> a7dd1933d


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/NICToAddressTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/NICToAddressTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/NICToAddressTest.java
new file mode 100644
index 0000000..70d6b8b
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/NICToAddressTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.cloudsigma2.domain.FirewallPolicy;
+import org.jclouds.cloudsigma2.domain.FirewallRule;
+import org.jclouds.cloudsigma2.domain.IP;
+import org.jclouds.cloudsigma2.domain.IPConfiguration;
+import org.jclouds.cloudsigma2.domain.IPConfigurationType;
+import org.jclouds.cloudsigma2.domain.NIC;
+import org.jclouds.cloudsigma2.domain.VLANInfo;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import java.net.URI;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "NICToAddressTest")
+public class NICToAddressTest {
+
+   private List<NIC> input;
+   private List<String> expected;
+
+   @BeforeMethod
+   public void setUp() throws Exception {
+      input = ImmutableList.of(
+            new NIC.Builder()
+                  .firewallPolicy(new FirewallPolicy.Builder()
+                        .name("firewall")
+                        .rules(ImmutableList.of(new FirewallRule.Builder()
+                              .sourcePort("22")
+                              .destinationPort("123")
+                              .sourceIp("1.2.3.4")
+                              .destinationIp("11.22.33.44")
+                              .build()))
+                        .build())
+                  .build(),
+            new NIC.Builder()
+                  .vlan(new VLANInfo.Builder()
+                        .uuid("a21a4e59-b133-487a-ad7b-16b41ac38e9b")
+                        .resourceUri(new URI("/api/2.0/vlans/a21a4e59-b133-487a-ad7b-16b41ac38e9b/"))
+                        .build())
+                  .build(),
+            new NIC.Builder()
+                  .ipV4Configuration(new IPConfiguration.Builder()
+                        .configurationType(IPConfigurationType.STATIC)
+                        .ip(new IP.Builder()
+                              .uuid("1.2.3.4")
+                              .resourceUri(new URI("api/2.0/ips/1.2.3.4/"))
+                              .build())
+                        .build())
+                  .build(),
+            new NIC.Builder()
+                  .ipV6Configuration(new IPConfiguration.Builder()
+                        .configurationType(IPConfigurationType.STATIC)
+                        .ip(new IP.Builder()
+                              .uuid("2001:0db8:0000:0000:0000:ff00:0042:8329")
+                              .resourceUri(new URI("api/2.0/ips/2001:0db8:0000:0000:0000:ff00:0042:8329/"))
+                              .build())
+                        .build())
+                  .build());
+
+      expected = Lists.newArrayList(null, null, "1.2.3.4", "2001:0db8:0000:0000:0000:ff00:0042:8329");
+   }
+
+   public void testConvertNICs() {
+      NICToAddress function = new NICToAddress();
+      for (int i = 0; i < input.size() - 1; i++) {
+         assertEquals(function.apply(input.get(i)), expected.get(i));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolumeTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolumeTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolumeTest.java
new file mode 100644
index 0000000..d2a1c31
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolumeTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import org.easymock.EasyMock;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.domain.DeviceEmulationType;
+import org.jclouds.cloudsigma2.domain.Drive;
+import org.jclouds.cloudsigma2.domain.DriveInfo;
+import org.jclouds.cloudsigma2.domain.ServerDrive;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.VolumeBuilder;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.math.BigInteger;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "ServerDriveToVolumeTest")
+public class ServerDriveToVolumeTest {
+
+   private ServerDrive input;
+   private Volume expected;
+
+   @BeforeMethod
+   public void setUp() throws Exception {
+      input = new ServerDrive.Builder()
+            .bootOrder(1)
+            .deviceChannel("0:1")
+            .deviceEmulationType(DeviceEmulationType.VIRTIO)
+            .drive(new Drive.Builder()
+                  .uuid("f17cce62-bcc9-4e0b-a57b-a5582b05aff0")
+                  .build())
+            .build();
+
+      expected = new VolumeBuilder()
+            .id("f17cce62-bcc9-4e0b-a57b-a5582b05aff0")
+            .size(1024000000.f)
+            .durable(true)
+            .type(Volume.Type.NAS)
+            .bootDevice(true)
+            .build();
+   }
+
+   public void testConvertServerDrive() {
+      CloudSigma2Api api = EasyMock.createMock(CloudSigma2Api.class);
+
+      DriveInfo mockDrive = new DriveInfo.Builder()
+            .uuid(input.getDrive().getUuid())
+            .size(new BigInteger("1024000000"))
+            .build();
+
+      expect(api.getDriveInfo(input.getDrive().getUuid())).andReturn(mockDrive);
+      replay(api);
+
+      ServerDriveToVolume function = new ServerDriveToVolume(api);
+      assertEquals(function.apply(input), expected);
+
+      verify(api);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadataTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadataTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadataTest.java
new file mode 100644
index 0000000..a77e928
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadataTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.name.Names;
+import org.easymock.EasyMock;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.CloudSigma2ApiMetadata;
+import org.jclouds.cloudsigma2.domain.DeviceEmulationType;
+import org.jclouds.cloudsigma2.domain.Drive;
+import org.jclouds.cloudsigma2.domain.DriveInfo;
+import org.jclouds.cloudsigma2.domain.IP;
+import org.jclouds.cloudsigma2.domain.IPConfiguration;
+import org.jclouds.cloudsigma2.domain.NIC;
+import org.jclouds.cloudsigma2.domain.ServerDrive;
+import org.jclouds.cloudsigma2.domain.ServerInfo;
+import org.jclouds.cloudsigma2.domain.ServerStatus;
+import org.jclouds.cloudsigma2.domain.Tag;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.VolumeBuilder;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.location.suppliers.all.JustProvider;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.Map;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.jclouds.cloudsigma2.compute.config.CloudSigma2ComputeServiceContextModule.serverStatusToNodeStatus;
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "ServerInfoToNodeMetadataTest")
+public class ServerInfoToNodeMetadataTest {
+
+   private ServerInfo input;
+   private NodeMetadata expected;
+   private Map<String, Credentials> credentialStore;
+   private GroupNamingConvention.Factory namingConvention;
+   private LoginCredentials credentials = LoginCredentials.builder().user("ubuntu").password("ubuntu").build();
+   private JustProvider justProvider;
+
+   @BeforeMethod
+   public void setUp() throws Exception {
+      CloudSigma2ApiMetadata metadata = new CloudSigma2ApiMetadata();
+      justProvider = new JustProvider(metadata.getId(), Suppliers.ofInstance(URI.create(metadata
+            .getDefaultEndpoint().get())), ImmutableSet.<String>of());
+
+      input = new ServerInfo.Builder()
+            .uuid("a19a425f-9e92-42f6-89fb-6361203071bb")
+            .name("jclouds-cloudsigma-test_acc_full_server")
+            .cpu(1000)
+            .memory(new BigInteger("268435456"))
+            .status(ServerStatus.STOPPED)
+            .drives(ImmutableList.of(
+                  new Drive.Builder()
+                        .uuid("ae78e68c-9daa-4471-8878-0bb87fa80260")
+                        .resourceUri(new URI("/api/2.0/drives/ae78e68c-9daa-4471-8878-0bb87fa80260/"))
+                        .build().toServerDrive(0, "0:0", DeviceEmulationType.IDE),
+                  new Drive.Builder()
+                        .uuid("22826af4-d6c8-4d39-bd41-9cea86df2976")
+                        .resourceUri(new URI("/api/2.0/drives/22826af4-d6c8-4d39-bd41-9cea86df2976/"))
+                        .build().toServerDrive(1, "0:0", DeviceEmulationType.VIRTIO)))
+            .nics(ImmutableList.of(new NIC.Builder()
+                  .ipV4Configuration(new IPConfiguration.Builder()
+                        .ip(new IP.Builder().uuid("1.2.3.4").build())
+                        .build())
+                  .build()))
+            .meta(ImmutableMap.of("foo", "bar", "image_id", "image"))
+            .tags(ImmutableList.of(new Tag.Builder().uuid("foo").name("foo").build(),
+                  new Tag.Builder().uuid("jclouds-cloudsigma2-s").name("jclouds-cloudsigma2-s").build(),
+                  new Tag.Builder().uuid("jclouds-cloudsigma2").name("jclouds-cloudsigma2").build()
+            ))
+            .build();
+
+      expected = new NodeMetadataBuilder()
+            .ids("a19a425f-9e92-42f6-89fb-6361203071bb")
+            .name("jclouds-cloudsigma-test_acc_full_server")
+            .group("jclouds-cloudsigma")
+            .status(NodeMetadata.Status.SUSPENDED)
+            .location(getOnlyElement(justProvider.get()))
+            .imageId("image")
+            .hardware(new HardwareBuilder()
+                  .ids("a19a425f-9e92-42f6-89fb-6361203071bb")
+                  .processor(new Processor(1, 1000))
+                  .ram(268435456)
+                  .volumes(ImmutableSet.of(
+                        new VolumeBuilder()
+                              .id("ae78e68c-9daa-4471-8878-0bb87fa80260")
+                              .size(1024000f)
+                              .durable(true)
+                              .type(Volume.Type.NAS)
+                              .bootDevice(false)
+                              .build(),
+                        new VolumeBuilder()
+                              .id("22826af4-d6c8-4d39-bd41-9cea86df2976")
+                              .size(1024000f)
+                              .durable(true)
+                              .type(Volume.Type.NAS)
+                              .bootDevice(true)
+                              .build()))
+                  .build())
+            .publicAddresses(ImmutableSet.of("1.2.3.4"))
+            .userMetadata(ImmutableMap.of("foo", "bar", "image_id", "image"))
+            .tags(ImmutableList.of("foo", "cloudsigma2-s", "cloudsigma2"))
+            .credentials(credentials)
+            .build();
+
+      namingConvention = Guice.createInjector(new AbstractModule() {
+         @Override
+         protected void configure() {
+            Names.bindProperties(binder(), new CloudSigma2ApiMetadata().getDefaultProperties());
+         }
+      }).getInstance(GroupNamingConvention.Factory.class);
+
+      credentialStore = ImmutableMap.of("node#a19a425f-9e92-42f6-89fb-6361203071bb", (Credentials) credentials);
+   }
+
+   public void testConvertServerInfo() {
+      CloudSigma2Api api = EasyMock.createMock(CloudSigma2Api.class);
+
+      for (ServerDrive drive : input.getDrives()) {
+         DriveInfo mockDrive = new DriveInfo.Builder()
+               .uuid(drive.getDriveUuid())
+               .size(new BigInteger("1024000"))
+               .build();
+
+         expect(api.getDriveInfo(drive.getDriveUuid())).andReturn(mockDrive);
+      }
+
+      // tags
+      expect(api.getTagInfo("foo")).andReturn(new Tag.Builder().name("foo").build());
+      expect(api.getTagInfo("jclouds-cloudsigma2-s")).andReturn(new Tag.Builder().name("jclouds-cloudsigma2-s")
+            .build());
+      expect(api.getTagInfo("jclouds-cloudsigma2")).andReturn(new Tag.Builder().name("jclouds-cloudsigma2").build());
+
+      replay(api);
+
+      ServerInfoToNodeMetadata function = new ServerInfoToNodeMetadata(new ServerDriveToVolume(api), new NICToAddress(),
+            serverStatusToNodeStatus, namingConvention, credentialStore, justProvider, api);
+
+      NodeMetadata converted = function.apply(input);
+      assertEquals(converted, expected);
+      assertEquals(converted.getName(), expected.getName());
+      assertEquals(converted.getStatus(), expected.getStatus());
+      assertEquals(converted.getPublicAddresses(), expected.getPublicAddresses());
+      assertEquals(converted.getImageId(), expected.getImageId());
+      assertEquals(converted.getHardware(), expected.getHardware());
+      assertEquals(converted.getCredentials(), expected.getCredentials());
+      assertEquals(converted.getGroup(), expected.getGroup());
+      assertEquals(converted.getTags(), expected.getTags());
+      assertEquals(converted.getUserMetadata(), expected.getUserMetadata());
+
+      verify(api);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
new file mode 100644
index 0000000..93caac0
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKeyTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
+import org.jclouds.ssh.SshKeys;
+import org.testng.annotations.Test;
+
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Unit tests for the {@link TemplateOptionsToStatementWithoutPublicKey} class.
+ */
+@Test(groups = "unit", testName = "TemplateOptionsToStatementWithoutPublicKeyTest")
+public class TemplateOptionsToStatementWithoutPublicKeyTest {
+
+   @Test
+   public void testPublicKeyDoesNotGenerateAuthorizePublicKeyStatementIfOnlyPublicKeyOptionsConfigured() {
+      Map<String, String> keys = SshKeys.generate();
+      TemplateOptions options = TemplateOptions.Builder.authorizePublicKey(keys.get("public"));
+
+      TemplateOptionsToStatementWithoutPublicKey function = new TemplateOptionsToStatementWithoutPublicKey();
+      assertNull(function.apply(options));
+   }
+
+   @Test
+   public void testPublicAndRunScriptKeyDoesNotGenerateAuthorizePublicKeyStatementIfRunScriptPresent() {
+      Map<String, String> keys = SshKeys.generate();
+      TemplateOptions options = TemplateOptions.Builder.authorizePublicKey(keys.get("public")).runScript("uptime");
+
+      TemplateOptionsToStatementWithoutPublicKey function = new TemplateOptionsToStatementWithoutPublicKey();
+      Statement statement = function.apply(options);
+
+      assertEquals(statement.render(OsFamily.UNIX), "uptime\n");
+   }
+
+   @Test
+   public void testPublicAndPrivateKeyAndRunScriptDoesNotGenerateAuthorizePublicKeyStatementIfOtherOptionsPresent() {
+      Map<String, String> keys = SshKeys.generate();
+      TemplateOptions options = TemplateOptions.Builder.authorizePublicKey(keys.get("public"))
+            .installPrivateKey(keys.get("private")).runScript("uptime");
+
+      TemplateOptionsToStatementWithoutPublicKey function = new TemplateOptionsToStatementWithoutPublicKey();
+      Statement statement = function.apply(options);
+
+      assertTrue(statement instanceof StatementList);
+      StatementList statements = (StatementList) statement;
+
+      assertEquals(statements.size(), 2);
+      assertEquals(statements.get(0).render(OsFamily.UNIX), "uptime\n");
+      assertTrue(statements.get(1) instanceof InstallRSAPrivateKey);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptionsTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptionsTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptionsTest.java
new file mode 100644
index 0000000..503e7ee
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptionsTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.cloudsigma2.compute.options;
+
+import org.jclouds.cloudsigma2.domain.DeviceEmulationType;
+import org.jclouds.cloudsigma2.domain.Model;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "CloudSigma2TemplateOptionsTest")
+public class CloudSigma2TemplateOptionsTest {
+
+   public void testDefaultsToVirtIO() {
+      CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions();
+      assertEquals(options.getDeviceEmulationType(), DeviceEmulationType.VIRTIO);
+      assertEquals(options.getNicModel(), Model.VIRTIO);
+   }
+
+   public void testDeviceEmulationType() {
+      CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions.Builder()
+            .deviceEmulationType(DeviceEmulationType.IDE);
+      assertEquals(options.getDeviceEmulationType(), DeviceEmulationType.IDE);
+   }
+
+   public void testNicModel() {
+      CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions.Builder().nicModel(Model.E1000);
+      assertEquals(options.getNicModel(), Model.E1000);
+   }
+
+   public void testVncPassword() {
+      CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions.Builder().vncPassword("foo");
+      assertEquals(options.getVncPassword(), "foo");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/functions/ServerInfoToJsonTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/functions/ServerInfoToJsonTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/functions/ServerInfoToJsonTest.java
index 884b05e..20b607e 100644
--- a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/functions/ServerInfoToJsonTest.java
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/functions/ServerInfoToJsonTest.java
@@ -16,12 +16,11 @@
  */
 package org.jclouds.cloudsigma2.functions;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import com.google.inject.Guice;
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Map;
+
 import org.jclouds.cloudsigma2.domain.DeviceEmulationType;
 import org.jclouds.cloudsigma2.domain.Drive;
 import org.jclouds.cloudsigma2.domain.IPConfiguration;
@@ -32,14 +31,16 @@ import org.jclouds.cloudsigma2.domain.Owner;
 import org.jclouds.cloudsigma2.domain.ServerDrive;
 import org.jclouds.cloudsigma2.domain.ServerInfo;
 import org.jclouds.cloudsigma2.domain.ServerStatus;
+import org.jclouds.cloudsigma2.domain.Tag;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import java.math.BigInteger;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Map;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.inject.Guice;
 
 @Test(groups = "unit")
 public class ServerInfoToJsonTest {
@@ -104,7 +105,7 @@ public class ServerInfoToJsonTest {
             .runtime(null)
             .smp(1)
             .status(ServerStatus.STOPPED)
-            .tags(ImmutableList.of("tag_uuid_1", "tag_uuid_2"))
+            .tags(ImmutableList.of(new Tag.Builder().name("tag_uuid_1").build(), new Tag.Builder().name("tag_uuid_2").build()))
             .uuid("a19a425f-9e92-42f6-89fb-6361203071bb")
             .vncPassword("tester")
             .build();
@@ -120,9 +121,16 @@ public class ServerInfoToJsonTest {
       expected.add("requirements", new JsonArray());
 
       JsonArray tagsArray = new JsonArray();
-      tagsArray.add(new JsonPrimitive("tag_uuid_1"));
-      tagsArray.add(new JsonPrimitive("tag_uuid_2"));
+      JsonObject tagObject1 = new JsonObject();
+      tagObject1.add("resources", new JsonArray());
+      tagObject1.addProperty("name", "tag_uuid_1");
+      JsonObject tagObject2 = new JsonObject();
+      tagObject2.add("resources", new JsonArray());
+      tagObject2.addProperty("name", "tag_uuid_2");
+      tagsArray.add(tagObject1);
+      tagsArray.add(tagObject2);
       expected.add("tags", tagsArray);
+
       expected.addProperty("vnc_password", "tester");
 
       JsonObject nicJson = new JsonObject();
@@ -140,7 +148,7 @@ public class ServerInfoToJsonTest {
 
       JsonArray drivesArray = new JsonArray();
       JsonObject driveJson1 = new JsonObject();
-      driveJson1.addProperty("boot_order", 0);
+      driveJson1.addProperty("boot_order", (Number) null);
       driveJson1.addProperty("dev_channel", "0:0");
       driveJson1.addProperty("device", "ide");
       driveJson1.addProperty("drive", "ae78e68c-9daa-4471-8878-0bb87fa80260");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/resources/drive-cloned.json
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/resources/drive-cloned.json b/cloudsigma2/src/test/resources/drive-cloned.json
new file mode 100644
index 0000000..be5b617
--- /dev/null
+++ b/cloudsigma2/src/test/resources/drive-cloned.json
@@ -0,0 +1,57 @@
+{
+    "objects": [
+        {
+            "affinities": [
+                "ssd",
+                "sample"
+            ],
+            "allow_multimount": true,
+            "jobs": [],
+            "licenses": [
+                {
+                    "amount" : 1,
+                    "license" : {
+                        "burstable" : true,
+                        "long_name" : "sample_longname",
+                        "name" : "sample_name",
+                        "resource_uri" : "/api/2.0/samples/",
+                        "type" : "sample_type",
+                        "user_metric" : sample
+                    },
+                    "user" : {
+                        "resource_uri": "/api/2.0/user/5b4a69a3-8e78-4c45-a8ba-8b13f0895e23/",
+                        "uuid": "5b4a69a3-8e78-4c45-a8ba-8b13f0895e23"
+                    }
+                }
+            ],
+            "media": "disk",
+            "meta": {
+                "description": "",
+                "install_notes": ""
+            },
+            "mounted_on": [
+                {
+                    "uuid" : "81f911f9-5152-4328-8671-02543bafbd0e",
+                    "resource_uri" : "/api/2.0/servers/81f911f9-5152-4328-8671-02543bafbd0e/"
+                },
+                {
+                    "uuid" : "19163e1a-a6d6-4e73-8087-157dd302c373",
+                    "resource_uri" : "/api/2.0/servers/19163e1a-a6d6-4e73-8087-157dd302c373/"
+                }
+            ],
+            "name": "atom-sol3",
+            "owner": {
+                "resource_uri": "/api/2.0/user/5b4a69a3-8e78-4c45-a8ba-8b13f0895e23/",
+                "uuid": "5b4a69a3-8e78-4c45-a8ba-8b13f0895e23"
+            },
+            "resource_uri": "/api/2.0/drives/92ca1450-417e-4cc1-983b-1015777e2591/",
+            "size": 12348030976,
+            "status": "unmounted",
+            "tags": [
+                "tag_uuid_1",
+                "tag_uuid_2"
+            ],
+            "uuid": "92ca1450-417e-4cc1-983b-1015777e2591"
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/resources/fwpolicies-get-single.json
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/resources/fwpolicies-get-single.json b/cloudsigma2/src/test/resources/fwpolicies-get-single.json
new file mode 100644
index 0000000..84307fb
--- /dev/null
+++ b/cloudsigma2/src/test/resources/fwpolicies-get-single.json
@@ -0,0 +1,61 @@
+{
+    "meta": {},
+    "name": "My awesome policy",
+    "owner": {
+        "resource_uri": "/api/2.0/user/a2d33327-87d6-4be9-ba7e-0082d89eb21a/",
+        "uuid": "a2d33327-87d6-4be9-ba7e-0082d89eb21a"
+    },
+    "resource_uri": "/api/2.0/fwpolicies/9001b532-857a-405a-8e50-54e342871e77/",
+    "rules": [
+        {
+            "action": "drop",
+            "comment": "Drop traffic from the VM to IP address 23.0.0.0/32",
+            "direction": "out", "dst_ip": "23.0.0.0/32",
+            "dst_port": null,
+            "ip_proto": null,
+            "src_ip": null,
+            "src_port": null},
+        {
+            "action": "accept",
+            "comment": "Allow SSH traffic to the VM from our office in Dubai",
+            "direction": "in", "dst_ip": null,
+            "dst_port": "22",
+            "ip_proto": "tcp",
+            "src_ip": "172.66.32.0/24",
+            "src_port": null
+        },
+        {
+            "action": "drop",
+            "comment": "Drop all other SSH traffic to the VM",
+            "direction": "in",
+            "dst_ip": null,
+            "dst_port": "22",
+            "ip_proto": "tcp",
+            "src_ip": null,
+            "src_port": null
+        },
+        {
+            "action": "drop",
+            "comment": "Drop all UDP traffic to the VM, not originating from 172.66.32.55",
+            "direction": "in",
+            "dst_ip": null,
+            "dst_port": null,
+            "ip_proto": "udp",
+            "src_ip": "!172.66.32.55/32",
+            "src_port": null
+        },
+        {
+            "action": "drop",
+            "comment": "Drop any traffic, to the VM with destination port not between 1-1024",
+            "direction": "in",
+            "dst_ip": null,
+            "dst_port": "!1:1024",
+            "ip_proto": "tcp",
+            "src_ip": null,
+            "src_port": null
+        }
+    ],
+    "servers": [],
+    "tags": [],
+    "uuid": "9001b532-857a-405a-8e50-54e342871e77"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/resources/libdrives-cloned.json
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/resources/libdrives-cloned.json b/cloudsigma2/src/test/resources/libdrives-cloned.json
new file mode 100644
index 0000000..5be4c02
--- /dev/null
+++ b/cloudsigma2/src/test/resources/libdrives-cloned.json
@@ -0,0 +1,34 @@
+{
+    "objects": [
+        {
+            "affinities": [],
+            "allow_multimount": false,
+            "arch": "32",
+            "category": [
+                "general"
+            ],
+            "description": "test_description",
+            "favourite": true,
+            "image_type": "install",
+            "install_notes": "test_install_notes",
+            "jobs": [],
+            "licenses": [],
+            "media": "cdrom",
+            "meta": {},
+            "mounted_on": [],
+            "name": "ZeroShell 1.3 Linux Install CD",
+            "os": "linux",
+            "owner": {
+                "resource_uri": "/api/2.0/user/5b4a69a3-8e78-4c45-a8ba-8b13f0895e23/",
+                "uuid": "5b4a69a3-8e78-4c45-a8ba-8b13f0895e23"
+            },
+            "paid": false,
+            "resource_uri": "/api/2.0/libdrives/8c45d8d9-4efd-44ec-9833-8d52004b4298/",
+            "size": 1000000000,
+            "status": "unmounted",
+            "tags": [],
+            "url": "test_url",
+            "uuid": "8c45d8d9-4efd-44ec-9833-8d52004b4298"
+        }
+    ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/resources/server-detail-first-page.json
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/resources/server-detail-first-page.json b/cloudsigma2/src/test/resources/server-detail-first-page.json
index 275a9a2..7f4b957 100644
--- a/cloudsigma2/src/test/resources/server-detail-first-page.json
+++ b/cloudsigma2/src/test/resources/server-detail-first-page.json
@@ -61,8 +61,8 @@
             "smp": 1,
             "status": "stopped",
             "tags": [
-                "tag_uuid_1",
-                "tag_uuid_2"
+                { "uuid": "tag_uuid_1" },
+                { "uuid": "tag_uuid_2" }
             ],
             "uuid": "a19a425f-9e92-42f6-89fb-6361203071bb",
             "vnc_password": "tester"

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/resources/server-detail.json
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/resources/server-detail.json b/cloudsigma2/src/test/resources/server-detail.json
index 9d8fe62..6070c8b 100644
--- a/cloudsigma2/src/test/resources/server-detail.json
+++ b/cloudsigma2/src/test/resources/server-detail.json
@@ -61,8 +61,8 @@
             "smp": 1,
             "status": "stopped",
             "tags": [
-                "tag_uuid_1",
-                "tag_uuid_2"
+                { "uuid": "tag_uuid_1" },
+                { "uuid": "tag_uuid_2" }
             ],
             "uuid": "a19a425f-9e92-42f6-89fb-6361203071bb",
             "vnc_password": "tester"

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/resources/servers-single.json
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/resources/servers-single.json b/cloudsigma2/src/test/resources/servers-single.json
index cbf35da..8a7dca5 100644
--- a/cloudsigma2/src/test/resources/servers-single.json
+++ b/cloudsigma2/src/test/resources/servers-single.json
@@ -56,8 +56,8 @@
             "smp": 1,
             "status": "stopped",
             "tags": [
-                "tag_uuid_1",
-                "tag_uuid_2"
+                { "uuid": "tag_uuid_1" },
+                { "uuid": "tag_uuid_2" }
             ],
             "uuid": "a19a425f-9e92-42f6-89fb-6361203071bb",
             "vnc_password": "tester"

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6b91b42..1979aac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,7 +70,9 @@
     <module>vcloud-director</module>
     <module>cdmi</module>
     <module>cloudsigma2</module>
+    <module>cloudsigma2-hnl</module>
     <module>cloudsigma2-lvs</module>
+    <module>cloudsigma2-sjc</module>
     <module>cloudsigma2-wdc</module>
     <module>cloudsigma2-zrh</module>
     <module>digitalocean</module>


[2/3] JCLOUDS-292: Added CloudSigma2 ComputeService

Posted by na...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadata.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadata.java
new file mode 100644
index 0000000..2cfc1b0
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerInfoToNodeMetadata.java
@@ -0,0 +1,135 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.domain.ServerDrive;
+import org.jclouds.cloudsigma2.domain.ServerInfo;
+import org.jclouds.cloudsigma2.domain.ServerStatus;
+import org.jclouds.cloudsigma2.domain.Tag;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.location.suppliers.all.JustProvider;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Iterables.transform;
+
+@Singleton
+public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetadata> {
+
+   private final ServerDriveToVolume serverDriveToVolume;
+   private final NICToAddress nicToAddress;
+   private final Map<ServerStatus, NodeMetadata.Status> serverStatusToNodeStatus;
+   private final GroupNamingConvention groupNamingConventionWithPrefix;
+   private final GroupNamingConvention groupNamingConventionWithoutPrefix;
+   private final Map<String, Credentials> credentialStore;
+   private final JustProvider locations;
+   private final CloudSigma2Api api;
+
+   @Inject
+   public ServerInfoToNodeMetadata(ServerDriveToVolume serverDriveToVolume, NICToAddress nicToAddress,
+                                   Map<ServerStatus, NodeMetadata.Status> serverStatusToNodeStatus,
+                                   GroupNamingConvention.Factory groupNamingConvention,
+                                   Map<String, Credentials> credentialStore,
+                                   JustProvider locations, CloudSigma2Api api) {
+      this.serverDriveToVolume = checkNotNull(serverDriveToVolume, "serverDriveToVolume");
+      this.nicToAddress = checkNotNull(nicToAddress, "nicToAddress");
+      this.serverStatusToNodeStatus = checkNotNull(serverStatusToNodeStatus, "serverStatusToNodeStatus");
+      this.groupNamingConventionWithPrefix = checkNotNull(groupNamingConvention, "groupNamingConvention").create();
+      this.groupNamingConventionWithoutPrefix = groupNamingConvention.createWithoutPrefix();
+      this.credentialStore = checkNotNull(credentialStore, "credentialStore");
+      this.locations = checkNotNull(locations, "locations");
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   public NodeMetadata apply(ServerInfo serverInfo) {
+      NodeMetadataBuilder builder = new NodeMetadataBuilder();
+
+      builder.ids(serverInfo.getUuid());
+      builder.name(serverInfo.getName());
+      builder.group(groupNamingConventionWithoutPrefix.extractGroup(serverInfo.getName()));
+      builder.location(getOnlyElement(locations.get()));
+
+      builder.hardware(new HardwareBuilder().ids(serverInfo.getUuid()).processor(new Processor(1, serverInfo.getCpu()))
+            .ram(serverInfo.getMemory().intValue())
+            .volumes(Iterables.transform(serverInfo.getDrives(), serverDriveToVolume)).build());
+
+      builder.tags(readTags(serverInfo));
+      builder.userMetadata(serverInfo.getMeta());
+      builder.imageId(extractImageId(serverInfo));
+      builder.status(serverStatusToNodeStatus.get(serverInfo.getStatus()));
+      builder.publicAddresses(filter(transform(serverInfo.getNics(), nicToAddress), notNull()));
+
+      // CloudSigma does not provide a way to get the credentials.
+      // Try to return them from the credential store
+      Credentials credentials = credentialStore.get("node#" + serverInfo.getUuid());
+      if (credentials instanceof LoginCredentials) {
+         builder.credentials(LoginCredentials.class.cast(credentials));
+      }
+
+      return builder.build();
+   }
+
+   private static String extractImageId(ServerInfo serverInfo) {
+      String imageId = serverInfo.getMeta().get("image_id");
+
+      if (imageId == null) {
+         ServerDrive serverBootDrive = null;
+         for (ServerDrive serverDrive : serverInfo.getDrives()) {
+            if (serverDrive.getBootOrder() != null
+                  && (serverBootDrive == null || serverDrive.getBootOrder() < serverBootDrive.getBootOrder())) {
+               serverBootDrive = serverDrive;
+            }
+         }
+         if (serverBootDrive != null) {
+            imageId = serverBootDrive.getDriveUuid();
+         }
+      }
+
+      return imageId;
+   }
+
+   private Iterable<String> readTags(ServerInfo serverInfo) {
+      return transform(serverInfo.getTags(), new Function<Tag, String>() {
+         @Override
+         public String apply(Tag input) {
+            Tag tag = api.getTagInfo(input.getUuid());
+            if (tag.getName() == null) {
+               return input.getUuid();
+            }
+            String tagWithoutPrefix = groupNamingConventionWithPrefix.groupInSharedNameOrNull(tag.getName());
+            return tagWithoutPrefix != null ? tagWithoutPrefix : tag.getName();
+         }
+      });
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
new file mode 100644
index 0000000..077917b
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/TemplateOptionsToStatementWithoutPublicKey.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.compute.functions.TemplateOptionsToStatement;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.scriptbuilder.InitScript;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
+
+import javax.inject.Singleton;
+
+/**
+ * Convert the template options into a statement, but ignoring the public key.
+ * <p/>
+ * The {@link org.jclouds.cloudsigma2.compute.strategy.CloudSigma2ComputeServiceAdapter} already takes care of
+ * installing it using the server metadata.
+ */
+@Singleton
+public class TemplateOptionsToStatementWithoutPublicKey extends TemplateOptionsToStatement {
+
+   @Override
+   public Statement apply(TemplateOptions options) {
+      ImmutableList.Builder<Statement> builder = ImmutableList.builder();
+      if (options.getRunScript() != null) {
+         builder.add(options.getRunScript());
+      }
+      if (options.getPrivateKey() != null) {
+         builder.add(new InstallRSAPrivateKey(options.getPrivateKey()));
+      }
+
+      ImmutableList<Statement> bootstrap = builder.build();
+      if (bootstrap.isEmpty()) {
+         return null;
+      }
+
+      if (options.getTaskName() == null && !(options.getRunScript() instanceof InitScript)) {
+         options.nameTask("bootstrap");
+      }
+      return bootstrap.size() == 1 ? bootstrap.get(0) : new StatementList(bootstrap);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptions.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptions.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptions.java
new file mode 100644
index 0000000..db43a7d
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/options/CloudSigma2TemplateOptions.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.cloudsigma2.compute.options;
+
+import com.google.common.base.Objects.ToStringHelper;
+import org.jclouds.cloudsigma2.domain.DeviceEmulationType;
+import org.jclouds.cloudsigma2.domain.Model;
+import org.jclouds.compute.options.TemplateOptions;
+
+public class CloudSigma2TemplateOptions extends TemplateOptions {
+
+   private DeviceEmulationType deviceEmulationType = DeviceEmulationType.VIRTIO;
+   private Model nicModel = Model.VIRTIO;
+   private String vncPassword;
+
+   /**
+    * Configures the device emulation type.
+    */
+   public CloudSigma2TemplateOptions deviceEmulationType(DeviceEmulationType deviceEmulationType) {
+      this.deviceEmulationType = deviceEmulationType;
+      return this;
+   }
+
+   /**
+    * Configures the type of NICs to create.
+    */
+   public CloudSigma2TemplateOptions nicModel(Model nicModel) {
+      this.nicModel = nicModel;
+      return this;
+   }
+
+   /**
+    * Configures the vnc password.
+    */
+   public CloudSigma2TemplateOptions vncPassword(String vncPassword) {
+      this.vncPassword = vncPassword;
+      return this;
+   }
+
+   public DeviceEmulationType getDeviceEmulationType() {
+      return deviceEmulationType;
+   }
+
+   public Model getNicModel() {
+      return nicModel;
+   }
+
+   public String getVncPassword() {
+      return vncPassword;
+   }
+
+   @Override
+   public TemplateOptions clone() {
+      CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions();
+      copyTo(options);
+      return options;
+   }
+
+   @Override
+   public void copyTo(TemplateOptions to) {
+      super.copyTo(to);
+      if (to instanceof CloudSigma2TemplateOptions) {
+         CloudSigma2TemplateOptions eTo = CloudSigma2TemplateOptions.class.cast(to);
+         eTo.deviceEmulationType(deviceEmulationType);
+         eTo.nicModel(nicModel);
+         eTo.vncPassword(vncPassword);
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      final int prime = 31;
+      int result = super.hashCode();
+      result = prime * result + ((deviceEmulationType == null) ? 0 : deviceEmulationType.hashCode());
+      result = prime * result + ((nicModel == null) ? 0 : nicModel.hashCode());
+      result = prime * result + ((vncPassword == null) ? 0 : vncPassword.hashCode());
+      return result;
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (!super.equals(obj))
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      CloudSigma2TemplateOptions other = (CloudSigma2TemplateOptions) obj;
+      if (deviceEmulationType != other.deviceEmulationType)
+         return false;
+      if (nicModel != other.nicModel)
+         return false;
+      if (vncPassword == null) {
+         if (other.vncPassword != null)
+            return false;
+      } else if (!vncPassword.equals(other.vncPassword))
+         return false;
+      return true;
+   }
+
+   @Override
+   public ToStringHelper string() {
+      ToStringHelper toString = super.string().omitNullValues();
+      toString.add("deviceEmulationType", deviceEmulationType);
+      toString.add("nicModel", nicModel);
+      toString.add("vncPassword", vncPassword);
+      return toString;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see CloudSigma2TemplateOptions#deviceEmulationType(DeviceEmulationType)
+       */
+      public CloudSigma2TemplateOptions deviceEmulationType(DeviceEmulationType deviceEmulationType) {
+         CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions();
+         options.deviceEmulationType(deviceEmulationType);
+         return options;
+      }
+
+      /**
+       * @see CloudSigma2TemplateOptions#nicModel(Model)
+       */
+      public CloudSigma2TemplateOptions nicModel(Model nicModel) {
+         CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions();
+         options.nicModel(nicModel);
+         return options;
+      }
+
+      /**
+       * @see CloudSigma2TemplateOptions#vncPassword(String)
+       */
+      public CloudSigma2TemplateOptions vncPassword(String vncPassword) {
+         CloudSigma2TemplateOptions options = new CloudSigma2TemplateOptions();
+         options.vncPassword(vncPassword);
+         return options;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/strategy/CloudSigma2ComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/strategy/CloudSigma2ComputeServiceAdapter.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/strategy/CloudSigma2ComputeServiceAdapter.java
new file mode 100644
index 0000000..69decb2
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/strategy/CloudSigma2ComputeServiceAdapter.java
@@ -0,0 +1,407 @@
+/*
+ * 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.cloudsigma2.compute.strategy;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+
+import org.jclouds.Constants;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.compute.options.CloudSigma2TemplateOptions;
+import org.jclouds.cloudsigma2.domain.DriveInfo;
+import org.jclouds.cloudsigma2.domain.DriveStatus;
+import org.jclouds.cloudsigma2.domain.FirewallAction;
+import org.jclouds.cloudsigma2.domain.FirewallDirection;
+import org.jclouds.cloudsigma2.domain.FirewallIpProtocol;
+import org.jclouds.cloudsigma2.domain.FirewallPolicy;
+import org.jclouds.cloudsigma2.domain.FirewallRule;
+import org.jclouds.cloudsigma2.domain.IPConfiguration;
+import org.jclouds.cloudsigma2.domain.IPConfigurationType;
+import org.jclouds.cloudsigma2.domain.LibraryDrive;
+import org.jclouds.cloudsigma2.domain.MediaType;
+import org.jclouds.cloudsigma2.domain.NIC;
+import org.jclouds.cloudsigma2.domain.ServerDrive;
+import org.jclouds.cloudsigma2.domain.ServerInfo;
+import org.jclouds.cloudsigma2.domain.ServerStatus;
+import org.jclouds.cloudsigma2.domain.Tag;
+import org.jclouds.cloudsigma2.domain.VLANInfo;
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.internal.VolumeImpl;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Lists.transform;
+import static com.google.common.util.concurrent.Futures.allAsList;
+import static com.google.common.util.concurrent.Futures.getUnchecked;
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.PROPERTY_DELETE_DRIVES;
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.PROPERTY_VNC_PASSWORD;
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.TIMEOUT_DRIVE_CLONED;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
+
+@Singleton
+public class CloudSigma2ComputeServiceAdapter implements
+      ComputeServiceAdapter<ServerInfo, Hardware, LibraryDrive, Location> {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final CloudSigma2Api api;
+   private final ListeningExecutorService userExecutor;
+   private final String defaultVncPassword;
+   private final Predicate<DriveInfo> driveCloned;
+   private final Predicate<String> serverStopped;
+   private final boolean destroyDrives;
+   private final GroupNamingConvention groupNamingConvention;
+
+   @Inject
+   public CloudSigma2ComputeServiceAdapter(CloudSigma2Api api,
+                                           @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService
+                                                 userExecutor,
+                                           @Named(PROPERTY_VNC_PASSWORD) String defaultVncPassword,
+                                           @Named(TIMEOUT_DRIVE_CLONED) Predicate<DriveInfo> driveCloned,
+                                           @Named(TIMEOUT_NODE_SUSPENDED) Predicate<String> serverStopped,
+                                           @Named(PROPERTY_DELETE_DRIVES) boolean destroyDrives,
+                                           GroupNamingConvention.Factory groupNamingConvention) {
+      this.api = checkNotNull(api, "api");
+      this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+      this.defaultVncPassword = checkNotNull(defaultVncPassword, "defaultVncPassword");
+      this.driveCloned = checkNotNull(driveCloned, "driveCloned");
+      this.serverStopped = checkNotNull(serverStopped, "serverStopped");
+      this.destroyDrives = destroyDrives;
+      this.groupNamingConvention = checkNotNull(groupNamingConvention, "groupNamingConvention").create();
+   }
+
+   @Override
+   public NodeAndInitialCredentials<ServerInfo> createNodeWithGroupEncodedIntoName(String group, String name,
+                                                                                   Template template) {
+      CloudSigma2TemplateOptions options = template.getOptions().as(CloudSigma2TemplateOptions.class);
+      Image image = template.getImage();
+      Hardware hardware = template.getHardware();
+
+      DriveInfo drive = api.getLibraryDrive(image.getProviderId());
+
+      if (!drive.getMedia().equals(MediaType.CDROM)) {
+         logger.debug(">> cloning library drive %s...", image.getProviderId());
+
+         drive = api.cloneLibraryDrive(image.getProviderId(), null);
+         driveCloned.apply(drive);
+
+         // Refresh the drive object and verify the clone operation didn't time out
+         drive = api.getDriveInfo(drive.getUuid());
+         DriveStatus status = drive.getStatus();
+
+         if (DriveStatus.UNMOUNTED != status) {
+            if (destroyDrives) {
+               // Rollback the cloned drive, if needed
+               logger.error(">> clone operation failed. Rolling back drive (%s)...", drive);
+               destroyDrives(ImmutableList.of(drive.getUuid()));
+            }
+            throw new IllegalStateException("Resource is in invalid status: " + status);
+         }
+
+         logger.debug(">> drive cloned (%s)...", drive);
+      }
+
+      ImmutableList.Builder<FirewallRule> firewallRulesBuilder = ImmutableList.builder();
+      for (int port : options.getInboundPorts()) {
+         firewallRulesBuilder.add(new FirewallRule.Builder().action(FirewallAction.ACCEPT)
+               .ipProtocol(FirewallIpProtocol.TCP).direction(FirewallDirection.IN).destinationPort("" + port).build());
+      }
+
+      List<NIC> nics = null;
+      try {
+         logger.debug(">> creating firewall policies...");
+         FirewallPolicy firewallPolicy = api.createFirewallPolicy(new FirewallPolicy.Builder().rules(
+               firewallRulesBuilder.build()).build());
+         nics = configureNICs(options, firewallPolicy);
+      } catch (Exception ex) {
+         if (destroyDrives) {
+            logger.debug(">> rolling back the cloned drive...", drive.getUuid());
+            destroyDrives(ImmutableList.of(drive.getUuid()));
+         }
+         throw propagate(ex);
+      }
+
+      List<Tag> tagIds = configureTags(options);
+
+      // Cloud init images expect the public key in the server metadata
+      Map<String, String> metadata = Maps.newLinkedHashMap();
+      metadata.put("image_id", image.getProviderId());
+      if (!Strings.isNullOrEmpty(options.getPublicKey())) {
+         metadata.put("ssh_public_key", options.getPublicKey());
+      }
+      metadata.putAll(options.getUserMetadata());
+
+      ServerInfo serverInfo = null;
+      try {
+         logger.debug(">> creating server...");
+
+         serverInfo = api.createServer(new ServerInfo.Builder()
+               .name(name)
+               .cpu((int) hardware.getProcessors().get(0).getSpeed())
+               .memory(BigInteger.valueOf(hardware.getRam()).multiply(BigInteger.valueOf(1024 * 1024)))
+               .drives(ImmutableList.of(drive.toServerDrive(1, "0:1", options.getDeviceEmulationType())))
+               .nics(nics)
+               .meta(metadata)
+               .tags(tagIds)
+               .vncPassword(Optional.fromNullable(options.getVncPassword()).or(defaultVncPassword)).build());
+
+         api.startServer(serverInfo.getUuid());
+
+         return new NodeAndInitialCredentials<ServerInfo>(serverInfo, serverInfo.getUuid(), LoginCredentials.builder()
+               .build());
+      } catch (Exception ex) {
+         try {
+            if (serverInfo != null) {
+               logger.debug(">> rolling back the server...");
+               api.deleteServer(serverInfo.getUuid());
+            }
+         } finally {
+            try {
+               if (destroyDrives) {
+                  logger.debug(">> rolling back the cloned drive...");
+                  destroyDrives(ImmutableList.of(drive.getUuid()));
+               }
+            } finally {
+               deleteTags(tagIds);
+            }
+         }
+         throw propagate(ex);
+      }
+   }
+
+   @Override
+   public Iterable<Hardware> listHardwareProfiles() {
+      // Return a hardcoded list of hardware profiles until
+      // https://issues.apache.org/jira/browse/JCLOUDS-482 is fixed
+      Builder<Hardware> hardware = ImmutableSet.builder();
+      Builder<Integer> ramSetBuilder = ImmutableSet.builder();
+      Builder<Double> cpuSetBuilder = ImmutableSet.builder();
+      for (int i = 1; i < 65; i++) {
+         ramSetBuilder.add(i * 1024);
+      }
+      for (int i = 1; i < 41; i++) {
+         cpuSetBuilder.add((double) i * 1000);
+      }
+      for (int ram : ramSetBuilder.build()) {
+         for (double cpu : cpuSetBuilder.build()) {
+            hardware.add(new HardwareBuilder().ids(String.format("cpu=%f,ram=%d", cpu, ram))
+                  .processor(new Processor(1, cpu)).ram(ram)
+                  .volumes(ImmutableList.<Volume>of(new VolumeImpl(null, true, false))).build());
+         }
+      }
+      return hardware.build();
+   }
+
+   @Override
+   public Iterable<LibraryDrive> listImages() {
+      return api.listLibraryDrives().concat();
+   }
+
+   @Override
+   public LibraryDrive getImage(String uuid) {
+      return api.getLibraryDrive(uuid);
+   }
+
+   @Override
+   public Iterable<Location> listLocations() {
+      // Nothing to return here. Each provider will configure the locations
+      return ImmutableSet.<Location>of();
+   }
+
+   @Override
+   public ServerInfo getNode(String uuid) {
+      return api.getServerInfo(uuid);
+   }
+
+   @Override
+   public void destroyNode(String uuid) {
+      ServerInfo server = api.getServerInfo(uuid);
+
+      if (ServerStatus.RUNNING == server.getStatus()) {
+         api.stopServer(uuid);
+         waitUntilServerIsStopped(uuid);
+      }
+
+      deleteTags(server.getTags());
+
+      List<String> driveIds = transform(server.getDrives(), new Function<ServerDrive, String>() {
+         @Override
+         public String apply(ServerDrive input) {
+            return input.getDriveUuid();
+         }
+      });
+
+      logger.debug(">> deleting server...");
+      api.deleteServer(uuid);
+
+      if (destroyDrives) {
+         logger.debug(">> deleting server drives...");
+         destroyDrives(driveIds);
+      }
+   }
+
+   @Override
+   public void rebootNode(String uuid) {
+      api.stopServer(uuid);
+      waitUntilServerIsStopped(uuid);
+      api.startServer(uuid);
+   }
+
+   @Override
+   public void resumeNode(String uuid) {
+      api.startServer(uuid);
+   }
+
+   @Override
+   public void suspendNode(String uuid) {
+      api.stopServer(uuid);
+   }
+
+   @Override
+   public Iterable<ServerInfo> listNodes() {
+      return api.listServersInfo().concat();
+   }
+
+   @Override
+   public Iterable<ServerInfo> listNodesByIds(final Iterable<String> uuids) {
+      // Only fetch the requested nodes. Do it in parallel.
+      ListenableFuture<List<ServerInfo>> futures = allAsList(transform(uuids,
+            new Function<String, ListenableFuture<ServerInfo>>() {
+               @Override
+               public ListenableFuture<ServerInfo> apply(final String input) {
+                  return userExecutor.submit(new Callable<ServerInfo>() {
+                     @Override
+                     public ServerInfo call() throws Exception {
+                        return api.getServerInfo(input);
+                     }
+                  });
+               }
+            }));
+
+      return getUnchecked(futures);
+   }
+
+   private void waitUntilServerIsStopped(String uuid) {
+      serverStopped.apply(uuid);
+      ServerInfo server = api.getServerInfo(uuid);
+      checkState(server.getStatus() == ServerStatus.STOPPED, "Resource is in invalid status: %s", server.getStatus());
+   }
+
+   private List<NIC> configureNICs(CloudSigma2TemplateOptions options, FirewallPolicy firewallPolicy) {
+      ImmutableList.Builder<NIC> nics = ImmutableList.builder();
+      for (String network : options.getNetworks()) {
+         VLANInfo vlan = api.getVLANInfo(network);
+         checkArgument(vlan != null, "network %s not found", network);
+         nics.add(new NIC.Builder().vlan(vlan).firewallPolicy(firewallPolicy).model(options.getNicModel()).build());
+      }
+
+      // If no network has been specified, assign an IP from the DHCP
+      if (options.getNetworks().isEmpty()) {
+         logger.debug(">> no networks configured. Will assign an IP from the DHCP...");
+         NIC nic = new NIC.Builder().firewallPolicy(firewallPolicy).model(options.getNicModel())
+               .ipV4Configuration(new IPConfiguration.Builder().configurationType(IPConfigurationType.DHCP).build())
+               .build();
+         nics.add(nic);
+      }
+
+      return nics.build();
+   }
+
+   private List<Tag> configureTags(CloudSigma2TemplateOptions options) {
+      ImmutableList.Builder<Tag> builder = ImmutableList.builder();
+      for (String tagName : options.getTags()) {
+         String nameWithPrefix = groupNamingConvention.sharedNameForGroup(tagName);
+         builder.add(new Tag.Builder().name(nameWithPrefix).build());
+      }
+
+      List<Tag> tags = builder.build();
+      builder = ImmutableList.builder();
+
+      if (!tags.isEmpty()) {
+         logger.debug(">> creating tags...");
+         builder.addAll(api.createTags(tags));
+      }
+
+      return builder.build();
+   }
+
+   private void deleteTags(List<Tag> tags) {
+      logger.debug(">> deleting server tags...");
+      Iterable<Tag> customTags = filter(tags, new Predicate<Tag>() {
+         @Override
+         public boolean apply(Tag input) {
+            // Only delete the tags jclouds has set
+            Tag tag = api.getTagInfo(input.getUuid());
+            return groupNamingConvention.groupInSharedNameOrNull(tag.getName()) != null;
+         }
+      });
+
+      for (Tag tag : customTags) {
+         try {
+            // Try to delete the tags but don't fail if the can't be deleted
+            api.deleteTag(tag.getUuid());
+         } catch (Exception ex) {
+            logger.warn(ex, ">> could not delete tag: %s", tag);
+         }
+      }
+   }
+
+   private void destroyDrives(List<String> driveIds) {
+      try {
+         // Try to delete the drives but don't fail if the can't be deleted, as the server has been already removed.
+         api.deleteDrives(driveIds);
+      } catch (Exception ex) {
+         logger.warn(ex, ">> could not delete drives: [%s]", Joiner.on(',').join(driveIds));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/config/CloudSigma2Properties.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/config/CloudSigma2Properties.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/config/CloudSigma2Properties.java
index 66a35a7..b83ae0d 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/config/CloudSigma2Properties.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/config/CloudSigma2Properties.java
@@ -19,8 +19,19 @@ package org.jclouds.cloudsigma2.config;
 public class CloudSigma2Properties {
 
    /**
-    * default VNC password used on new machines
+    * Default VNC password used on new machines
     */
    public static final String PROPERTY_VNC_PASSWORD = "jclouds.cloudsigma.vnc-password";
-
+   
+   /**
+    * Time in milliseconds to wait for a drive to be cloned
+    * Default: 60000 
+    */
+   public static final String TIMEOUT_DRIVE_CLONED = "jclouds.cloudsigma.timeout.drive-cloned";
+   
+   /**
+    * Controls if the drives of a server should be destroyed when deleting the server
+    * Default: true 
+    */
+   public static final String PROPERTY_DELETE_DRIVES = "jclouds.cloudsigma.delete-drives";
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/Drive.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/Drive.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/Drive.java
index ec2ff76..14570d4 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/Drive.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/Drive.java
@@ -166,7 +166,7 @@ public class Drive extends Item {
     * @param deviceChannel       device channel in format {controller:unit} ex. 0:1, 0:2, etc.
     * @param deviceEmulationType device emulation type
     */
-   public ServerDrive toServerDrive(int bootOrder, String deviceChannel, DeviceEmulationType deviceEmulationType) {
+   public ServerDrive toServerDrive(Integer bootOrder, String deviceChannel, DeviceEmulationType deviceEmulationType) {
       return new ServerDrive(bootOrder, deviceChannel, deviceEmulationType, this.uuid);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/DrivesListRequestFieldsGroup.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/DrivesListRequestFieldsGroup.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/DrivesListRequestFieldsGroup.java
index 9100050..56aad17 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/DrivesListRequestFieldsGroup.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/DrivesListRequestFieldsGroup.java
@@ -16,7 +16,7 @@
  */
 package org.jclouds.cloudsigma2.domain;
 
-import com.google.common.base.Joiner;
+import java.util.Iterator;
 
 public class DrivesListRequestFieldsGroup {
    private final Iterable<String> fields;
@@ -31,6 +31,18 @@ public class DrivesListRequestFieldsGroup {
 
    @Override
    public String toString() {
-      return Joiner.on(',').join(fields);
+      String returnString = "";
+
+      Iterator<?> iterator = fields.iterator();
+
+      while (iterator.hasNext()) {
+         returnString += iterator.next();
+
+         if (iterator.hasNext()) {
+            returnString += ",";
+         }
+      }
+
+      return returnString;
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/FirewallPolicy.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/FirewallPolicy.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/FirewallPolicy.java
index 50cf8ea..05ba638 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/FirewallPolicy.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/FirewallPolicy.java
@@ -30,6 +30,7 @@ public class FirewallPolicy extends Item {
       private Map<String, String> meta;
       private Owner owner;
       private List<FirewallRule> rules;
+      private List<Tag> tags;
       private List<Server> servers;
 
       /**
@@ -69,6 +70,15 @@ public class FirewallPolicy extends Item {
       }
 
       /**
+       * @param tags Many related resources. Can be either a list of URIs or list of individually nested resource data.
+       * @return
+       */
+      public Builder tags(List<Tag> tags) {
+         this.tags = ImmutableList.copyOf(tags);
+         return this;
+      }
+
+      /**
        * @param resourceUri Resource URI
        * @return
        */
@@ -98,25 +108,37 @@ public class FirewallPolicy extends Item {
          return this;
       }
 
+      public static Builder fromFirewallPolicy(FirewallPolicy firewallPolicy) {
+         return new Builder()
+               .resourceUri(firewallPolicy.getResourceUri())
+               .uuid(firewallPolicy.getUuid())
+               .rules(firewallPolicy.getRules())
+               .name(firewallPolicy.getName())
+               .meta(firewallPolicy.getMeta())
+               .tags(firewallPolicy.getTags());
+      }
+
       public FirewallPolicy build() {
-         return new FirewallPolicy(meta, name, owner, resourceUri, rules, servers, uuid);
+         return new FirewallPolicy(meta, name, owner, resourceUri, rules, servers, tags, uuid);
       }
    }
 
    private final Map<String, String> meta;
    private final Owner owner;
    private final List<FirewallRule> rules;
+   private final List<Tag> tags;
    private final List<Server> servers;
 
    @ConstructorProperties({
-         "meta", "name", "owner", "resource_uri", "rules", "servers", "uuid"
+         "meta", "name", "owner", "resource_uri", "rules", "servers", "tags", "uuid"
    })
    public FirewallPolicy(Map<String, String> meta, String name, Owner owner, URI resourceUri, List<FirewallRule> rules,
-                         List<Server> servers, String uuid) {
+                         List<Server> servers, List<Tag> tags, String uuid) {
       super(uuid, name, resourceUri);
       this.meta = meta;
       this.owner = owner;
       this.rules = rules == null ? new ArrayList<FirewallRule>() : rules;
+      this.tags = tags == null ? new ArrayList<Tag>() : tags;
       this.servers = servers == null ? new ArrayList<Server>() : servers;
    }
 
@@ -163,6 +185,13 @@ public class FirewallPolicy extends Item {
    }
 
    /**
+    * @return Related resources URI list.
+    */
+   public List<Tag> getTags() {
+      return tags;
+   }
+
+   /**
     * @return UUID of the policy
     */
    public String getUuid() {
@@ -172,7 +201,7 @@ public class FirewallPolicy extends Item {
    @Override
    public boolean equals(Object o) {
       if (this == o) return true;
-      if (!(o instanceof FirewallPolicy)) return false;
+      if (o == null || getClass() != o.getClass()) return false;
       if (!super.equals(o)) return false;
 
       FirewallPolicy that = (FirewallPolicy) o;
@@ -181,6 +210,7 @@ public class FirewallPolicy extends Item {
       if (owner != null ? !owner.equals(that.owner) : that.owner != null) return false;
       if (rules != null ? !rules.equals(that.rules) : that.rules != null) return false;
       if (servers != null ? !servers.equals(that.servers) : that.servers != null) return false;
+      if (tags != null ? !tags.equals(that.tags) : that.tags != null) return false;
 
       return true;
    }
@@ -191,6 +221,7 @@ public class FirewallPolicy extends Item {
       result = 31 * result + (meta != null ? meta.hashCode() : 0);
       result = 31 * result + (owner != null ? owner.hashCode() : 0);
       result = 31 * result + (rules != null ? rules.hashCode() : 0);
+      result = 31 * result + (tags != null ? tags.hashCode() : 0);
       result = 31 * result + (servers != null ? servers.hashCode() : 0);
       return result;
    }
@@ -199,12 +230,10 @@ public class FirewallPolicy extends Item {
    public String toString() {
       return "[" +
             "meta=" + meta +
-            ", name='" + name + '\'' +
             ", owner=" + owner +
-            ", resourceUri='" + resourceUri + '\'' +
             ", rules=" + rules +
+            ", tags=" + tags +
             ", servers=" + servers +
-            ", uuid='" + uuid + '\'' +
             "]";
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/LibraryDrive.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/LibraryDrive.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/LibraryDrive.java
index d479867..d7a0ca5 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/LibraryDrive.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/LibraryDrive.java
@@ -38,6 +38,7 @@ public class LibraryDrive extends DriveInfo {
       private String os;
       private boolean isPaid;
       private String url;
+      private String version;
 
       public Builder arch(String arch) {
          this.arch = arch;
@@ -84,6 +85,11 @@ public class LibraryDrive extends DriveInfo {
          return this;
       }
 
+      public Builder version(String version) {
+         this.version = version;
+         return this;
+      }
+
       /**
        * {@inheritDoc}
        */
@@ -226,7 +232,7 @@ public class LibraryDrive extends DriveInfo {
       public LibraryDrive build() {
          return new LibraryDrive(uuid, name, resourceUri, size, owner, status, allowMultimount, affinities, jobs,
                licenses, media, meta, mountedOn, tags, arch, category, description, isFavorite, imageType, installNotes,
-               os, isPaid, url);
+               os, isPaid, url, version);
       }
    }
 
@@ -243,18 +249,20 @@ public class LibraryDrive extends DriveInfo {
    @Named("paid")
    private final boolean isPaid;
    private final String url;
+   private final String version;
 
    @ConstructorProperties({
          "uuid", "name", "resource_uri", "size", "owner", "status",
          "allow_multimount", "affinities", "jobs", "licenses",
          "media", "meta", "mounted_on", "tags", "arch", "category",
-         "description", "favourite", "image_type", "install_notes", "os", "paid", "url"
+         "description", "favourite", "image_type", "install_notes",
+         "os", "paid", "url", "version"
    })
    public LibraryDrive(String uuid, String name, URI resourceUri, BigInteger size, Owner owner, DriveStatus status,
                        boolean allowMultimount, List<String> affinities, List<Job> jobs, List<DriveLicense> licenses,
                        MediaType media, Map<String, String> meta, List<Server> mountedOn, List<String> tags,
                        String arch, List<String> category, String description, boolean favorite, String imageType,
-                       String installNotes, String os, boolean paid, String url) {
+                       String installNotes, String os, boolean paid, String url, String version) {
       super(uuid, name, resourceUri, size, owner, status, allowMultimount, affinities, jobs, licenses, media, meta,
             mountedOn, tags);
       this.arch = arch;
@@ -266,6 +274,7 @@ public class LibraryDrive extends DriveInfo {
       this.os = os;
       this.isPaid = paid;
       this.url = url;
+      this.version = version;
    }
 
    /**
@@ -331,10 +340,17 @@ public class LibraryDrive extends DriveInfo {
       return url;
    }
 
+   /**
+    * @return Operating system version.
+    */
+   public String getVersion() {
+      return version;
+   }
+
    @Override
    public boolean equals(Object o) {
       if (this == o) return true;
-      if (!(o instanceof LibraryDrive)) return false;
+      if (o == null || getClass() != o.getClass()) return false;
       if (!super.equals(o)) return false;
 
       LibraryDrive that = (LibraryDrive) o;
@@ -348,6 +364,7 @@ public class LibraryDrive extends DriveInfo {
       if (installNotes != null ? !installNotes.equals(that.installNotes) : that.installNotes != null) return false;
       if (os != null ? !os.equals(that.os) : that.os != null) return false;
       if (url != null ? !url.equals(that.url) : that.url != null) return false;
+      if (version != null ? !version.equals(that.version) : that.version != null) return false;
 
       return true;
    }
@@ -364,15 +381,14 @@ public class LibraryDrive extends DriveInfo {
       result = 31 * result + (os != null ? os.hashCode() : 0);
       result = 31 * result + (isPaid ? 1 : 0);
       result = 31 * result + (url != null ? url.hashCode() : 0);
+      result = 31 * result + (version != null ? version.hashCode() : 0);
       return result;
    }
 
    @Override
    public String toString() {
-      return "[uuid=" + uuid + ", name=" + name + ", size=" + size + ", owner=" + owner + ", status=" + status
-            + ", affinities=" + affinities + ", jobs=" + jobs + ", licenses=" + licenses + ", media=" + media
-            + ", meta=" + meta + ", mountedOn=" + mountedOn + ", tags=" + tags +
-            ", arch='" + arch + '\'' +
+      return "LibraryDrive{" +
+            "arch='" + arch + '\'' +
             ", category=" + category +
             ", description='" + description + '\'' +
             ", isFavorite=" + isFavorite +
@@ -381,6 +397,7 @@ public class LibraryDrive extends DriveInfo {
             ", os='" + os + '\'' +
             ", isPaid=" + isPaid +
             ", url='" + url + '\'' +
-            "]";
+            ", version='" + version + '\'' +
+            '}';
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerAvailabilityGroup.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerAvailabilityGroup.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerAvailabilityGroup.java
index 4104f15..855e782 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerAvailabilityGroup.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerAvailabilityGroup.java
@@ -16,10 +16,9 @@
  */
 package org.jclouds.cloudsigma2.domain;
 
+import java.util.Iterator;
 import java.util.List;
 
-import com.google.common.base.Joiner;
-
 public class ServerAvailabilityGroup {
 
    private final List<String> uuids;
@@ -51,6 +50,18 @@ public class ServerAvailabilityGroup {
 
    @Override
    public String toString() {
-      return Joiner.on(',').join(uuids);
+      String returnString = "";
+
+      Iterator<?> iterator = uuids.iterator();
+
+      while (iterator.hasNext()) {
+         returnString += iterator.next();
+
+         if (iterator.hasNext()) {
+            returnString += ",";
+         }
+      }
+
+      return returnString;
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerDrive.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerDrive.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerDrive.java
index 7f69e35..cff05c1 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerDrive.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerDrive.java
@@ -22,12 +22,12 @@ import java.beans.ConstructorProperties;
 public class ServerDrive {
 
    public static class Builder {
-      private int bootOrder;
+      private Integer bootOrder;
       private String deviceChannel;
       private DeviceEmulationType deviceEmulationType;
       private Drive drive;
 
-      public Builder bootOrder(int bootOrder) {
+      public Builder bootOrder(Integer bootOrder) {
          this.bootOrder = bootOrder;
          return this;
       }
@@ -53,7 +53,7 @@ public class ServerDrive {
    }
 
    @Named("boot_order")
-   private final int bootOrder;
+   private final Integer bootOrder;
    @Named("dev_channel")
    private final String deviceChannel;
    @Named("device")
@@ -71,7 +71,7 @@ public class ServerDrive {
    @ConstructorProperties({
          "boot_order", "dev_channel", "device", "drive"
    })
-   public ServerDrive(int bootOrder, String deviceChannel, DeviceEmulationType deviceEmulationType, Drive drive) {
+   public ServerDrive(Integer bootOrder, String deviceChannel, DeviceEmulationType deviceEmulationType, Drive drive) {
       this.bootOrder = bootOrder;
       this.deviceChannel = deviceChannel;
       this.deviceEmulationType = deviceEmulationType;
@@ -96,7 +96,7 @@ public class ServerDrive {
    /**
     * @return drive boot order
     */
-   public int getBootOrder() {
+   public Integer getBootOrder() {
       return bootOrder;
    }
 
@@ -131,31 +131,37 @@ public class ServerDrive {
    @Override
    public boolean equals(Object o) {
       if (this == o) return true;
-      if (!(o instanceof ServerDrive)) return false;
+      if (o == null || getClass() != o.getClass()) return false;
 
       ServerDrive that = (ServerDrive) o;
 
-      if (bootOrder != that.bootOrder) return false;
-      if (deviceChannel != null ? !deviceChannel.equals(that.deviceChannel) : that.deviceChannel != null)
-         return false;
+      if (bootOrder != null ? !bootOrder.equals(that.bootOrder) : that.bootOrder != null) return false;
+      if (deviceChannel != null ? !deviceChannel.equals(that.deviceChannel) : that.deviceChannel != null) return false;
       if (deviceEmulationType != that.deviceEmulationType) return false;
       if (drive != null ? !drive.equals(that.drive) : that.drive != null) return false;
+      if (driveUuid != null ? !driveUuid.equals(that.driveUuid) : that.driveUuid != null) return false;
 
       return true;
    }
 
    @Override
    public int hashCode() {
-      int result = bootOrder;
+      int result = bootOrder != null ? bootOrder.hashCode() : 0;
       result = 31 * result + (deviceChannel != null ? deviceChannel.hashCode() : 0);
       result = 31 * result + (deviceEmulationType != null ? deviceEmulationType.hashCode() : 0);
       result = 31 * result + (drive != null ? drive.hashCode() : 0);
+      result = 31 * result + (driveUuid != null ? driveUuid.hashCode() : 0);
       return result;
    }
 
    @Override
    public String toString() {
-      return "[bootOrder=" + bootOrder + ", deviceChannel=" + deviceChannel
-            + ", deviceEmulationType=" + deviceEmulationType + ", drive=" + drive + "]";
+      return "ServerDrive{" +
+            "bootOrder=" + bootOrder +
+            ", deviceChannel='" + deviceChannel + '\'' +
+            ", deviceEmulationType=" + deviceEmulationType +
+            ", drive=" + drive +
+            ", driveUuid='" + driveUuid + '\'' +
+            '}';
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerInfo.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerInfo.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerInfo.java
index 062eae5..f3e4a00 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerInfo.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/domain/ServerInfo.java
@@ -39,7 +39,7 @@ public class ServerInfo extends Server {
       private Map<String, String> meta;
       private List<NIC> nics;
       private List<String> requirements;
-      private List<String> tags;
+      private List<Tag> tags;
       private String vncPassword;
       private int smp;
 
@@ -137,7 +137,7 @@ public class ServerInfo extends Server {
        * @param tags list of tags this server is associated with
        * @return ServerInfo Builder
        */
-      public Builder tags(List<String> tags) {
+      public Builder tags(List<Tag> tags) {
          this.tags = ImmutableList.copyOf(tags);
          return this;
       }
@@ -278,7 +278,7 @@ public class ServerInfo extends Server {
    private final Map<String, String> meta;
    private final List<NIC> nics;
    private final List<String> requirements;
-   private final List<String> tags;
+   private final List<Tag> tags;
    @Named("vnc_password")
    private final String vncPassword;
    private final int smp;
@@ -292,7 +292,7 @@ public class ServerInfo extends Server {
    public ServerInfo(String uuid, String name, URI resourceUri, Owner owner, ServerStatus status, ServerRuntime runtime,
                      int cpu, boolean cpusInsteadOfCores, List<ServerDrive> drives, boolean enableNuma,
                      boolean hvRelaxed, boolean hvTsc, BigInteger memory, Map<String, String> meta, List<NIC> nics,
-                     List<String> requirements, List<String> tags, String vncPassword, int smp) {
+                     List<String> requirements, List<Tag> tags, String vncPassword, int smp) {
       super(uuid, name, resourceUri, owner, status, runtime);
       this.cpu = cpu;
       this.cpusInsteadOfCores = cpusInsteadOfCores;
@@ -382,7 +382,7 @@ public class ServerInfo extends Server {
    /**
     * @return list of tags this server is associated with
     */
-   public List<String> getTags() {
+   public List<Tag> getTags() {
       return tags;
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/functions/internal/ParseTags.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/functions/internal/ParseTags.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/functions/internal/ParseTags.java
index c7427b1..ff6c1a8 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/functions/internal/ParseTags.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/functions/internal/ParseTags.java
@@ -67,25 +67,4 @@ public class ParseTags extends ParseJson<ParseTags.Tags> {
          };
       }
    }
-
-   public static class ToPagedIterableInfo extends ArgsToPagedIterable<Tag, ToPagedIterable> {
-
-      private CloudSigma2Api api;
-
-      @Inject
-      public ToPagedIterableInfo(CloudSigma2Api api) {
-         this.api = api;
-      }
-
-      @Override
-      protected Function<Object, IterableWithMarker<Tag>> markerToNextForArgs(List<Object> args) {
-         return new Function<Object, IterableWithMarker<Tag>>() {
-            @Override
-            public IterableWithMarker<Tag> apply(Object input) {
-               PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
-               return api.listTagsInfo(paginationOptions);
-            }
-         };
-      }
-   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/handlers/CloudSigmaErrorHandler.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/handlers/CloudSigmaErrorHandler.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/handlers/CloudSigmaErrorHandler.java
index a2912e7..f41e865 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/handlers/CloudSigmaErrorHandler.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/handlers/CloudSigmaErrorHandler.java
@@ -16,8 +16,11 @@
  */
 package org.jclouds.cloudsigma2.handlers;
 
-import com.google.common.base.Throwables;
-import com.google.common.io.Closeables;
+import java.io.IOException;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
 import org.jclouds.http.HttpCommand;
 import org.jclouds.http.HttpErrorHandler;
 import org.jclouds.http.HttpResponse;
@@ -27,9 +30,8 @@ import org.jclouds.rest.AuthorizationException;
 import org.jclouds.rest.ResourceNotFoundException;
 import org.jclouds.util.Strings2;
 
-import javax.annotation.Resource;
-import javax.inject.Singleton;
-import java.io.IOException;
+import com.google.common.base.Throwables;
+import com.google.common.io.Closeables;
 
 /**
  * This will parse and set an appropriate exception on the command object.

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiExpectTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiExpectTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiExpectTest.java
index e5ff7ad..1395eae 100644
--- a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiExpectTest.java
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiExpectTest.java
@@ -16,8 +16,16 @@
  */
 package org.jclouds.cloudsigma2;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
 import org.jclouds.cloudsigma2.domain.AccountBalance;
 import org.jclouds.cloudsigma2.domain.CalcSubscription;
 import org.jclouds.cloudsigma2.domain.CreateSubscriptionRequest;
@@ -52,14 +60,8 @@ import org.jclouds.http.HttpResponse;
 import org.jclouds.rest.internal.BaseRestApiExpectTest;
 import org.testng.annotations.Test;
 
-import javax.ws.rs.core.MediaType;
-import java.math.BigInteger;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
 
 @Test(groups = "unit")
 public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2Api> {
@@ -323,7 +325,7 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
 
    @Test
    public void testCloneDrive() throws Exception {
-      String uuid = "e96f3c63-6f50-47eb-9401-a56c5ccf6b32";
+      String uuid = "92ca1450-417e-4cc1-983b-1015777e2591";
       CloudSigma2Api api = requestSendsResponse(
             postBuilder()
                   .payload(payloadFromResourceWithContentType("/drives-create-request.json",
@@ -331,7 +333,7 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
                   .endpoint(endpoint + "drives/" + uuid + "/action/?do=clone")
                   .build(),
             responseBuilder()
-                  .payload(payloadFromResourceWithContentType("/drives-detail.json", MediaType.APPLICATION_JSON))
+                  .payload(payloadFromResourceWithContentType("/drive-cloned.json", MediaType.APPLICATION_JSON))
                   .build());
 
       DriveInfo result = api.cloneDrive(uuid, new DriveInfo.Builder()
@@ -404,7 +406,7 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
 
    @Test
    public void testCloneLibraryDrive() throws Exception {
-      String uuid = "e96f3c63-6f50-47eb-9401-a56c5ccf6b32";
+      String uuid = "8c45d8d9-4efd-44ec-9833-8d52004b4298";
       CloudSigma2Api api = requestSendsResponse(
             postBuilder()
                   .payload(payloadFromResourceWithContentType("/libdrives-create-request.json",
@@ -412,7 +414,7 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
                   .endpoint(endpoint + "libdrives/" + uuid + "/action/?do=clone")
                   .build(),
             responseBuilder()
-                  .payload(payloadFromResourceWithContentType("/libdrives-single.json", MediaType.APPLICATION_JSON))
+                  .payload(payloadFromResourceWithContentType("/libdrives-cloned.json", MediaType.APPLICATION_JSON))
                   .build());
 
       DriveInfo result = api.cloneLibraryDrive(uuid, new LibraryDrive.Builder()
@@ -817,6 +819,27 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
    }
 
    @Test
+   public void testGetFirewallPolicy() throws Exception {
+      String uuid = "9001b532-857a-405a-8e50-54e342871e77";
+      CloudSigma2Api api = requestsSendResponses(
+            getBuilder()
+                  .endpoint(endpoint + "fwpolicies/" + uuid + "/")
+                  .build(),
+            responseBuilder()
+                  .payload(payloadFromResourceWithContentType("/fwpolicies-get-single.json",
+                        MediaType.APPLICATION_JSON))
+                  .build(),
+            getBuilder()
+                  .endpoint(endpoint + "fwpolicies/failure")
+                  .build(),
+            HttpResponse.builder()
+                  .statusCode(404)
+                  .build());
+
+      assertNotNull(api.getFirewallPolicy(uuid));
+   }
+
+   @Test
    public void testCreateFirewallPolicies() throws Exception {
       CloudSigma2Api api = requestSendsResponse(
             postBuilder()
@@ -1000,6 +1023,26 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
    }
 
    @Test
+   public void testDeleteFirewallPolicy() throws Exception {
+      String uuid = "9001b532-857a-405a-8e50-54e342871e77";
+
+      CloudSigma2Api api = requestsSendResponses(
+            deleteBuilder()
+                  .endpoint(endpoint + "fwpolicies/" + uuid + "/")
+                  .build(),
+            responseBuilder()
+                  .build(),
+            deleteBuilder()
+                  .endpoint(endpoint + "fwpolicies/failure")
+                  .build(),
+            HttpResponse.builder()
+                  .statusCode(404)
+                  .build());
+
+      api.deleteFirewallPolicy(uuid);
+   }
+
+   @Test
    public void testGetVLANInfo() throws Exception {
       String uuid = "96537817-f4b6-496b-a861-e74192d3ccb0";
       CloudSigma2Api api = requestSendsResponse(
@@ -1276,50 +1319,6 @@ public class CloudSigma2ApiExpectTest extends BaseRestApiExpectTest<CloudSigma2A
    }
 
    @Test
-   public void testListTagsInfo() throws Exception {
-      CloudSigma2Api api = requestsSendResponses(
-            getBuilder()
-                  .endpoint(endpoint + "tags/detail/")
-                  .build(),
-            responseBuilder()
-                  .payload(payloadFromResourceWithContentType("/tags-detail-first-page.json",
-                        MediaType.APPLICATION_JSON))
-                  .build(),
-            getBuilder()
-                  .endpoint(endpoint + "tags/detail/")
-                  .addQueryParam("limit", "1")
-                  .addQueryParam("offset", "1")
-                  .build(),
-            responseBuilder()
-                  .payload(payloadFromResourceWithContentType("/tags-detail-last-page.json",
-                        MediaType.APPLICATION_JSON))
-                  .build());
-
-
-      List<Tag> tags = api.listTagsInfo().concat().toList();
-
-      assertEquals(tags.size(), 2);
-      assertEquals(tags.get(0).getUuid(), "956e2ca0-dee3-4b3f-a1be-a6e86f90946f");
-      assertEquals(tags.get(1).getUuid(), "68bb0cfc-0c76-4f37-847d-7bb705c5ae46");
-   }
-
-
-   @Test
-   public void testListTagsInfoPaginatedCollection() throws Exception {
-      CloudSigma2Api api = requestSendsResponse(
-            getBuilder()
-                  .endpoint(endpoint + "tags/detail/?limit=2&offset=2")
-                  .build(),
-            responseBuilder()
-                  .payload(payloadFromResourceWithContentType("/tags-detail.json", MediaType.APPLICATION_JSON))
-                  .build());
-
-      for (Tag tag : api.listTagsInfo(new PaginationOptions.Builder().limit(2).offset(2).build())) {
-         assertNotNull(tag);
-      }
-   }
-
-   @Test
    public void testGetTagInfo() throws Exception {
       String uuid = "68bb0cfc-0c76-4f37-847d-7bb705c5ae46";
       CloudSigma2Api api = requestSendsResponse(

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiLiveTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiLiveTest.java
index 5fcf1bb..751dea8 100644
--- a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiLiveTest.java
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ApiLiveTest.java
@@ -70,10 +70,13 @@ import com.google.common.collect.Maps;
 public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
 
    private DriveInfo createdDrive;
+   private DriveInfo clonedDrive;
+   private LibraryDrive clonedLibraryDrive;
    private List<DriveInfo> createdDrives;
    private ServerInfo createdServer;
    private List<ServerInfo> createdServers;
    private FirewallPolicy createdFirewallPolicy;
+   private List<FirewallPolicy> createdFirewallPolicies;
    private Tag createdTag;
    private List<Tag> createdTags;
 
@@ -142,11 +145,23 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
       checkDrive(editedDrive, api.editDrive(createdDrive.getUuid(), editedDrive));
    }
 
+   @Test(dependsOnMethods = {"testCreateDrive"})
+   public void testCloneDrive() throws Exception {
+      clonedDrive = api.cloneDrive(createdDrive.getUuid(), null);
+      checkDrive(createdDrive, clonedDrive);
+   }
+
    @Test(dependsOnMethods = {"testEditDrive", "testCreateTag", "testEditTag"})
    public void testDeleteDrive() throws Exception {
       String uuid = createdDrive.getUuid();
       api.deleteDrive(uuid);
       assertNull(api.getDriveInfo(uuid));
+      String clonedDriveUuid = clonedDrive.getUuid();
+      api.deleteDrive(clonedDriveUuid);
+      assertNull(api.getDriveInfo(clonedDriveUuid));
+      String clonedLibraryDriveUuid = clonedLibraryDrive.getUuid();
+      api.deleteDrive(clonedLibraryDriveUuid);
+      assertNull(api.getDriveInfo(clonedLibraryDriveUuid));
    }
 
    @Test(dependsOnMethods = {"testCreateDrives"})
@@ -175,6 +190,13 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
       }
    }
 
+   @Test
+   public void testCloneLibraryDrive() throws Exception {
+      LibraryDrive libraryDrive = api.listLibraryDrives().concat().get(0);
+      clonedLibraryDrive = api.cloneLibraryDrive(libraryDrive.getUuid(), null);
+      checkLibraryDrive(libraryDrive, clonedLibraryDrive);
+   }
+
    @Test(dependsOnMethods = {"testCreateServers"})
    public void testListServers() throws Exception {
       assertNotNull(api.listServers());
@@ -273,6 +295,15 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
       assertNotNull(api.listFirewallPoliciesInfo());
    }
 
+   @Test(dependsOnMethods = {"testCreateFirewallPolicies"})
+   public void testGetFirewallPolicy() throws Exception {
+      for (FirewallPolicy firewallPolicy : api.listFirewallPoliciesInfo().concat()) {
+         FirewallPolicy receivedPolicy = api.getFirewallPolicy(firewallPolicy.getUuid());
+         checkFirewallPolicy(firewallPolicy, receivedPolicy);
+         assertEquals(firewallPolicy.getUuid(), receivedPolicy.getUuid());
+      }
+   }
+
    @Test
    public void testCreateFirewallPolicies() throws Exception {
       List<FirewallPolicy> newFirewallPolicies = ImmutableList.of(
@@ -329,7 +360,7 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
                         .build()))
                   .build());
 
-      List<FirewallPolicy> createdFirewallPolicies = api.createFirewallPolicies(newFirewallPolicies);
+      createdFirewallPolicies = api.createFirewallPolicies(newFirewallPolicies);
       assertEquals(newFirewallPolicies.size(), createdFirewallPolicies.size());
 
       for (int i = 0; i < newFirewallPolicies.size(); i++) {
@@ -403,6 +434,23 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
       checkFirewallPolicy(editedPolicy, api.editFirewallPolicy(createdFirewallPolicy.getUuid(), editedPolicy));
    }
 
+   @Test(dependsOnMethods = {"testEditFirewallPolicy", "testCreateFirewallPolicies"})
+   public void deleteFirewallPolicies() throws Exception {
+      ImmutableList.Builder<String> stringListBuilder = ImmutableList.builder();
+
+      stringListBuilder.add(createdFirewallPolicy.getUuid());
+      api.deleteFirewallPolicy(createdFirewallPolicy.getUuid());
+
+      for (FirewallPolicy firewallPolicy : createdFirewallPolicies) {
+         stringListBuilder.add(firewallPolicy.getUuid());
+         api.deleteFirewallPolicy(firewallPolicy.getUuid());
+      }
+
+      ImmutableList<String> uuids = stringListBuilder.build();
+      FluentIterable<FirewallPolicy> servers = api.listFirewallPolicies().concat();
+      assertFalse(any(transform(servers, extractUuid()), in(uuids)));
+   }
+
    @Test
    public void testListVLANs() throws Exception {
       assertNotNull(api.listVLANs());
@@ -429,7 +477,7 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
             .meta(meta)
             .build();
 
-      if (!api.listVLANs().isEmpty()) {
+      if (!api.listVLANs().concat().isEmpty()) {
          checkVlAN(vlanInfo, api.editVLAN(api.listVLANs().concat().get(0).getUuid(), vlanInfo));
       }
    }
@@ -460,7 +508,7 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
             .meta(meta)
             .build();
 
-      if (!api.listIPs().isEmpty()) {
+      if (!api.listIPs().concat().isEmpty()) {
          checkIP(ip, api.editIP(api.listIPs().concat().get(0).getUuid(), ip));
       }
    }
@@ -471,11 +519,6 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
    }
 
    @Test(dependsOnMethods = {"testCreateTags"})
-   public void testListTagsInfo() throws Exception {
-      assertNotNull(api.listTagsInfo());
-   }
-
-   @Test(dependsOnMethods = {"testCreateTags"})
    public void testGetTagInfo() throws Exception {
       for (Tag tag : api.listTags().concat()) {
          assertNotNull(api.getTagInfo(tag.getUuid()));
@@ -652,6 +695,18 @@ public class CloudSigma2ApiLiveTest extends BaseApiLiveTest<CloudSigma2Api> {
       assertEquals(newDrive.getMedia(), createdDrive.getMedia());
    }
 
+   private void checkLibraryDrive(LibraryDrive newDrive, LibraryDrive createdDrive) {
+      checkDrive(newDrive, createdDrive);
+      Map<String, String> meta = createdDrive.getMeta();
+
+      assertEquals(newDrive.getArch() == null ? "None" : newDrive.getArch(), meta.get("arch"));
+      assertEquals(newDrive.getDescription() == null ? "None" : newDrive.getDescription(), meta.get("description"));
+      assertEquals(newDrive.getImageType() == null ? "None" : newDrive.getImageType(), meta.get("image_type"));
+      assertEquals(newDrive.getInstallNotes() == null ? "None" : newDrive.getInstallNotes(), meta.get("install_notes"));
+      assertEquals(newDrive.getOs() == null ? "None" : newDrive.getOs(), meta.get("os"));
+      assertEquals(newDrive.getVersion() == null ? "None" : newDrive.getVersion(), meta.get("version"));
+   }
+
    private void checkServer(ServerInfo newServer, ServerInfo createdServer) {
       assertEquals(newServer.getName(), createdServer.getName());
       assertEquals(newServer.getMemory(), createdServer.getMemory());

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ComputeServiceLiveTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ComputeServiceLiveTest.java
new file mode 100644
index 0000000..d0b5a91
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ComputeServiceLiveTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.cloudsigma2.compute;
+
+import com.google.inject.Module;
+import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2ComputeServiceLiveTest")
+public class CloudSigma2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
+
+   public CloudSigma2ComputeServiceLiveTest() {
+      provider = "cloudsigma2";
+
+   }
+
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
+
+   // CloudSigma templates require manual interaction to change the password on the first login.
+   // The only way to automatically authenticate to a server is to use an image that supports Cloud Init
+   // and provide the public key
+   @Override
+   protected Template buildTemplate(TemplateBuilder templateBuilder) {
+      Template template = super.buildTemplate(templateBuilder);
+      template.getOptions().authorizePublicKey(keyPair.get("public"));
+      return template;
+   }
+
+   @Override
+   protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) {
+      // CloudSigma does not return the hostname
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/DriveClonedPredicateTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/DriveClonedPredicateTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/DriveClonedPredicateTest.java
new file mode 100644
index 0000000..acabdb3
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/DriveClonedPredicateTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.cloudsigma2.compute.config;
+
+import org.easymock.EasyMock;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.compute.config.CloudSigma2ComputeServiceContextModule.DriveClonedPredicate;
+import org.jclouds.cloudsigma2.domain.DriveInfo;
+import org.jclouds.cloudsigma2.domain.DriveStatus;
+import org.testng.annotations.Test;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Unit tests for the drive cloned predicate
+ */
+@Test(groups = "unit", testName = "DriveClonedPredicateTest")
+public class DriveClonedPredicateTest {
+
+   public void testDriveCloned() {
+      CloudSigma2Api api = EasyMock.createMock(CloudSigma2Api.class);
+
+      for (DriveStatus status : DriveStatus.values()) {
+         expect(api.getDriveInfo(status.name())).andReturn(mockDrive(status));
+      }
+
+      replay(api);
+
+      DriveClonedPredicate predicate = new DriveClonedPredicate(api);
+
+      assertFalse(predicate.apply(mockDrive(DriveStatus.COPYING)));
+      assertFalse(predicate.apply(mockDrive(DriveStatus.UNAVAILABLE)));
+      assertTrue(predicate.apply(mockDrive(DriveStatus.MOUNTED)));
+      assertTrue(predicate.apply(mockDrive(DriveStatus.UNMOUNTED)));
+
+      verify(api);
+   }
+
+   private static DriveInfo mockDrive(DriveStatus status) {
+      return new DriveInfo.Builder().uuid(status.name()).status(status).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/ServerStatusPredicatePredicateTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/ServerStatusPredicatePredicateTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/ServerStatusPredicatePredicateTest.java
new file mode 100644
index 0000000..ea17420
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/config/ServerStatusPredicatePredicateTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.cloudsigma2.compute.config;
+
+import org.easymock.EasyMock;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.compute.config.CloudSigma2ComputeServiceContextModule.ServerStatusPredicate;
+import org.jclouds.cloudsigma2.domain.ServerInfo;
+import org.testng.annotations.Test;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.jclouds.cloudsigma2.domain.ServerStatus.STOPPED;
+import static org.jclouds.cloudsigma2.domain.ServerStatus.STOPPING;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Unit tests for the server status predicate.
+ */
+@Test(groups = "unit", testName = "ServerStatusPredicatePredicateTest")
+public class ServerStatusPredicatePredicateTest {
+
+   public void testServerStatus() {
+      CloudSigma2Api api = EasyMock.createMock(CloudSigma2Api.class);
+
+      expect(api.getServerInfo("one")).andReturn(new ServerInfo.Builder().status(STOPPED).build());
+      expect(api.getServerInfo("two")).andReturn(new ServerInfo.Builder().status(STOPPING).build());
+
+      replay(api);
+
+      ServerStatusPredicate predicate = new ServerStatusPredicate(api, STOPPED);
+      assertTrue(predicate.apply("one"));
+      assertFalse(predicate.apply("two"));
+
+      verify(api);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImageTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImageTest.java b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImageTest.java
new file mode 100644
index 0000000..313ea61
--- /dev/null
+++ b/cloudsigma2/src/test/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImageTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.cloudsigma2.domain.DriveStatus;
+import org.jclouds.cloudsigma2.domain.LibraryDrive;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.jclouds.cloudsigma2.compute.config.CloudSigma2ComputeServiceContextModule.driveStatusToImageStatus;
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "LibraryDriveToImageTest")
+public class LibraryDriveToImageTest {
+
+   private LibraryDrive input;
+   private Image expected;
+
+   @BeforeMethod
+   public void setUp() throws Exception {
+      input = new LibraryDrive.Builder()
+            .uuid("0bc6b02c-7ea2-4c5c-bf07-41c4cec2797d")
+            .name("Debian 7.3 Server")
+            .description("Debian 7.3 Server - amd64 Pre-Installed English with Python, SSH and VirtIO support. " +
+                  "Last update 2014/02/15.")
+            .os("linux")
+            .arch("64")
+            .version("7.3")
+            .status(DriveStatus.UNMOUNTED)
+            .meta(ImmutableMap.of("test_key", "test_value",
+                  "sample key", "sample value"))
+            .build();
+
+      expected = new ImageBuilder()
+            .ids("0bc6b02c-7ea2-4c5c-bf07-41c4cec2797d")
+            .userMetadata(ImmutableMap.of("test_key", "test_value",
+                  "sample key", "sample value"))
+            .name("Debian 7.3 Server")
+            .description("Debian 7.3 Server - amd64 Pre-Installed English with Python, SSH and VirtIO support. " +
+                  "Last update 2014/02/15.")
+            .operatingSystem(OperatingSystem.builder()
+                  .name("Debian 7.3 Server")
+                  .arch("64")
+                  .family(OsFamily.LINUX)
+                  .version("7.3")
+                  .is64Bit(true)
+                  .description("Debian 7.3 Server - amd64 Pre-Installed English with Python, SSH and VirtIO support. " +
+                        "Last update 2014/02/15.")
+                  .build())
+            .status(Image.Status.UNRECOGNIZED)
+            .build();
+   }
+
+   public void testConvertLibraryDrive() {
+      LibraryDriveToImage function = new LibraryDriveToImage(driveStatusToImageStatus);
+      Image converted = function.apply(input);
+      assertEquals(converted, expected);
+      assertEquals(converted.getUserMetadata(), expected.getUserMetadata());
+      assertEquals(converted.getName(), expected.getName());
+      assertEquals(converted.getDescription(), expected.getDescription());
+      assertEquals(converted.getStatus(), expected.getStatus());
+      assertEquals(converted.getOperatingSystem(), expected.getOperatingSystem());
+   }
+}


[3/3] git commit: JCLOUDS-292: Added CloudSigma2 ComputeService

Posted by na...@apache.org.
JCLOUDS-292: Added CloudSigma2 ComputeService

* Added the ComputeService implementation
* Added the San Jose region
* Added the Honolulu region


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

Branch: refs/heads/master
Commit: a7dd1933d8ca283e1118b538be8aa2e2ac5e8be7
Parents: 75178c7
Author: Vladimir Shevchenko <sh...@gmail.com>
Authored: Thu Jun 12 04:29:25 2014 +0700
Committer: Ignasi Barrera <na...@apache.org>
Committed: Mon Oct 27 18:24:56 2014 +0100

----------------------------------------------------------------------
 cloudsigma2-hnl/pom.xml                         | 127 ++++++
 .../CloudSigma2HonoluluProviderMetadata.java    |  80 ++++
 .../org.jclouds.providers.ProviderMetadata      |   1 +
 .../CloudSigma2HonoluluLiveTest.java            |  27 ++
 ...oudSigma2HonoluluComputeServiceLiveTest.java |  28 ++
 cloudsigma2-lvs/pom.xml                         |   3 +-
 .../CloudSigma2LasVegasLiveTest.java            |  11 +-
 ...oudSigma2LasVegasComputeServiceLiveTest.java |  28 ++
 cloudsigma2-sjc/pom.xml                         | 127 ++++++
 .../CloudSigma2SanJoseProviderMetadata.java     |  80 ++++
 .../org.jclouds.providers.ProviderMetadata      |   1 +
 .../cloudsigma2/CloudSigma2SanJoseLiveTest.java |  27 ++
 ...loudSigma2SanJoseComputeServiceLiveTest.java |  28 ++
 cloudsigma2-wdc/pom.xml                         |   3 +-
 .../CloudSigma2WashingtonLiveTest.java          |   9 +-
 ...dSigma2WashingtonComputeServiceLiveTest.java |  28 ++
 cloudsigma2-zrh/pom.xml                         |   3 +-
 .../cloudsigma2/CloudSigma2ZurichLiveTest.java  |  11 +-
 ...CloudSigma2ZurichComputeServiceLiveTest.java |  28 ++
 cloudsigma2/pom.xml                             |   2 +-
 .../org/jclouds/cloudsigma2/CloudSigma2Api.java | 119 +++---
 .../cloudsigma2/CloudSigma2ApiMetadata.java     |  24 +-
 .../BindCreateSubscriptionRequestList.java      |   3 +
 .../cloudsigma2/binders/BindDrivesToJson.java   |   3 +
 .../BindFirewallPoliciesListToJsonRequest.java  |   3 +
 .../BindServerInfoListToJsonRequest.java        |   3 +
 .../binders/BindTagListToJsonRequest.java       |   3 +
 .../binders/BindUuidStringsToJsonArray.java     |   3 +
 .../CloudSigma2ComputeServiceContextModule.java | 177 ++++++++
 .../compute/functions/LibraryDriveToImage.java  |  61 +++
 .../compute/functions/NICToAddress.java         |  55 +++
 .../compute/functions/ServerDriveToVolume.java  |  52 +++
 .../functions/ServerInfoToNodeMetadata.java     | 135 ++++++
 ...plateOptionsToStatementWithoutPublicKey.java |  59 +++
 .../options/CloudSigma2TemplateOptions.java     | 153 +++++++
 .../CloudSigma2ComputeServiceAdapter.java       | 407 +++++++++++++++++++
 .../config/CloudSigma2Properties.java           |  15 +-
 .../org/jclouds/cloudsigma2/domain/Drive.java   |   2 +-
 .../domain/DrivesListRequestFieldsGroup.java    |  16 +-
 .../cloudsigma2/domain/FirewallPolicy.java      |  43 +-
 .../cloudsigma2/domain/LibraryDrive.java        |  35 +-
 .../domain/ServerAvailabilityGroup.java         |  17 +-
 .../jclouds/cloudsigma2/domain/ServerDrive.java |  30 +-
 .../jclouds/cloudsigma2/domain/ServerInfo.java  |  10 +-
 .../functions/internal/ParseTags.java           |  21 -
 .../handlers/CloudSigmaErrorHandler.java        |  12 +-
 .../cloudsigma2/CloudSigma2ApiExpectTest.java   | 115 +++---
 .../cloudsigma2/CloudSigma2ApiLiveTest.java     |  71 +++-
 .../CloudSigma2ComputeServiceLiveTest.java      |  56 +++
 .../config/DriveClonedPredicateTest.java        |  60 +++
 .../ServerStatusPredicatePredicateTest.java     |  54 +++
 .../functions/LibraryDriveToImageTest.java      |  83 ++++
 .../compute/functions/NICToAddressTest.java     |  90 ++++
 .../functions/ServerDriveToVolumeTest.java      |  79 ++++
 .../functions/ServerInfoToNodeMetadataTest.java | 186 +++++++++
 ...eOptionsToStatementWithoutPublicKeyTest.java |  75 ++++
 .../options/CloudSigma2TemplateOptionsTest.java |  49 +++
 .../functions/ServerInfoToJsonTest.java         |  36 +-
 .../src/test/resources/drive-cloned.json        |  57 +++
 .../test/resources/fwpolicies-get-single.json   |  61 +++
 .../src/test/resources/libdrives-cloned.json    |  34 ++
 .../resources/server-detail-first-page.json     |   4 +-
 .../src/test/resources/server-detail.json       |   4 +-
 .../src/test/resources/servers-single.json      |   4 +-
 pom.xml                                         |   2 +
 65 files changed, 2991 insertions(+), 242 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-hnl/pom.xml
----------------------------------------------------------------------
diff --git a/cloudsigma2-hnl/pom.xml b/cloudsigma2-hnl/pom.xml
new file mode 100644
index 0000000..4a58c7f
--- /dev/null
+++ b/cloudsigma2-hnl/pom.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds.labs</groupId>
+    <artifactId>jclouds-labs</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <!-- TODO: when out of labs, switch to org.jclouds.provider -->
+  <groupId>org.apache.jclouds.labs</groupId>
+  <artifactId>cloudsigma2-hnl</artifactId>
+  <version>2.0.0-SNAPSHOT</version>
+  <name>jclouds CloudSigma v2 Honolulu Provider</name>
+  <description>ComputeService binding to the CloudSigma datacenter in Honolulu</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <test.cloudsigma2-hnl.endpoint>https://hnl.cloudsigma.com/api/2.0/</test.cloudsigma2-hnl.endpoint>
+    <test.cloudsigma2-hnl.api-version>2.0</test.cloudsigma2-hnl.api-version>
+    <test.cloudsigma2-hnl.build-version />
+    <test.cloudsigma2-hnl.identity>FIXME</test.cloudsigma2-hnl.identity>
+    <test.cloudsigma2-hnl.credential>FIXME</test.cloudsigma2-hnl.credential>
+    <!-- Ubuntu 14.04 Cloud Image -->
+    <test.cloudsigma2-hnl.template>imageId=9e0400ab-d911-4232-971d-f552330b61be,loginUser=ubuntu</test.cloudsigma2-hnl.template>
+    <jclouds.osgi.export>org.jclouds.cloudsigma2*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>
+      org.jclouds.compute.internal;version="${project.version}",
+      org.jclouds.rest.internal;version="${project.version}",
+      org.jclouds*;version="${project.version}",
+      *
+    </jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>cloudsigma2</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>cloudsigma2</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-compute</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-log4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-sshj</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <systemPropertyVariables>
+                    <test.cloudsigma2-hnl.endpoint>${test.cloudsigma2-hnl.endpoint}</test.cloudsigma2-hnl.endpoint>
+                    <test.cloudsigma2-hnl.api-version>${test.cloudsigma2-hnl.api-version}</test.cloudsigma2-hnl.api-version>
+                    <test.cloudsigma2-hnl.build-version>${test.cloudsigma2-hnl.build-version}</test.cloudsigma2-hnl.build-version>
+                    <test.cloudsigma2-hnl.identity>${test.cloudsigma2-hnl.identity}</test.cloudsigma2-hnl.identity>
+                    <test.cloudsigma2-hnl.credential>${test.cloudsigma2-hnl.credential}</test.cloudsigma2-hnl.credential>
+                    <test.cloudsigma2-hnl.template>${test.cloudsigma2-hnl.template}</test.cloudsigma2-hnl.template>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-hnl/src/main/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluProviderMetadata.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-hnl/src/main/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluProviderMetadata.java b/cloudsigma2-hnl/src/main/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluProviderMetadata.java
new file mode 100644
index 0000000..ed5860c
--- /dev/null
+++ b/cloudsigma2-hnl/src/main/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluProviderMetadata.java
@@ -0,0 +1,80 @@
+/*
+ * 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.cloudsigma2;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+/**
+ * Implementation of {@link org.jclouds.providers.internal.BaseProviderMetadata} for CloudSigma Honolulu.
+ */
+public class CloudSigma2HonoluluProviderMetadata extends BaseProviderMetadata {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
+
+   public CloudSigma2HonoluluProviderMetadata() {
+      super(builder());
+   }
+
+   public CloudSigma2HonoluluProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
+      return properties;
+   }
+
+   public static class Builder
+         extends
+         BaseProviderMetadata.Builder {
+
+      protected Builder() {
+         id("cloudsigma2-hnl")
+         .name("CloudSigma 2 Honolulu")
+         .apiMetadata(new CloudSigma2ApiMetadata())
+         .homepage(URI.create("http://www.cloudsigma.com/en/our-cloud/features"))
+         .console(URI.create("https://gui.hnl.cloudsigma.com/"))
+         .iso3166Codes("US-NV")
+         .endpoint("https://hnl.cloudsigma.com/api/2.0/")
+         .defaultProperties(CloudSigma2HonoluluProviderMetadata.defaultProperties());
+      }
+
+      @Override
+      public CloudSigma2HonoluluProviderMetadata build() {
+         return new CloudSigma2HonoluluProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(
+            ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-hnl/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
----------------------------------------------------------------------
diff --git a/cloudsigma2-hnl/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/cloudsigma2-hnl/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..01eff09
--- /dev/null
+++ b/cloudsigma2-hnl/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.cloudsigma2.CloudSigma2HonoluluProviderMetadata

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluLiveTest.java b/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluLiveTest.java
new file mode 100644
index 0000000..d980ffd
--- /dev/null
+++ b/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/CloudSigma2HonoluluLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * 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.cloudsigma2;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2HonoluluLiveTest")
+public class CloudSigma2HonoluluLiveTest extends CloudSigma2ApiLiveTest {
+
+   public CloudSigma2HonoluluLiveTest() {
+      provider = "cloudsigma2-hnl";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2HonoluluComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2HonoluluComputeServiceLiveTest.java b/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2HonoluluComputeServiceLiveTest.java
new file mode 100644
index 0000000..3d97ed1
--- /dev/null
+++ b/cloudsigma2-hnl/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2HonoluluComputeServiceLiveTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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.cloudsigma2.compute;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2HonoluluComputeServiceLiveTest")
+public class CloudSigma2HonoluluComputeServiceLiveTest extends CloudSigma2ComputeServiceLiveTest {
+
+   public CloudSigma2HonoluluComputeServiceLiveTest() {
+      provider = "cloudsigma2-hnl";
+      group = "cloudsigma2";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-lvs/pom.xml
----------------------------------------------------------------------
diff --git a/cloudsigma2-lvs/pom.xml b/cloudsigma2-lvs/pom.xml
index 54874c8..699b963 100644
--- a/cloudsigma2-lvs/pom.xml
+++ b/cloudsigma2-lvs/pom.xml
@@ -39,7 +39,8 @@
     <test.cloudsigma2-lvs.build-version />
     <test.cloudsigma2-lvs.identity>FIXME</test.cloudsigma2-lvs.identity>
     <test.cloudsigma2-lvs.credential>FIXME</test.cloudsigma2-lvs.credential>
-    <test.cloudsigma2-lvs.template />
+    <!-- Ubuntu 14.04 Cloud Image -->
+    <test.cloudsigma2-lvs.template>imageId=9e0400ab-d911-4232-971d-f552330b61be,loginUser=ubuntu</test.cloudsigma2-lvs.template>
     <jclouds.osgi.export>org.jclouds.cloudsigma2*;version="${project.version}"</jclouds.osgi.export>
     <jclouds.osgi.import>
       org.jclouds.compute.internal;version="${project.version}",

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/CloudSigma2LasVegasLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/CloudSigma2LasVegasLiveTest.java b/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/CloudSigma2LasVegasLiveTest.java
index 5a560cd..e42523e 100644
--- a/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/CloudSigma2LasVegasLiveTest.java
+++ b/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/CloudSigma2LasVegasLiveTest.java
@@ -18,9 +18,10 @@ package org.jclouds.cloudsigma2;
 
 import org.testng.annotations.Test;
 
-@Test(groups = {"live"})
-public class CloudSigma2LasVegasLiveTest extends CloudSigma2ApiLiveTest{
-    public CloudSigma2LasVegasLiveTest() {
-        provider = "cloudsigma2-lvs";
-    }
+@Test(groups = "live", testName = "CloudSigma2LasVegasLiveTest")
+public class CloudSigma2LasVegasLiveTest extends CloudSigma2ApiLiveTest {
+
+   public CloudSigma2LasVegasLiveTest() {
+      provider = "cloudsigma2-lvs";
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2LasVegasComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2LasVegasComputeServiceLiveTest.java b/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2LasVegasComputeServiceLiveTest.java
new file mode 100644
index 0000000..f4f4aaf
--- /dev/null
+++ b/cloudsigma2-lvs/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2LasVegasComputeServiceLiveTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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.cloudsigma2.compute;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2LasVegasComputeServiceLiveTest")
+public class CloudSigma2LasVegasComputeServiceLiveTest extends CloudSigma2ComputeServiceLiveTest {
+
+   public CloudSigma2LasVegasComputeServiceLiveTest() {
+      provider = "cloudsigma2-lvs";
+      group = "cloudsigma2";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-sjc/pom.xml
----------------------------------------------------------------------
diff --git a/cloudsigma2-sjc/pom.xml b/cloudsigma2-sjc/pom.xml
new file mode 100644
index 0000000..a4b2200
--- /dev/null
+++ b/cloudsigma2-sjc/pom.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds.labs</groupId>
+    <artifactId>jclouds-labs</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <!-- TODO: when out of labs, switch to org.jclouds.provider -->
+  <groupId>org.apache.jclouds.labs</groupId>
+  <artifactId>cloudsigma2-sjc</artifactId>
+  <version>2.0.0-SNAPSHOT</version>
+  <name>jclouds CloudSigma v2 San Jose Provider</name>
+  <description>ComputeService binding to the CloudSigma datacenter in San Jose</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <test.cloudsigma2-sjc.endpoint>https://sjc.cloudsigma.com/api/2.0/</test.cloudsigma2-sjc.endpoint>
+    <test.cloudsigma2-sjc.api-version>2.0</test.cloudsigma2-sjc.api-version>
+    <test.cloudsigma2-sjc.build-version />
+    <test.cloudsigma2-sjc.identity>FIXME</test.cloudsigma2-sjc.identity>
+    <test.cloudsigma2-sjc.credential>FIXME</test.cloudsigma2-sjc.credential>
+    <!-- Ubuntu 14.04 Cloud Image -->
+    <test.cloudsigma2-sjc.template>imageId=4e1fb3af-5da9-4575-9b38-b8adac549aad,loginUser=ubuntu</test.cloudsigma2-sjc.template>
+    <jclouds.osgi.export>org.jclouds.cloudsigma2*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>
+      org.jclouds.compute.internal;version="${project.version}",
+      org.jclouds.rest.internal;version="${project.version}",
+      org.jclouds*;version="${project.version}",
+      *
+    </jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>cloudsigma2</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.labs</groupId>
+      <artifactId>cloudsigma2</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-compute</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-log4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-sshj</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <systemPropertyVariables>
+                    <test.cloudsigma2-sjc.endpoint>${test.cloudsigma2-sjc.endpoint}</test.cloudsigma2-sjc.endpoint>
+                    <test.cloudsigma2-sjc.api-version>${test.cloudsigma2-sjc.api-version}</test.cloudsigma2-sjc.api-version>
+                    <test.cloudsigma2-sjc.build-version>${test.cloudsigma2-sjc.build-version}</test.cloudsigma2-sjc.build-version>
+                    <test.cloudsigma2-sjc.identity>${test.cloudsigma2-sjc.identity}</test.cloudsigma2-sjc.identity>
+                    <test.cloudsigma2-sjc.credential>${test.cloudsigma2-sjc.credential}</test.cloudsigma2-sjc.credential>
+                    <test.cloudsigma2-sjc.template>${test.cloudsigma2-sjc.template}</test.cloudsigma2-sjc.template>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-sjc/src/main/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseProviderMetadata.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-sjc/src/main/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseProviderMetadata.java b/cloudsigma2-sjc/src/main/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseProviderMetadata.java
new file mode 100644
index 0000000..b47b399
--- /dev/null
+++ b/cloudsigma2-sjc/src/main/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseProviderMetadata.java
@@ -0,0 +1,80 @@
+/*
+ * 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.cloudsigma2;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+/**
+ * Implementation of {@link org.jclouds.providers.internal.BaseProviderMetadata} for CloudSigma San Jose.
+ */
+public class CloudSigma2SanJoseProviderMetadata extends BaseProviderMetadata {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
+
+   public CloudSigma2SanJoseProviderMetadata() {
+      super(builder());
+   }
+
+   public CloudSigma2SanJoseProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
+      return properties;
+   }
+
+   public static class Builder
+         extends
+         BaseProviderMetadata.Builder {
+
+      protected Builder() {
+         id("cloudsigma2-sjc")
+         .name("CloudSigma 2 San Jose")
+         .apiMetadata(new CloudSigma2ApiMetadata())
+         .homepage(URI.create("http://www.cloudsigma.com/en/our-cloud/features"))
+         .console(URI.create("https://gui.sjc.cloudsigma.com/"))
+         .iso3166Codes("US-CA")
+         .endpoint("https://sjc.cloudsigma.com/api/2.0/")
+         .defaultProperties(CloudSigma2SanJoseProviderMetadata.defaultProperties());
+      }
+
+      @Override
+      public CloudSigma2SanJoseProviderMetadata build() {
+         return new CloudSigma2SanJoseProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(
+            ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-sjc/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
----------------------------------------------------------------------
diff --git a/cloudsigma2-sjc/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/cloudsigma2-sjc/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..d8aa542
--- /dev/null
+++ b/cloudsigma2-sjc/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.cloudsigma2.CloudSigma2SanJoseProviderMetadata

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseLiveTest.java b/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseLiveTest.java
new file mode 100644
index 0000000..70f8050
--- /dev/null
+++ b/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2SanJoseLiveTest.java
@@ -0,0 +1,27 @@
+/*
+ * 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.cloudsigma2;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2SanJoseLiveTest")
+public class CloudSigma2SanJoseLiveTest extends CloudSigma2ApiLiveTest {
+
+   public CloudSigma2SanJoseLiveTest() {
+      provider = "cloudsigma2-sjc";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2SanJoseComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2SanJoseComputeServiceLiveTest.java b/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2SanJoseComputeServiceLiveTest.java
new file mode 100644
index 0000000..7f1ce77
--- /dev/null
+++ b/cloudsigma2-sjc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2SanJoseComputeServiceLiveTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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.cloudsigma2.compute;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2SanJoseComputeServiceLiveTest")
+public class CloudSigma2SanJoseComputeServiceLiveTest extends CloudSigma2ComputeServiceLiveTest {
+
+   public CloudSigma2SanJoseComputeServiceLiveTest() {
+      provider = "cloudsigma2-sjc";
+      group = "cloudsigma2";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-wdc/pom.xml
----------------------------------------------------------------------
diff --git a/cloudsigma2-wdc/pom.xml b/cloudsigma2-wdc/pom.xml
index ff5ba30..220080a 100644
--- a/cloudsigma2-wdc/pom.xml
+++ b/cloudsigma2-wdc/pom.xml
@@ -39,7 +39,8 @@
     <test.cloudsigma2-wdc.build-version />
     <test.cloudsigma2-wdc.identity>FIXME</test.cloudsigma2-wdc.identity>
     <test.cloudsigma2-wdc.credential>FIXME</test.cloudsigma2-wdc.credential>
-    <test.cloudsigma2-wdc.template />
+    <!-- Ubuntu 14.04 Cloud Image -->
+    <test.cloudsigma2-wdc.template>imageId=677f3f9a-840a-4f6e-8a21-987dcb59c81a,loginUser=ubuntu</test.cloudsigma2-wdc.template>
     <jclouds.osgi.export>org.jclouds.cloudsigma2*;version="${project.version}"</jclouds.osgi.export>
     <jclouds.osgi.import>
       org.jclouds.compute.internal;version="${project.version}",

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2WashingtonLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2WashingtonLiveTest.java b/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2WashingtonLiveTest.java
index 2fe5f2b..cb80b1e 100644
--- a/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2WashingtonLiveTest.java
+++ b/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/CloudSigma2WashingtonLiveTest.java
@@ -18,9 +18,10 @@ package org.jclouds.cloudsigma2;
 
 import org.testng.annotations.Test;
 
-@Test(groups = {"live"})
+@Test(groups = "live", testName = "CloudSigma2WashingtonLiveTest")
 public class CloudSigma2WashingtonLiveTest extends CloudSigma2ApiLiveTest {
-    public CloudSigma2WashingtonLiveTest() {
-        provider = "cloudsigma2-wdc";
-    }
+
+   public CloudSigma2WashingtonLiveTest() {
+      provider = "cloudsigma2-wdc";
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2WashingtonComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2WashingtonComputeServiceLiveTest.java b/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2WashingtonComputeServiceLiveTest.java
new file mode 100644
index 0000000..cd3976d
--- /dev/null
+++ b/cloudsigma2-wdc/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2WashingtonComputeServiceLiveTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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.cloudsigma2.compute;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2WashingtonComputeServiceLiveTest")
+public class CloudSigma2WashingtonComputeServiceLiveTest extends CloudSigma2ComputeServiceLiveTest {
+
+   public CloudSigma2WashingtonComputeServiceLiveTest() {
+      provider = "cloudsigma2-wdc";
+      group = "cloudsigma2";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-zrh/pom.xml
----------------------------------------------------------------------
diff --git a/cloudsigma2-zrh/pom.xml b/cloudsigma2-zrh/pom.xml
index 0dbba31..e6ffa2d 100644
--- a/cloudsigma2-zrh/pom.xml
+++ b/cloudsigma2-zrh/pom.xml
@@ -39,7 +39,8 @@
     <test.cloudsigma2-zrh.build-version />
     <test.cloudsigma2-zrh.identity>FIXME</test.cloudsigma2-zrh.identity>
     <test.cloudsigma2-zrh.credential>FIXME</test.cloudsigma2-zrh.credential>
-    <test.cloudsigma2-zrh.template />
+    <!-- Ubuntu 14.04 Cloud Image -->
+    <test.cloudsigma2-zrh.template>imageId=473adb38-3b64-43b2-93bd-f1a3443c19ea,loginUser=ubuntu</test.cloudsigma2-zrh.template>
     <jclouds.osgi.export>org.jclouds.cloudsigma2*;version="${project.version}"</jclouds.osgi.export>
     <jclouds.osgi.import>
       org.jclouds.compute.internal;version="${project.version}",

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ZurichLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ZurichLiveTest.java b/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ZurichLiveTest.java
index d84899a..e090a88 100644
--- a/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ZurichLiveTest.java
+++ b/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/CloudSigma2ZurichLiveTest.java
@@ -18,9 +18,10 @@ package org.jclouds.cloudsigma2;
 
 import org.testng.annotations.Test;
 
-@Test(groups = {"live"})
-public class CloudSigma2ZurichLiveTest extends CloudSigma2ApiLiveTest{
-    public CloudSigma2ZurichLiveTest() {
-        provider = "cloudsigma2-zrh";
-    }
+@Test(groups = "live", testName = "CloudSigma2ZurichLiveTest")
+public class CloudSigma2ZurichLiveTest extends CloudSigma2ApiLiveTest {
+
+   public CloudSigma2ZurichLiveTest() {
+      provider = "cloudsigma2-zrh";
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ZurichComputeServiceLiveTest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ZurichComputeServiceLiveTest.java b/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ZurichComputeServiceLiveTest.java
new file mode 100644
index 0000000..b85cb57
--- /dev/null
+++ b/cloudsigma2-zrh/src/test/java/org/jclouds/cloudsigma2/compute/CloudSigma2ZurichComputeServiceLiveTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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.cloudsigma2.compute;
+
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "CloudSigma2ZurichComputeServiceLiveTest")
+public class CloudSigma2ZurichComputeServiceLiveTest extends CloudSigma2ComputeServiceLiveTest {
+
+   public CloudSigma2ZurichComputeServiceLiveTest() {
+      provider = "cloudsigma2-zrh";
+      group = "cloudsigma2";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/pom.xml
----------------------------------------------------------------------
diff --git a/cloudsigma2/pom.xml b/cloudsigma2/pom.xml
index 902cfe4..a77745c 100644
--- a/cloudsigma2/pom.xml
+++ b/cloudsigma2/pom.xml
@@ -39,7 +39,7 @@
         <test.cloudsigma2.api-version>2.0</test.cloudsigma2.api-version>
         <test.cloudsigma2.identity>FIXME</test.cloudsigma2.identity>
         <test.cloudsigma2.credential>FIXME</test.cloudsigma2.credential>
-        <test.cloudsigma2.template>imageId=f3c7c665-cd54-4a78-8fd2-7ec2f028cf29</test.cloudsigma2.template>
+        <test.cloudsigma2.template>imageId=f3c7c665-cd54-4a78-8fd2-7ec2f028cf29,loginUser=ubuntu</test.cloudsigma2.template>
         <jclouds.osgi.export>org.jclouds.cloudsigma2*;version="${project.version}"</jclouds.osgi.export>
         <jclouds.osgi.import>
             org.jclouds.compute.internal;version="${project.version}",

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2Api.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2Api.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2Api.java
index ef06286..4b0590b 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2Api.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2Api.java
@@ -174,7 +174,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid drive uuid to get
     * @return null, if not found
     */
-   @Named("drive:getDriveInfo/{uuid}")
+   @Named("drive:getDriveInfo")
    @GET
    @Path("/drives/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -212,7 +212,7 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid what to delete
     */
-   @Named("drive:deleteDrive/{uuid}")
+   @Named("drive:deleteDrive")
    @DELETE
    @Path("/drives/{uuid}/")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
@@ -236,7 +236,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param driveInfo  drive parameters to change
     * @return changed drive
     */
-   @Named("drive:editDrive/{uuid}")
+   @Named("drive:editDrive")
    @PUT
    @Path("/drives/{uuid}/")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
@@ -250,10 +250,12 @@ public interface CloudSigma2Api extends Closeable {
     * @param driveInfo  drive parameters to change
     * @return new drive
     */
-   @Named("drive:cloneDrive/{uuid}")
+   @Named("drive:cloneDrive")
    @POST
    @Path("/drives/{uuid}/action/?do=clone")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   @SelectJson("objects")
+   @OnlyElement
    DriveInfo cloneDrive(@PathParam("uuid") String sourceUuid,
                         @Nullable @BinderParam(BindDriveToJson.class) DriveInfo driveInfo);
 
@@ -286,7 +288,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid uuid of library drive to be listed
     * @return drive information or null if not found
     */
-   @Named("libdrive:getLibraryDrive/{uuid}")
+   @Named("libdrive:getLibraryDrive")
    @GET
    @Path("/libdrives/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -299,10 +301,12 @@ public interface CloudSigma2Api extends Closeable {
     * @param libraryDrive cloned drive
     * @return cloned drive information or null if not found
     */
-   @Named("libdrive:cloneLibraryDrive/{uuid}")
+   @Named("libdrive:cloneLibraryDrive")
    @POST
    @Path("/libdrives/{uuid}/action/?do=clone")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   @SelectJson("objects")
+   @OnlyElement
    LibraryDrive cloneLibraryDrive(@PathParam("uuid") String uuid
          , @Nullable @BinderParam(BindLibraryDriveToJson.class) LibraryDrive libraryDrive);
 
@@ -389,7 +393,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param server data to change
     * @return modified server
     */
-   @Named("server:editServer/{uuid}")
+   @Named("server:editServer")
    @PUT
    @Path("/servers/{uuid}/")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
@@ -401,7 +405,7 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid uuid of server to delete
     */
-   @Named("server:deleteServer/{uuid}")
+   @Named("server:deleteServer")
    @DELETE
    @Path("/servers/{uuid}/")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
@@ -427,7 +431,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid server what to clone
     * @return cloned server
     */
-   @Named("server:cloneServer/{uuid}")
+   @Named("server:cloneServer")
    @POST
    @Path("/servers/{uuid}/action/?do=clone")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
@@ -439,7 +443,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid server uuid
     * @return server info or null, if not found
     */
-   @Named("server:getServerInfo/{uuid}")
+   @Named("server:getServerInfo")
    @GET
    @Path("/servers/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -450,10 +454,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid uuid of server to start
     */
-   @Named("server:startServer/{uuid}")
+   @Named("server:startServer")
    @POST
    @Path("/servers/{uuid}/action/?do=start")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void startServer(@PathParam("uuid") String uuid);
 
    /**
@@ -461,10 +465,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid uuid of server to stop
     */
-   @Named("server:stopServer/{uuid}")
+   @Named("server:stopServer")
    @POST
    @Path("/servers/{uuid}/action/?do=stop")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void stopServer(@PathParam("uuid") String uuid);
 
    /**
@@ -478,10 +482,10 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid      uuid of server to start
     * @param uuidGroup availability group to avoid
     */
-   @Named("server:startServerInSeparateAvailabilityGroup/{uuid}")
+   @Named("server:startServerInSeparateAvailabilityGroup")
    @POST
    @Path("/servers/{uuid}/action/?do=start")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void startServerInSeparateAvailabilityGroup(@PathParam("uuid") String uuid,
                                                @QueryParam("avoid") List<String> uuidGroup);
 
@@ -490,10 +494,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid uuid of server to open VNC tunnel
     */
-   @Named("server:openServerVNCTunnel/{uuid}")
+   @Named("server:openServerVNCTunnel")
    @POST
    @Path("/servers/{uuid}/action/?do=open_vnc")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void openServerVNCTunnel(@PathParam("uuid") String uuid);
 
    /**
@@ -501,10 +505,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid uuid of server to close VNC tunnel
     */
-   @Named("server:closeServerVCNTunnel/{uuid}")
+   @Named("server:closeServerVCNTunnel")
    @POST
    @Path("/servers/{uuid}/action/?do=close_vnc")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void closeServerVCNTunnel(@PathParam("uuid") String uuid);
 
    /**
@@ -521,7 +525,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid Uuid of server to find availability group
     * @return an array holding server UUIDs. The response includes also the UUID of the queried server.
     */
-   @Named("server:getServerAvailabilityGroup/{uuid}")
+   @Named("server:getServerAvailabilityGroup")
    @GET
    @PathParam("/servers/availability_groups/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -574,6 +578,17 @@ public interface CloudSigma2Api extends Closeable {
    PaginatedCollection<FirewallPolicy> listFirewallPoliciesInfo(PaginationOptions options);
 
    /**
+    * Gets firewall policy.
+    *
+    * @return firewall policy
+    */
+   @Named("fwpolicy:getFirewallPolicy")
+   @GET
+   @Path("/fwpolicies/{uuid}/")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   FirewallPolicy getFirewallPolicy(@PathParam("uuid") String uuid);
+
+   /**
     * Creates firewall policies.
     *
     * @param firewallPolicies firewall policies to create
@@ -607,19 +622,30 @@ public interface CloudSigma2Api extends Closeable {
     * @param firewallPolicy firewall policy data to update
     * @return updated firewall policy
     */
-   @Named("fwpolicy:editFirewallPolicy/{uuid}")
+   @Named("fwpolicy:editFirewallPolicy")
    @PUT
    @Path("/fwpolicies/{uuid}/")
    FirewallPolicy editFirewallPolicy(@PathParam("uuid") String uuid
          , @BinderParam(BindFirewallPolicyToJsonRequest.class) FirewallPolicy firewallPolicy);
 
    /**
+    * Deletes a single firewall policy.
+    *
+    * @param uuid uuid of firewall policy to delete
+    */
+   @Named("tag:deleteFirewallPolicy")
+   @DELETE
+   @Path("/fwpolicies/{uuid}/")
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deleteFirewallPolicy(@PathParam("uuid") String uuid);
+
+   /**
     * Gets detailed information for VLAN identified by VLAN uuid.
     *
     * @param uuid uuid of VLAN to get
     * @return null, if not found
     */
-   @Named("vlan:getVLANInfo/{uuid}")
+   @Named("vlan:getVLANInfo")
    @GET
    @Path("/vlans/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -678,7 +704,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param vlanInfo data to change
     * @return changed VLAN
     */
-   @Named("vlan:listVLANInfo/{uuid}")
+   @Named("vlan:listVLANInfo")
    @PUT
    @Path("/vlans/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -737,7 +763,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param uuid uuid of IP to get
     * @return null, if not found
     */
-   @Named("ip:getIPInfo/{uuid}")
+   @Named("ip:getIPInfo")
    @GET
    @Path("/ips/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -750,7 +776,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param ipInfo data to change
     * @return changed IP
     */
-   @Named("ip:editIP/{uuid}")
+   @Named("ip:editIP")
    @PUT
    @Path("/ips/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -781,37 +807,12 @@ public interface CloudSigma2Api extends Closeable {
    PaginatedCollection<Tag> listTags(PaginationOptions options);
 
    /**
-    * Gets the detailed list of tags with additional information to which the authenticated user has access,
-    * like the tagged resource
-    *
-    * @return detailed listings of your tags
-    */
-   @Named("tag:listTagsInfo")
-   @GET
-   @Path("/tags/detail/")
-   @ResponseParser(ParseTags.class)
-   @Transform(ParseTags.ToPagedIterableInfo.class)
-   PagedIterable<Tag> listTagsInfo();
-
-   /**
-    * Gets the detailed list of tags with additional information to which the authenticated user has access,
-    * like the tagged resource
-    *
-    * @return PaginatedCollection of detailed tags
-    */
-   @Named("tag:listTagsInfo")
-   @GET
-   @Path("/tags/detail/")
-   @ResponseParser(ParseTags.class)
-   PaginatedCollection<Tag> listTagsInfo(PaginationOptions options);
-
-   /**
     * Gets detailed information for tag identified by tag uuid.
     *
     * @param uuid tag uuid
     * @return detailed info of tag
     */
-   @Named("tag:getTagInfo/{uuid}")
+   @Named("tag:getTagInfo")
    @GET
    @Path("/tags/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -825,7 +826,7 @@ public interface CloudSigma2Api extends Closeable {
     * @param tag  info to change
     * @return detailed info of tag
     */
-   @Named("tag:editTag/{uuid}")
+   @Named("tag:editTag")
    @PUT
    @Path("/tags/{uuid}/")
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
@@ -849,10 +850,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param uuid uuid of tag to delete
     */
-   @Named("tag:deleteTag/{uuid}")
+   @Named("tag:deleteTag")
    @DELETE
    @Path("/tags/{uuid}/")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void deleteTag(@PathParam("uuid") String uuid);
 
    /**
@@ -1002,10 +1003,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param id id of subscription to extend
     */
-   @Named("subscription:extendSubscription/{id}")
+   @Named("subscription:extendSubscription")
    @POST
    @Path("/subscriptions/{id}/action/?do=extend")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void extendSubscription(@PathParam("id") String id);
 
    /**
@@ -1013,10 +1014,10 @@ public interface CloudSigma2Api extends Closeable {
     *
     * @param id id of subscription to enable autorenew
     */
-   @Named("subscription:enableSubscriptionAutorenew/{id}")
+   @Named("subscription:enableSubscriptionAutorenew")
    @POST
    @Path("/subscriptions/{id}/action/?do=auto_renew")
-   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void enableSubscriptionAutorenew(@PathParam("id") String id);
 
    /**

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2ApiMetadata.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2ApiMetadata.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2ApiMetadata.java
index ea0ff7d..b1dec88 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2ApiMetadata.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/CloudSigma2ApiMetadata.java
@@ -16,15 +16,19 @@
  */
 package org.jclouds.cloudsigma2;
 
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.PROPERTY_DELETE_DRIVES;
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.PROPERTY_VNC_PASSWORD;
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.TIMEOUT_DRIVE_CLONED;
 import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
 
 import java.net.URI;
 import java.util.Properties;
 
 import org.jclouds.apis.ApiMetadata;
+import org.jclouds.cloudsigma2.compute.config.CloudSigma2ComputeServiceContextModule;
 import org.jclouds.cloudsigma2.config.CloudSigma2HttpApiModule;
 import org.jclouds.cloudsigma2.config.CloudSigma2ParserModule;
-import org.jclouds.cloudsigma2.config.CloudSigma2Properties;
+import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.rest.internal.BaseHttpApiMetadata;
 
 import com.google.common.collect.ImmutableSet;
@@ -50,12 +54,10 @@ public class CloudSigma2ApiMetadata extends BaseHttpApiMetadata<CloudSigma2Api>
 
    public static Properties defaultProperties() {
       Properties properties = BaseHttpApiMetadata.defaultProperties();
-      properties.setProperty(CloudSigma2Properties.PROPERTY_VNC_PASSWORD, "IL9vs34d");
-      // passwords are set post-boot, so auth failures are possible
-      // from a race condition applying the password set script
-      properties.setProperty("jclouds.ssh.max-retries", "7");
-      properties.setProperty("jclouds.ssh.retry-auth", "true");
-      properties.setProperty(TEMPLATE, "osFamily=UBUNTU,imageNameMatches=.*[Aa]utomated SSH Access.*,os64Bit=true");
+      properties.setProperty(PROPERTY_VNC_PASSWORD, "IL9vs34d");
+      properties.setProperty(TIMEOUT_DRIVE_CLONED, "60000");
+      properties.setProperty(PROPERTY_DELETE_DRIVES, "true");
+      properties.setProperty(TEMPLATE, "imageNameMatches=Ubuntu.*[Cc]loud [Ii]mage.*,loginUser=ubuntu");
       return properties;
    }
 
@@ -65,19 +67,17 @@ public class CloudSigma2ApiMetadata extends BaseHttpApiMetadata<CloudSigma2Api>
          super(CloudSigma2Api.class);
          id("cloudsigma2")
                .name("CloudSigma API")
-               .defaultIdentity("email")
                .identityName("Email")
-               .defaultCredential("Password")
                .credentialName("Password")
                .documentation(URI.create("http://cloudsigma.com/en/platform-details/the-api"))
                .version("2.0")
                .defaultEndpoint("https://zrh.cloudsigma.com/api/2.0")
                .defaultProperties(CloudSigma2ApiMetadata.defaultProperties())
-               // Uncomment once the ComputeService is implemented 
-               //.view(typeToken(ComputeServiceContext.class))
+               .view(ComputeServiceContext.class)
                .defaultModules(ImmutableSet.<Class<? extends Module>>of(
                      CloudSigma2HttpApiModule.class,
-                     CloudSigma2ParserModule.class));
+                     CloudSigma2ParserModule.class,
+                     CloudSigma2ComputeServiceContextModule.class));
       }
 
       @Override

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindCreateSubscriptionRequestList.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindCreateSubscriptionRequestList.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindCreateSubscriptionRequestList.java
index 1787478..da47e8e 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindCreateSubscriptionRequestList.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindCreateSubscriptionRequestList.java
@@ -18,6 +18,7 @@ package org.jclouds.cloudsigma2.binders;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+
 import org.jclouds.cloudsigma2.domain.CreateSubscriptionRequest;
 import org.jclouds.cloudsigma2.functions.CreateSubscriptionRequestToJson;
 import org.jclouds.http.HttpRequest;
@@ -26,6 +27,7 @@ import org.jclouds.rest.Binder;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import javax.ws.rs.core.MediaType;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -40,6 +42,7 @@ public class BindCreateSubscriptionRequestList implements Binder {
       this.subscriptionRequestJsonObjectFunction = subscriptionRequestJsonObjectFunction;
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object input) {
       checkArgument(input instanceof List, "this binder is only valid for List<CreateSubscriptionRequest>!");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindDrivesToJson.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindDrivesToJson.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindDrivesToJson.java
index 1040da4..5900734 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindDrivesToJson.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindDrivesToJson.java
@@ -18,6 +18,7 @@ package org.jclouds.cloudsigma2.binders;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+
 import org.jclouds.cloudsigma2.domain.DriveInfo;
 import org.jclouds.cloudsigma2.functions.DriveToJson;
 import org.jclouds.http.HttpRequest;
@@ -26,6 +27,7 @@ import org.jclouds.rest.Binder;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import javax.ws.rs.core.MediaType;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -39,6 +41,7 @@ public class BindDrivesToJson implements Binder {
       this.createDriveRequestJson = createDriveRequestToMap;
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
       checkArgument(payload instanceof List, "this binder is only valid for List<DriveInfo>!");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindFirewallPoliciesListToJsonRequest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindFirewallPoliciesListToJsonRequest.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindFirewallPoliciesListToJsonRequest.java
index 4dd9b3c..5c2b22e 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindFirewallPoliciesListToJsonRequest.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindFirewallPoliciesListToJsonRequest.java
@@ -18,6 +18,7 @@ package org.jclouds.cloudsigma2.binders;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+
 import org.jclouds.cloudsigma2.domain.FirewallPolicy;
 import org.jclouds.cloudsigma2.functions.FirewallPolicyToJson;
 import org.jclouds.http.HttpRequest;
@@ -25,6 +26,7 @@ import org.jclouds.rest.Binder;
 
 import javax.inject.Inject;
 import javax.ws.rs.core.MediaType;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -38,6 +40,7 @@ public class BindFirewallPoliciesListToJsonRequest implements Binder {
       this.policyJsonObjectFunction = policyJsonObjectFunction;
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object input) {
       checkArgument(input instanceof List, "this binder is only valid for List<FirewallPolicy>!");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindServerInfoListToJsonRequest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindServerInfoListToJsonRequest.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindServerInfoListToJsonRequest.java
index 9764a11..8cb35d4 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindServerInfoListToJsonRequest.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindServerInfoListToJsonRequest.java
@@ -18,6 +18,7 @@ package org.jclouds.cloudsigma2.binders;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+
 import org.jclouds.cloudsigma2.domain.ServerInfo;
 import org.jclouds.cloudsigma2.functions.ServerInfoToJson;
 import org.jclouds.http.HttpRequest;
@@ -26,6 +27,7 @@ import org.jclouds.rest.Binder;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import javax.ws.rs.core.MediaType;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -39,6 +41,7 @@ public class BindServerInfoListToJsonRequest implements Binder {
       this.createServerInfoRequestToJson = createServerInfoRequestToJson;
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
       checkArgument(payload instanceof List, "this binder is only valid for List<ServerInfo>!");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindTagListToJsonRequest.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindTagListToJsonRequest.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindTagListToJsonRequest.java
index 36d8bee..162851b 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindTagListToJsonRequest.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindTagListToJsonRequest.java
@@ -18,6 +18,7 @@ package org.jclouds.cloudsigma2.binders;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+
 import org.jclouds.cloudsigma2.domain.Tag;
 import org.jclouds.cloudsigma2.functions.TagToJson;
 import org.jclouds.http.HttpRequest;
@@ -26,6 +27,7 @@ import org.jclouds.rest.Binder;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import javax.ws.rs.core.MediaType;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -39,6 +41,7 @@ public class BindTagListToJsonRequest implements Binder {
       this.tagJsonObjectFunction = tagJsonObjectFunction;
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
       checkArgument(payload instanceof List, "this binder is only valid for List<Tag>!");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindUuidStringsToJsonArray.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindUuidStringsToJsonArray.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindUuidStringsToJsonArray.java
index 80ba1ae..44a36ea 100644
--- a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindUuidStringsToJsonArray.java
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/binders/BindUuidStringsToJsonArray.java
@@ -18,17 +18,20 @@ package org.jclouds.cloudsigma2.binders;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+
 import org.jclouds.http.HttpRequest;
 import org.jclouds.rest.Binder;
 
 import javax.inject.Singleton;
 import javax.ws.rs.core.MediaType;
+
 import java.util.List;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
 @Singleton
 public class BindUuidStringsToJsonArray implements Binder {
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
       checkArgument(payload instanceof List, "this binder is only valid for List<String>!");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/config/CloudSigma2ComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/config/CloudSigma2ComputeServiceContextModule.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/config/CloudSigma2ComputeServiceContextModule.java
new file mode 100644
index 0000000..84497e4
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/config/CloudSigma2ComputeServiceContextModule.java
@@ -0,0 +1,177 @@
+/*
+ * 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.cloudsigma2.compute.config;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.compute.functions.LibraryDriveToImage;
+import org.jclouds.cloudsigma2.compute.functions.NICToAddress;
+import org.jclouds.cloudsigma2.compute.functions.ServerDriveToVolume;
+import org.jclouds.cloudsigma2.compute.functions.ServerInfoToNodeMetadata;
+import org.jclouds.cloudsigma2.compute.functions.TemplateOptionsToStatementWithoutPublicKey;
+import org.jclouds.cloudsigma2.compute.options.CloudSigma2TemplateOptions;
+import org.jclouds.cloudsigma2.compute.strategy.CloudSigma2ComputeServiceAdapter;
+import org.jclouds.cloudsigma2.domain.DriveInfo;
+import org.jclouds.cloudsigma2.domain.DriveStatus;
+import org.jclouds.cloudsigma2.domain.LibraryDrive;
+import org.jclouds.cloudsigma2.domain.NIC;
+import org.jclouds.cloudsigma2.domain.ServerDrive;
+import org.jclouds.cloudsigma2.domain.ServerInfo;
+import org.jclouds.cloudsigma2.domain.ServerStatus;
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.functions.TemplateOptionsToStatement;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.compute.reference.ComputeServiceConstants.PollPeriod;
+import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
+import org.jclouds.domain.Location;
+import org.jclouds.functions.IdentityFunction;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.cloudsigma2.config.CloudSigma2Properties.TIMEOUT_DRIVE_CLONED;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
+import static org.jclouds.util.Predicates2.retry;
+
+public class CloudSigma2ComputeServiceContextModule extends
+      ComputeServiceAdapterContextModule<ServerInfo, Hardware, LibraryDrive, Location> {
+
+   @SuppressWarnings("unchecked")
+   @Override
+   protected void configure() {
+      super.configure();
+
+      bind(new TypeLiteral<ComputeServiceAdapter<ServerInfo, Hardware, LibraryDrive, Location>>() {
+      }).to(CloudSigma2ComputeServiceAdapter.class);
+
+      bind(new TypeLiteral<Function<ServerInfo, NodeMetadata>>() {
+      }).to(ServerInfoToNodeMetadata.class);
+      bind(new TypeLiteral<Function<LibraryDrive, Image>>() {
+      }).to(LibraryDriveToImage.class);
+      bind(new TypeLiteral<Function<ServerDrive, Volume>>() {
+      }).to(ServerDriveToVolume.class);
+      bind(new TypeLiteral<Function<Hardware, Hardware>>() {
+      }).to(Class.class.cast(IdentityFunction.class));
+      bind(new TypeLiteral<Function<Location, Location>>() {
+      }).to(Class.class.cast(IdentityFunction.class));
+      bind(new TypeLiteral<Function<NIC, String>>() {
+      }).to(NICToAddress.class);
+
+      bind(TemplateOptions.class).to(CloudSigma2TemplateOptions.class);
+      bind(TemplateOptionsToStatement.class).to(TemplateOptionsToStatementWithoutPublicKey.class);
+   }
+
+   @VisibleForTesting
+   public static final Map<ServerStatus, NodeMetadata.Status> serverStatusToNodeStatus = ImmutableMap
+         .<ServerStatus, NodeMetadata.Status>builder().put(ServerStatus.RUNNING, NodeMetadata.Status.RUNNING)
+         .put(ServerStatus.STARTING, NodeMetadata.Status.PENDING)
+         .put(ServerStatus.STOPPING, NodeMetadata.Status.PENDING)
+         .put(ServerStatus.STOPPED, NodeMetadata.Status.SUSPENDED)
+         .put(ServerStatus.PAUSED, NodeMetadata.Status.SUSPENDED)
+         .put(ServerStatus.UNAVAILABLE, NodeMetadata.Status.SUSPENDED)
+         .put(ServerStatus.UNRECOGNIZED, NodeMetadata.Status.UNRECOGNIZED).build();
+
+   @Provides
+   @Singleton
+   protected Map<ServerStatus, NodeMetadata.Status> provideStatusMap() {
+      return serverStatusToNodeStatus;
+   }
+
+   @VisibleForTesting
+   public static final Map<DriveStatus, Image.Status> driveStatusToImageStatus = ImmutableMap
+         .<DriveStatus, Image.Status>builder().put(DriveStatus.MOUNTED, Image.Status.AVAILABLE)
+         .put(DriveStatus.UNMOUNTED, Image.Status.UNRECOGNIZED).put(DriveStatus.COPYING, Image.Status.PENDING)
+         .put(DriveStatus.UNAVAILABLE, Image.Status.ERROR).build();
+
+   @Provides
+   @Singleton
+   protected Map<DriveStatus, Image.Status> provideImageStatusMap() {
+      return driveStatusToImageStatus;
+   }
+
+   @Provides
+   @Singleton
+   @Named(TIMEOUT_DRIVE_CLONED)
+   protected Predicate<DriveInfo> provideDriveClonedPredicate(final CloudSigma2Api api,
+                                                              @Named(TIMEOUT_DRIVE_CLONED) long driveClonedTimeout) {
+      return retry(new DriveClonedPredicate(api), driveClonedTimeout);
+   }
+
+   @Provides
+   @Singleton
+   @Named(TIMEOUT_NODE_SUSPENDED)
+   protected Predicate<String> provideServerStoppedPredicate(final CloudSigma2Api api, Timeouts timeouts,
+                                                             PollPeriod pollPeriod) {
+      return retry(new ServerStatusPredicate(api, ServerStatus.STOPPED), timeouts.nodeSuspended,
+            pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
+   }
+
+   @VisibleForTesting
+   static class DriveClonedPredicate implements Predicate<DriveInfo> {
+
+      private final CloudSigma2Api api;
+
+      public DriveClonedPredicate(CloudSigma2Api api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      public boolean apply(DriveInfo input) {
+         DriveInfo drive = api.getDriveInfo(input.getUuid());
+         switch (drive.getStatus()) {
+            case COPYING:
+            case UNAVAILABLE:
+               return false;
+            case MOUNTED:
+            case UNMOUNTED:
+               return true;
+            default:
+               throw new IllegalStateException("Resource is in invalid status: " + drive.getStatus());
+         }
+      }
+   }
+
+   @VisibleForTesting
+   static class ServerStatusPredicate implements Predicate<String> {
+
+      private final CloudSigma2Api api;
+      private final ServerStatus status;
+
+      public ServerStatusPredicate(CloudSigma2Api api, ServerStatus status) {
+         this.api = checkNotNull(api, "api");
+         this.status = checkNotNull(status, "status");
+      }
+
+      @Override
+      public boolean apply(String input) {
+         ServerInfo serverInfo = api.getServerInfo(input);
+         return status.equals(serverInfo.getStatus());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImage.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImage.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImage.java
new file mode 100644
index 0000000..d829861
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/LibraryDriveToImage.java
@@ -0,0 +1,61 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.base.Function;
+import org.jclouds.cloudsigma2.domain.DriveStatus;
+import org.jclouds.cloudsigma2.domain.LibraryDrive;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class LibraryDriveToImage implements Function<LibraryDrive, Image> {
+
+   private final Map<DriveStatus, Image.Status> driveStatusToNodeStatus;
+
+   @Inject
+   public LibraryDriveToImage(Map<DriveStatus, Image.Status> driveStatusToNodeStatus) {
+      this.driveStatusToNodeStatus = checkNotNull(driveStatusToNodeStatus, "driveStatusToNodeStatus");
+   }
+
+   @Override
+   public Image apply(LibraryDrive libraryDrive) {
+      return new ImageBuilder()
+            .ids(libraryDrive.getUuid())
+            .userMetadata(libraryDrive.getMeta())
+            .name(libraryDrive.getName())
+            .description(libraryDrive.getDescription())
+            .operatingSystem(OperatingSystem.builder()
+                  .name(libraryDrive.getName())
+                  .arch(libraryDrive.getArch())
+                  .is64Bit(libraryDrive.getArch() != null && libraryDrive.getArch().equals("64"))
+                  .family(libraryDrive.getOs() == null ? null : OsFamily.fromValue(libraryDrive.getOs()))
+                  .version(libraryDrive.getVersion())
+                  .description(libraryDrive.getDescription())
+                  .build())
+            .status(driveStatusToNodeStatus.get(libraryDrive.getStatus()))
+            .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/NICToAddress.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/NICToAddress.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/NICToAddress.java
new file mode 100644
index 0000000..3b0d03f
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/NICToAddress.java
@@ -0,0 +1,55 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.base.Function;
+import org.jclouds.cloudsigma2.domain.IPConfiguration;
+import org.jclouds.cloudsigma2.domain.IPConfigurationType;
+import org.jclouds.cloudsigma2.domain.NIC;
+import org.jclouds.cloudsigma2.domain.NICStats;
+
+import javax.inject.Singleton;
+
+@Singleton
+public final class NICToAddress implements Function<NIC, String> {
+
+   @Override
+   public String apply(NIC nic) {
+      IPConfiguration ipV4Configuration = nic.getIpV4Configuration();
+      IPConfiguration ipV6Configuration = nic.getIpV6Configuration();
+      if (ipV4Configuration != null) {
+         if (ipV4Configuration.getIp() != null) {
+            return ipV4Configuration.getIp().getUuid();
+         } else if (ipV4Configuration.getConfigurationType().equals(IPConfigurationType.DHCP)) {
+            NICStats runtime = nic.getRuntime();
+            if (runtime != null && runtime.getIpV4() != null) {
+               return runtime.getIpV4().getUuid();
+            }
+         }
+      } else if (ipV6Configuration != null) {
+         if (ipV6Configuration.getIp() != null) {
+            return ipV6Configuration.getIp().getUuid();
+         } else if (ipV6Configuration.getConfigurationType().equals(IPConfigurationType.DHCP)) {
+            NICStats runtime = nic.getRuntime();
+            if (runtime != null && runtime.getIpV6() != null) {
+               return runtime.getIpV6().getUuid();
+            }
+         }
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/a7dd1933/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolume.java
----------------------------------------------------------------------
diff --git a/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolume.java b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolume.java
new file mode 100644
index 0000000..ed5c78f
--- /dev/null
+++ b/cloudsigma2/src/main/java/org/jclouds/cloudsigma2/compute/functions/ServerDriveToVolume.java
@@ -0,0 +1,52 @@
+/*
+ * 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.cloudsigma2.compute.functions;
+
+import com.google.common.base.Function;
+import org.jclouds.cloudsigma2.CloudSigma2Api;
+import org.jclouds.cloudsigma2.domain.DriveInfo;
+import org.jclouds.cloudsigma2.domain.ServerDrive;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.VolumeBuilder;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public final class ServerDriveToVolume implements Function<ServerDrive, Volume> {
+
+   private final CloudSigma2Api api;
+
+   @Inject
+   public ServerDriveToVolume(CloudSigma2Api api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   public Volume apply(ServerDrive serverDrive) {
+      VolumeBuilder builder = new VolumeBuilder();
+      DriveInfo driveInfo = api.getDriveInfo(serverDrive.getDriveUuid());
+      builder.id(driveInfo.getUuid());
+      builder.size(driveInfo.getSize().floatValue());
+      builder.durable(true);
+      builder.type(Volume.Type.NAS);
+      builder.bootDevice(serverDrive.getBootOrder() != null);
+      return builder.build();
+   }
+}