Repository: jclouds-labs
Updated Branches:
  refs/heads/2.0.x 96fca7eb9 -> f9ee0d6b9


JCLOUDS-1255 Server API migration.


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

Branch: refs/heads/2.0.x
Commit: f9ee0d6b93164e3d0a81a530627d4a4e862d3609
Parents: 96fca7e
Author: Trevor Flanagan <[email protected]>
Authored: Thu Jul 6 16:37:50 2017 +0100
Committer: Ignasi Barrera <[email protected]>
Committed: Fri Nov 24 15:07:18 2017 +0100

----------------------------------------------------------------------
 dimensiondata/pom.xml                           |   2 +-
 .../DimensionDataCloudControlApi.java           |   4 +
 .../dimensiondata/cloudcontrol/domain/Disk.java |  12 +-
 .../cloudcontrol/domain/Server.java             |  26 +--
 .../cloudcontrol/domain/State.java              |   2 +-
 .../cloudcontrol/domain/VMwareTools.java        |  59 ------
 .../domain/options/CloneServerOptions.java      | 128 +++++++++++
 .../domain/options/CreateServerOptions.java     | 200 ++++++++++++++++++
 .../cloudcontrol/features/ServerApi.java        | 211 +++++++++++++++++++
 .../predicates/NetworkDomainState.java          |  50 +++++
 .../predicates/NetworkDomainStatus.java         |  50 -----
 .../cloudcontrol/predicates/ServerState.java    |  58 +++++
 .../cloudcontrol/predicates/ServerStatus.java   |  58 +++++
 .../predicates/VMToolsRunningStatus.java        |  51 +++++
 .../cloudcontrol/predicates/VlanState.java      |  52 +++++
 .../cloudcontrol/predicates/VlanStatus.java     |  52 -----
 .../DimensionDataCloudControlResponseUtils.java |  41 +++-
 .../features/NetworkApiLiveTest.java            |  14 +-
 .../features/ServerApiLiveTest.java             | 126 +++++++++++
 .../features/ServerApiMockTest.java             | 198 +++++++++++++++++
 ...aseDimensionDataCloudControlApiLiveTest.java |   6 +
 .../src/test/resources/cloneServerResponse.json |  16 ++
 .../src/test/resources/deleteServer.json        |   9 +
 .../test/resources/deployServerResponse.json    |  14 ++
 .../src/test/resources/powerOffServer.json      |   9 +
 .../src/test/resources/rebootServer.json        |   9 +
 .../src/test/resources/reconfigureServer.json   |   9 +
 dimensiondata/src/test/resources/server.json    |  60 ++++++
 dimensiondata/src/test/resources/servers.json   |  85 ++++++++
 29 files changed, 1411 insertions(+), 200 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/pom.xml
----------------------------------------------------------------------
diff --git a/dimensiondata/pom.xml b/dimensiondata/pom.xml
index 1adfd07..d3ab6cb 100644
--- a/dimensiondata/pom.xml
+++ b/dimensiondata/pom.xml
@@ -144,7 +144,7 @@
                                         
<test.dimensiondata-cloudcontrol.credential>
                                             
${test.dimensiondata-cloudcontrol.credential}
                                         
</test.dimensiondata-cloudcontrol.credential>
-                                        
<jclouds.zones>LAB04_N2_VMWARE_1</jclouds.zones>
+                                        <jclouds.zones>EU6</jclouds.zones>
                                     </systemPropertyVariables>
                                 </configuration>
                             </execution>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
index 5967453..ef75536 100644
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
@@ -19,6 +19,7 @@ package org.jclouds.dimensiondata.cloudcontrol;
 import org.jclouds.dimensiondata.cloudcontrol.features.AccountApi;
 import org.jclouds.dimensiondata.cloudcontrol.features.InfrastructureApi;
 import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
+import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
 import org.jclouds.dimensiondata.cloudcontrol.features.ServerImageApi;
 import org.jclouds.rest.annotations.Delegate;
 
@@ -37,4 +38,7 @@ public interface DimensionDataCloudControlApi extends 
Closeable {
 
    @Delegate
    NetworkApi getNetworkApi();
+
+   @Delegate
+   ServerApi getServerApi();
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Disk.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Disk.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Disk.java
index a851fd2..575b39c 100644
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Disk.java
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Disk.java
@@ -29,9 +29,11 @@ public abstract class Disk {
    @Nullable
    public abstract String id();
 
-   public abstract int scsiId();
+   @Nullable
+   public abstract Integer scsiId();
 
-   public abstract int sizeGb();
+   @Nullable
+   public abstract Integer sizeGb();
 
    public abstract String speed();
 
@@ -39,7 +41,7 @@ public abstract class Disk {
    public abstract String state();
 
    @SerializedNames({ "id", "scsiId", "sizeGb", "speed", "state" })
-   public static Disk create(String id, int scsiId, int sizeGb, String speed, 
String state) {
+   public static Disk create(String id, Integer scsiId, Integer sizeGb, String 
speed, String state) {
       return 
builder().id(id).scsiId(scsiId).sizeGb(sizeGb).speed(speed).state(state).build();
    }
 
@@ -49,9 +51,9 @@ public abstract class Disk {
    public abstract static class Builder {
       public abstract Builder id(String id);
 
-      public abstract Builder scsiId(int scsiId);
+      public abstract Builder scsiId(Integer scsiId);
 
-      public abstract Builder sizeGb(int sizeGb);
+      public abstract Builder sizeGb(Integer sizeGb);
 
       public abstract Builder speed(String speed);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
index 79de501..4657e94 100644
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
@@ -53,7 +53,7 @@ public abstract class Server {
 
    public abstract Boolean deployed();
 
-   public abstract OperatingSystem operatingSystem();
+   public abstract Guest guest();
 
    public abstract CPU cpu();
 
@@ -69,26 +69,22 @@ public abstract class Server {
    public abstract List<Object> softwareLabels();
 
    @Nullable
-   public abstract VMwareTools vmwareTools();
-
-   @Nullable
    public abstract Progress progress();
 
    @Nullable
    public abstract VirtualHardware virtualHardware();
 
    @SerializedNames({ "id", "name", "description", "datacenterId", "state", 
"sourceImageId", "createTime", "started",
-         "deployed", "operatingSystem", "cpu", "memoryGb", "disk", 
"networkInfo", "softwareLabel", "vmwareTools",
-         "progress", "virtualHardware" })
+         "deployed", "guest", "cpu", "memoryGb", "disk", "networkInfo", 
"softwareLabel", "progress",
+         "virtualHardware" })
    public static Server create(String id, String name, String description, 
String datacenterId, State state,
-         String sourceImageId, Date createTime, Boolean started, Boolean 
deployed, OperatingSystem operatingSystem,
-         CPU cpu, int memoryGb, List<Disk> disks, NetworkInfo networkInfo, 
List<Object> softwareLabels,
-         VMwareTools vmwareTools, Progress progress, VirtualHardware 
virtualHardware) {
+         String sourceImageId, Date createTime, Boolean started, Boolean 
deployed, Guest guest, CPU cpu, int memoryGb,
+         List<Disk> disks, NetworkInfo networkInfo, List<Object> 
softwareLabels, Progress progress,
+         VirtualHardware virtualHardware) {
       return 
builder().id(id).name(name).datacenterId(datacenterId).description(description).state(state)
-            
.sourceImageId(sourceImageId).createTime(createTime).started(started).deployed(deployed)
-            
.operatingSystem(operatingSystem).cpu(cpu).memoryGb(memoryGb).disks(disks).networkInfo(networkInfo)
-            
.softwareLabels(softwareLabels).vmwareTools(vmwareTools).progress(progress).virtualHardware(virtualHardware)
-            .build();
+            
.sourceImageId(sourceImageId).createTime(createTime).started(started).deployed(deployed).guest(guest)
+            
.cpu(cpu).memoryGb(memoryGb).disks(disks).networkInfo(networkInfo).softwareLabels(softwareLabels)
+            .progress(progress).virtualHardware(virtualHardware).build();
    }
 
    public abstract Builder toBuilder();
@@ -113,7 +109,7 @@ public abstract class Server {
 
       public abstract Builder deployed(Boolean deployed);
 
-      public abstract Builder operatingSystem(OperatingSystem operatingSystem);
+      public abstract Builder guest(Guest guest);
 
       public abstract Builder cpu(CPU cpu);
 
@@ -125,8 +121,6 @@ public abstract class Server {
 
       public abstract Builder softwareLabels(List<Object> softwareLabels);
 
-      public abstract Builder vmwareTools(VMwareTools vmwareTools);
-
       public abstract Builder progress(Progress progress);
 
       public abstract Builder virtualHardware(VirtualHardware virtualHardware);

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
index e832264..37ff17d 100644
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
@@ -22,7 +22,7 @@ import static 
com.google.common.base.Preconditions.checkNotNull;
 
 public enum State {
 
-   NORMAL, FAILED_ADD, FAILED_CHANGE, FAILED_DELETE, PENDING_DELETE, DELETED, 
UNRECOGNIZED;
+   NORMAL, FAILED_ADD, FAILED_CHANGE, FAILED_DELETE, PENDING_DELETE, DELETED, 
UNRECOGNIZED, PENDING_CHANGE;
 
    @Override
    public String toString() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/VMwareTools.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/VMwareTools.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/VMwareTools.java
deleted file mode 100644
index 99306c1..0000000
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/VMwareTools.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.dimensiondata.cloudcontrol.domain;
-
-import com.google.auto.value.AutoValue;
-import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.json.SerializedNames;
-
-@AutoValue
-public abstract class VMwareTools {
-
-   VMwareTools() {
-   }
-
-   @Nullable
-   public abstract String versionStatus();
-
-   @Nullable
-   public abstract String runningStatus();
-
-   @Nullable
-   public abstract Integer apiVersion();
-
-   @SerializedNames({ "versionStatus", "runningStatus", "apiVersion" })
-   public static VMwareTools create(String versionStatus, String 
runningStatus, Integer apiVersion) {
-      return 
builder().versionStatus(versionStatus).runningStatus(runningStatus).apiVersion(apiVersion).build();
-   }
-
-   public abstract Builder toBuilder();
-
-   @AutoValue.Builder
-   public abstract static class Builder {
-      public abstract Builder versionStatus(String versionStatus);
-
-      public abstract Builder runningStatus(String runningStatus);
-
-      public abstract Builder apiVersion(Integer apiVersion);
-
-      public abstract VMwareTools build();
-   }
-
-   public static Builder builder() {
-      return new AutoValue_VMwareTools.Builder();
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CloneServerOptions.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CloneServerOptions.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CloneServerOptions.java
new file mode 100644
index 0000000..d2a10df
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CloneServerOptions.java
@@ -0,0 +1,128 @@
+/*
+ * 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.dimensiondata.cloudcontrol.domain.options;
+
+import com.google.auto.value.AutoValue;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class CloneServerOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   private final String description;
+   private final String clusterId;
+   private final boolean guestOsCustomization;
+
+   public CloneServerOptions(String description, String clusterId, boolean 
guestOsCustomization) {
+      this.description = description;
+      this.clusterId = clusterId;
+      this.guestOsCustomization = guestOsCustomization;
+   }
+
+   @AutoValue
+   abstract static class CloneServerRequest {
+
+      abstract String id();
+
+      abstract String imageName();
+
+      @Nullable
+      abstract String description();
+
+      @Nullable
+      abstract String clusterId();
+
+      abstract boolean guestOsCustomization();
+
+      @SerializedNames({ "id", "imageName", "description", "clusterId", 
"guestOsCustomization" })
+      static CloneServerRequest create(String id, String imageName, String 
description, String clusterId,
+            Boolean guestOsCustomization) {
+         return new AutoValue_CloneServerOptions_CloneServerRequest(id, 
imageName, description, clusterId,
+               guestOsCustomization);
+      }
+
+      CloneServerRequest() {
+      }
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, 
Object> postParams) {
+      CloneServerRequest cloneServer = CloneServerRequest
+            .create(checkNotNull(postParams.get("id"), "id parameter not 
present").toString(),
+                  checkNotNull(postParams.get("imageName"), "imageName 
parameter not present").toString().toString(),
+                  description, clusterId, guestOsCustomization);
+
+      return bindToRequest(request, cloneServer);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+
+   public String getDescription() {
+      return description;
+   }
+
+   public String getClusterId() {
+      return clusterId;
+   }
+
+   public boolean isGuestOsCustomization() {
+      return guestOsCustomization;
+   }
+
+   public static class Builder {
+      private String description;
+      private String clusterId;
+      private boolean guestOsCustomization = false;
+
+      public Builder description(String description) {
+         this.description = description;
+         return this;
+      }
+
+      public Builder clusterId(String clusterId) {
+         this.clusterId = clusterId;
+         return this;
+      }
+
+      public Builder guestOsCustomization(boolean guestOsCustomization) {
+         this.guestOsCustomization = guestOsCustomization;
+         return this;
+      }
+
+      public CloneServerOptions build() {
+         return new CloneServerOptions(description, clusterId, 
guestOsCustomization);
+      }
+   }
+
+   public static CloneServerOptions.Builder builder() {
+      return new CloneServerOptions.Builder();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CreateServerOptions.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CreateServerOptions.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CreateServerOptions.java
new file mode 100644
index 0000000..33e2fa1
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/options/CreateServerOptions.java
@@ -0,0 +1,200 @@
+/*
+ * 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.dimensiondata.cloudcontrol.domain.options;
+
+import com.google.auto.value.AutoValue;
+import com.google.inject.Inject;
+import org.jclouds.dimensiondata.cloudcontrol.domain.CPU;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Disk;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkInfo;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Options to customize server creation.
+ */
+public class CreateServerOptions implements MapBinder {
+
+   @Inject
+   private BindToJsonPayload jsonBinder;
+
+   private String description;
+   private CPU cpu;
+   private Integer memoryGb;
+   private String primaryDns;
+   private String secondaryDns;
+   private String microsoftTimeZone;
+
+   public CreateServerOptions() {
+
+   }
+
+   CreateServerOptions(String description, CPU cpu, Integer memoryGb, String 
primaryDns, String secondaryDns,
+         String microsoftTimeZone) {
+      this.description = description;
+      this.cpu = cpu;
+      this.memoryGb = memoryGb;
+      this.primaryDns = primaryDns;
+      this.secondaryDns = secondaryDns;
+      this.microsoftTimeZone = microsoftTimeZone;
+   }
+
+   @AutoValue
+   abstract static class ServerRequest {
+
+      abstract String name();
+
+      abstract String imageId();
+
+      abstract Boolean start();
+
+      abstract NetworkInfo networkInfo();
+
+      abstract List<Disk> disks();
+
+      @Nullable
+      abstract String administratorPassword();
+
+      @Nullable
+      abstract String description();
+
+      @Nullable
+      abstract CPU cpu();
+
+      @Nullable
+      abstract Integer memoryGb();
+
+      @Nullable
+      abstract String primaryDns();
+
+      @Nullable
+      abstract String secondaryDns();
+
+      @Nullable
+      abstract String microsoftTimeZone();
+
+      @SerializedNames({ "name", "imageId", "start", "networkInfo", "disk", 
"administratorPassword", "description",
+            "cpu", "memoryGb", "primaryDns", "secondaryDns", 
"microsoftTimeZone" })
+      static ServerRequest create(String name, String imageId, Boolean start, 
NetworkInfo networkInfo, List<Disk> disks,
+            String administratorPassword, String description, CPU cpu, Integer 
memoryGb, String primaryDns,
+            String secondaryDns, String microsoftTimeZone) {
+         return new AutoValue_CreateServerOptions_ServerRequest(name, imageId, 
start, networkInfo, disks,
+               administratorPassword, description, cpu, memoryGb, primaryDns, 
secondaryDns, microsoftTimeZone);
+      }
+
+      ServerRequest() {
+      }
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, 
Object> postParams) {
+      ServerRequest Server = ServerRequest
+            .create(checkNotNull(postParams.get("name"), "name parameter not 
present").toString(),
+                  checkNotNull(postParams.get("imageId"), "imageId parameter 
not present").toString(),
+                  Boolean.valueOf(checkNotNull(postParams.get("start"), "start 
parameter not present").toString()),
+                  (NetworkInfo) checkNotNull(postParams.get("networkInfo"), 
"image parameter not present"),
+                  (List<Disk>) checkNotNull(postParams.get("disk"), "disk 
parameter not present"),
+                  (String) postParams.get("administratorPassword"), 
description, cpu, memoryGb, primaryDns,
+                  secondaryDns, microsoftTimeZone);
+
+      return bindToRequest(request, Server);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return jsonBinder.bindToRequest(request, input);
+   }
+
+   public String getDescription() {
+      return description;
+   }
+
+   public CPU getCpu() {
+      return cpu;
+   }
+
+   public Integer getMemoryGb() {
+      return memoryGb;
+   }
+
+   public String getPrimaryDns() {
+      return primaryDns;
+   }
+
+   public String getSecondaryDns() {
+      return secondaryDns;
+   }
+
+   public String getMicrosoftTimeZone() {
+      return microsoftTimeZone;
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder {
+      private String description;
+      private CPU cpu;
+      private Integer memoryGb;
+      private String primaryDns;
+      private String secondaryDns;
+      private String microsoftTimeZone;
+
+      public Builder description(String description) {
+         this.description = description;
+         return this;
+      }
+
+      public Builder cpu(CPU cpu) {
+         this.cpu = cpu;
+         return this;
+      }
+
+      public Builder memoryGb(Integer memoryGb) {
+         this.memoryGb = memoryGb;
+         return this;
+      }
+
+      public Builder primaryDns(String primaryDns) {
+         this.primaryDns = primaryDns;
+         return this;
+      }
+
+      public Builder secondaryDns(String secondaryDns) {
+         this.secondaryDns = secondaryDns;
+         return this;
+      }
+
+      public Builder microsoftTimeZone(String microsoftTimeZone) {
+         this.microsoftTimeZone = microsoftTimeZone;
+         return this;
+      }
+
+      public CreateServerOptions build() {
+         return new CreateServerOptions(description, cpu, memoryGb, 
primaryDns, secondaryDns, microsoftTimeZone);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApi.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApi.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApi.java
new file mode 100644
index 0000000..5ec225c
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApi.java
@@ -0,0 +1,211 @@
+/*
+ * 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.dimensiondata.cloudcontrol.features;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.Fallbacks;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Disk;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkInfo;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PaginatedCollection;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Servers;
+import 
org.jclouds.dimensiondata.cloudcontrol.domain.options.CloneServerOptions;
+import 
org.jclouds.dimensiondata.cloudcontrol.domain.options.CreateServerOptions;
+import org.jclouds.dimensiondata.cloudcontrol.filters.DatacenterIdFilter;
+import org.jclouds.dimensiondata.cloudcontrol.filters.OrganisationIdFilter;
+import org.jclouds.dimensiondata.cloudcontrol.options.PaginationOptions;
+import org.jclouds.dimensiondata.cloudcontrol.utils.ParseResponse;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.Json;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@RequestFilters({ BasicAuthentication.class, OrganisationIdFilter.class })
+@Consumes(MediaType.APPLICATION_JSON)
+@Path("/{jclouds.api-version}/server")
+public interface ServerApi {
+
+   @Named("server:list")
+   @GET
+   @Path("/server")
+   @ResponseParser(ParseServers.class)
+   @Fallback(Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404.class)
+   PaginatedCollection<Server> listServers(PaginationOptions options);
+
+   @Named("server:list")
+   @GET
+   @Path("/server")
+   @Transform(ParseServers.ToPagedIterable.class)
+   @ResponseParser(ParseServers.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   @RequestFilters({ DatacenterIdFilter.class })
+   PagedIterable<Server> listServers();
+
+   @Named("server:get")
+   @GET
+   @Path("/server/{id}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   Server getServer(@PathParam("id") String id);
+
+   @Named("server:deploy")
+   @POST
+   @Path("/deployServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @ResponseParser(ServerId.class)
+   String deployServer(@PayloadParam("name") String name, 
@PayloadParam("imageId") String imageId,
+         @PayloadParam("start") Boolean start, @PayloadParam("networkInfo") 
NetworkInfo networkInfo,
+         @PayloadParam("administratorPassword") String administratorPassword);
+
+   @Named("server:deploy")
+   @POST
+   @Path("/deployServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(CreateServerOptions.class)
+   @ResponseParser(ServerId.class)
+   String deployServer(@PayloadParam("name") String name, 
@PayloadParam("imageId") String imageId,
+         @PayloadParam("start") Boolean start, @PayloadParam("networkInfo") 
NetworkInfo networkInfo,
+         @Nullable @PayloadParam("administratorPassword") String 
administratorPassword,
+         @Nullable @PayloadParam("disk") List<Disk> disks, @Nullable 
CreateServerOptions options);
+
+   @Named("server:delete")
+   @POST
+   @Path("/deleteServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   @MapBinder(BindToJsonPayload.class)
+   void deleteServer(@PayloadParam("id") String id);
+
+   @Named("server:powerOff")
+   @POST
+   @Path("/powerOffServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   void powerOffServer(@PayloadParam("id") String id);
+
+   @Named("server:reboot")
+   @POST
+   @Path("/rebootServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   void rebootServer(@PayloadParam("id") String id);
+
+   @Named("server:reconfigure")
+   @POST
+   @Path("/reconfigureServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   void reconfigureServer(@PayloadParam("id") String id, 
@PayloadParam("cpuCount") int cpuCount,
+         @PayloadParam("cpuSpeed") String cpuSpeed, 
@PayloadParam("coresPerSocket") int coresPerSocket);
+
+   @Named("server:clone")
+   @POST
+   @Path("/cloneServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(CloneServerOptions.class)
+   @ResponseParser(ImageId.class)
+   String cloneServer(@PayloadParam("id") String id, 
@PayloadParam("imageName") String imageName,
+         CloneServerOptions cloneServerOptions);
+
+   @Named("server:start")
+   @POST
+   @Path("/startServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   void startServer(@PayloadParam("id") String id);
+
+   @Named("server:shutdown")
+   @POST
+   @Path("/shutdownServer")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   void shutdownServer(@PayloadParam("id") String id);
+
+   @Singleton
+   final class ParseServers extends ParseJson<Servers> {
+
+      @Inject
+      ParseServers(Json json) {
+         super(json, TypeLiteral.get(Servers.class));
+      }
+
+      static class ToPagedIterable extends Arg0ToPagedIterable<Server, 
ToPagedIterable> {
+
+         private DimensionDataCloudControlApi api;
+
+         @Inject
+         ToPagedIterable(DimensionDataCloudControlApi api) {
+            this.api = api;
+         }
+
+         @Override
+         protected Function<Object, IterableWithMarker<Server>> 
markerToNextForArg0(Optional<Object> arg0) {
+            return new Function<Object, IterableWithMarker<Server>>() {
+               @Override
+               public IterableWithMarker<Server> apply(Object input) {
+                  PaginationOptions paginationOptions = 
PaginationOptions.class.cast(input);
+                  return api.getServerApi().listServers(paginationOptions);
+               }
+            };
+         }
+      }
+
+   }
+
+   @Singleton
+   final class ServerId extends ParseResponse {
+
+      @Inject
+      ServerId(Json json) {
+         super(json, "serverId");
+      }
+   }
+
+   @Singleton
+   final class ImageId extends ParseResponse {
+
+      @Inject
+      ImageId(Json json) {
+         super(json, "imageId");
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainState.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainState.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainState.java
new file mode 100644
index 0000000..5741b32
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainState.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class NetworkDomainState implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final State state;
+   private final NetworkApi networkApi;
+
+   public NetworkDomainState(NetworkApi networkApi, State state) {
+      this.networkApi = networkApi;
+      this.state = state;
+   }
+
+   @Override
+   public boolean apply(String networkDomainId) {
+      checkNotNull(networkDomainId, "networkDomainId");
+      logger.trace("looking for state on network domain %s", networkDomainId);
+      final NetworkDomain networkDomain = 
networkApi.getNetworkDomain(networkDomainId);
+      final boolean isDeleted = networkDomain == null && state == 
State.DELETED;
+      return isDeleted || (networkDomain != null && networkDomain.state() == 
state);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java
deleted file mode 100644
index 94882d1..0000000
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.dimensiondata.cloudcontrol.predicates;
-
-import com.google.common.base.Predicate;
-import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
-import org.jclouds.dimensiondata.cloudcontrol.domain.State;
-import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
-import org.jclouds.logging.Logger;
-
-import javax.annotation.Resource;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-public class NetworkDomainStatus implements Predicate<String> {
-
-   @Resource
-   protected Logger logger = Logger.NULL;
-
-   private final State state;
-   private final NetworkApi networkApi;
-
-   public NetworkDomainStatus(NetworkApi networkApi, State state) {
-      this.networkApi = networkApi;
-      this.state = state;
-   }
-
-   @Override
-   public boolean apply(String networkDomainId) {
-      checkNotNull(networkDomainId, "networkDomainId");
-      logger.trace("looking for state on network domain %s", networkDomainId);
-      final NetworkDomain networkDomain = 
networkApi.getNetworkDomain(networkDomainId);
-      final boolean isDeleted = networkDomain == null && state == 
State.DELETED;
-      return isDeleted || (networkDomain != null && networkDomain.state() == 
state);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerState.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerState.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerState.java
new file mode 100644
index 0000000..232a30b
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerState.java
@@ -0,0 +1,58 @@
+/*
+ * 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.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import java.text.MessageFormat;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class ServerState implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+   private final ServerApi api;
+   private final State state;
+
+   public ServerState(ServerApi api, State state) {
+      this.api = api;
+      this.state = state;
+   }
+
+   @Override
+   public boolean apply(String serverId) {
+      checkNotNull(serverId, "serverId");
+      logger.trace("looking for state on Server %s", serverId);
+      final Server server = api.getServer(serverId);
+
+      if (server == null && state == State.DELETED) {
+         return true;
+      }
+
+      if (server.state().isFailed()) {
+         throw new IllegalStateException(MessageFormat.format("Server {0} is 
in FAILED state", server.id()));
+      } else {
+         return server.state().equals(state);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerStatus.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerStatus.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerStatus.java
new file mode 100644
index 0000000..96e6f4f
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/ServerStatus.java
@@ -0,0 +1,58 @@
+/*
+ * 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.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
+import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import java.text.MessageFormat;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class ServerStatus implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+   private final ServerApi api;
+   private final boolean started;
+   private final boolean deployed;
+
+   public ServerStatus(ServerApi api, boolean started, boolean deployed) {
+      this.api = api;
+      this.started = started;
+      this.deployed = deployed;
+   }
+
+   @Override
+   public boolean apply(String serverId) {
+      checkNotNull(serverId, "serverId");
+      logger.trace("looking for state on Server %s", serverId);
+      final Server server = api.getServer(serverId);
+
+      // perhaps request isn't available, yet
+      if (server == null)
+         return false;
+      logger.trace("%s: looking for server %s deployed: currently: %s", 
server, server.state());
+      if (server.state().isFailed()) {
+         throw new IllegalStateException(MessageFormat.format("Server {0} is 
in FAILED state", server.id()));
+      }
+      return server.started() == started && server.deployed() == deployed;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VMToolsRunningStatus.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VMToolsRunningStatus.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VMToolsRunningStatus.java
new file mode 100644
index 0000000..2875a0e
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VMToolsRunningStatus.java
@@ -0,0 +1,51 @@
+/*
+ * 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.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
+import org.jclouds.dimensiondata.cloudcontrol.domain.VmTools;
+import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import java.text.MessageFormat;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class VMToolsRunningStatus implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+   private final ServerApi api;
+
+   public VMToolsRunningStatus(ServerApi api) {
+      this.api = api;
+   }
+
+   @Override
+   public boolean apply(String serverId) {
+      checkNotNull(serverId, "serverId");
+      logger.trace("looking for state on Server %s", serverId);
+      final Server server = api.getServer(serverId);
+      if (server == null) {
+         throw new IllegalStateException(MessageFormat.format("Server {0} is 
not found", serverId));
+      }
+      final VmTools vmTools = server.guest().vmTools();
+      return vmTools != null && 
vmTools.runningStatus().equals(VmTools.RunningStatus.RUNNING);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanState.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanState.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanState.java
new file mode 100644
index 0000000..119e2d6
--- /dev/null
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanState.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.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
+import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class VlanState implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final State state;
+   private final NetworkApi networkApi;
+
+   public VlanState(NetworkApi networkApi, State state) {
+      this.networkApi = networkApi;
+      this.state = state;
+   }
+
+   @Override
+   public boolean apply(String vlanId) {
+      checkNotNull(vlanId, "vlanId");
+      logger.trace("looking for state on vlan %s", vlanId);
+      final Vlan vlan = networkApi.getVlan(vlanId);
+      final boolean isDeleted = (vlan == null) && (state == State.DELETED);
+      return isDeleted || ((vlan != null) && vlan.state() == state);
+
+   }
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
deleted file mode 100644
index 79aa75a..0000000
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.dimensiondata.cloudcontrol.predicates;
-
-import com.google.common.base.Predicate;
-import org.jclouds.dimensiondata.cloudcontrol.domain.State;
-import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
-import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
-import org.jclouds.logging.Logger;
-
-import javax.annotation.Resource;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-public class VlanStatus implements Predicate<String> {
-
-   @Resource
-   protected Logger logger = Logger.NULL;
-
-   private final State state;
-   private final NetworkApi networkApi;
-
-   public VlanStatus(NetworkApi networkApi, State state) {
-      this.networkApi = networkApi;
-      this.state = state;
-   }
-
-   @Override
-   public boolean apply(String vlanId) {
-      checkNotNull(vlanId, "vlanId");
-      logger.trace("looking for state on vlan %s", vlanId);
-      final Vlan vlan = networkApi.getVlan(vlanId);
-      final boolean isDeleted = (vlan == null) && (state == State.DELETED);
-      return isDeleted || ((vlan != null) && vlan.state() == state);
-
-   }
-}
-

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
index 2c80d7c..a339d5d 100644
--- 
a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
+++ 
b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
@@ -18,8 +18,12 @@ package org.jclouds.dimensiondata.cloudcontrol.utils;
 
 import org.jclouds.dimensiondata.cloudcontrol.domain.State;
 import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
-import org.jclouds.dimensiondata.cloudcontrol.predicates.NetworkDomainStatus;
-import org.jclouds.dimensiondata.cloudcontrol.predicates.VlanStatus;
+import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.NetworkDomainState;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.ServerState;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.ServerStatus;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.VMToolsRunningStatus;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.VlanState;
 
 import static org.jclouds.util.Predicates2.retry;
 
@@ -33,20 +37,41 @@ public class DimensionDataCloudControlResponseUtils {
       return String.format("fw.%s", convertServerId(serverId));
    }
 
-   public static void waitForNetworkDomainStatus(NetworkApi api, String 
networkDomainId, State state,
-         long timeoutMillis, String message) {
-      boolean isNetworkDomainInState = retry(new NetworkDomainStatus(api, 
state), timeoutMillis).apply(networkDomainId);
+   public static void waitForNetworkDomainState(NetworkApi api, String 
networkDomainId, State state, long timeoutMillis,
+         String message) {
+      boolean isNetworkDomainInState = retry(new NetworkDomainState(api, 
state), timeoutMillis).apply(networkDomainId);
       if (!isNetworkDomainInState) {
          throw new IllegalStateException(message);
       }
    }
 
-   public static void waitForVlanStatus(NetworkApi api, String vlanId, State 
state, long timeoutMillis,
+   public static void waitForVlanState(NetworkApi api, String vlanId, State 
state, long timeoutMillis, String message) {
+      boolean isVlanInState = retry(new VlanState(api, state), 
timeoutMillis).apply(vlanId);
+      if (!isVlanInState) {
+         throw new IllegalStateException(message);
+      }
+   }
+
+   public static void waitForServerState(ServerApi api, String serverId, State 
state, long timeoutMillis,
          String message) {
-      boolean isVlanInstate = retry(new VlanStatus(api, state), 
timeoutMillis).apply(vlanId);
-      if (!isVlanInstate) {
+      boolean isServerInState = retry(new ServerState(api, state), 
timeoutMillis).apply(serverId);
+      if (!isServerInState) {
+         throw new IllegalStateException(message);
+      }
+   }
+
+   public static void waitForServerStatus(ServerApi api, String serverId, 
boolean started, boolean deployed,
+         long timeoutMillis, String message) {
+      boolean serverHasStatus = retry(new ServerStatus(api, started, 
deployed), timeoutMillis).apply(serverId);
+      if (!serverHasStatus) {
          throw new IllegalStateException(message);
       }
    }
 
+   public static void waitForVmToolsRunning(ServerApi api, String serverId, 
long timeoutMillis, String message) {
+      boolean vmwareToolsRunning = retry(new VMToolsRunningStatus(api), 
timeoutMillis).apply(serverId);
+      if (!vmwareToolsRunning) {
+         throw new IllegalStateException(message);
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
index 424eecc..735f1bc 100644
--- 
a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
+++ 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
@@ -33,15 +33,13 @@ import java.util.List;
 import static 
org.jclouds.dimensiondata.cloudcontrol.features.NetworkApiMockTest.DEFAULT_ACTION;
 import static 
org.jclouds.dimensiondata.cloudcontrol.features.NetworkApiMockTest.DEFAULT_IP_VERSION;
 import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.generateFirewallRuleName;
-import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForNetworkDomainStatus;
-import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForVlanStatus;
+import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForNetworkDomainState;
+import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForVlanState;
 import static org.testng.Assert.assertNotNull;
 
 @Test(groups = "live", testName = "NetworkApiLiveTest", singleThreaded = true)
 public class NetworkApiLiveTest extends 
BaseDimensionDataCloudControlApiLiveTest {
 
-   private static final String DATACENTER = "NW20-EPC-LAB04";
-
    private static final String DEFAULT_PRIVATE_IPV4_BASE_ADDRESS = "10.0.0.0";
    private static final Integer DEFAULT_PRIVATE_IPV4_PREFIX_SIZE = 24;
    private static final String DEFAULT_PROTOCOL = "TCP";
@@ -79,7 +77,7 @@ public class NetworkApiLiveTest extends 
BaseDimensionDataCloudControlApiLiveTest
             NetworkApiLiveTest.class.getSimpleName(), 
DEFAULT_PRIVATE_IPV4_BASE_ADDRESS,
             DEFAULT_PRIVATE_IPV4_PREFIX_SIZE);
       assertNotNull(vlanId);
-      waitForVlanStatus(api(), vlanId, State.NORMAL, 30 * 60 * 1000, "Error - 
unable to deploy vlan");
+      waitForVlanState(api(), vlanId, State.NORMAL, 30 * 60 * 1000, "Error - 
unable to deploy vlan");
    }
 
    @Test
@@ -88,7 +86,7 @@ public class NetworkApiLiveTest extends 
BaseDimensionDataCloudControlApiLiveTest
       networkDomainId = api()
             .deployNetworkDomain(DATACENTER, networkDomainName, 
NetworkApiLiveTest.class.getSimpleName(), "ESSENTIALS");
       assertNotNull(networkDomainId);
-      waitForNetworkDomainStatus(api(), networkDomainId, State.NORMAL, 30 * 60 
* 1000,
+      waitForNetworkDomainState(api(), networkDomainId, State.NORMAL, 30 * 60 
* 1000,
             "Error - unable to deploy network domain");
    }
 
@@ -110,11 +108,11 @@ public class NetworkApiLiveTest extends 
BaseDimensionDataCloudControlApiLiveTest
       }
       if (vlanId != null) {
          api().deleteVlan(vlanId);
-         waitForVlanStatus(api(), vlanId, State.DELETED, 30 * 60 * 1000, 
"Error deleting vlan");
+         waitForVlanState(api(), vlanId, State.DELETED, 30 * 60 * 1000, "Error 
deleting vlan");
       }
       if (networkDomainId != null) {
          api().deleteNetworkDomain(networkDomainId);
-         waitForNetworkDomainStatus(api(), networkDomainId, State.DELETED, 30 
* 60 * 1000,
+         waitForNetworkDomainState(api(), networkDomainId, State.DELETED, 30 * 
60 * 1000,
                "Error deleting network domain");
       }
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiLiveTest.java
 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiLiveTest.java
new file mode 100644
index 0000000..c8de243
--- /dev/null
+++ 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiLiveTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.dimensiondata.cloudcontrol.features;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.jclouds.dimensiondata.cloudcontrol.domain.CpuSpeed;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Disk;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NIC;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkInfo;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import 
org.jclouds.dimensiondata.cloudcontrol.domain.options.CloneServerOptions;
+import 
org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlApiLiveTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForServerState;
+import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForServerStatus;
+import static 
org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForVmToolsRunning;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "live", testName = "ServerApiLiveTest", singleThreaded = true)
+public class ServerApiLiveTest extends 
BaseDimensionDataCloudControlApiLiveTest {
+
+   private String serverId;
+   private String cloneImageId;
+   private final String deployedServerName = 
ServerApiLiveTest.class.getSimpleName() + System.currentTimeMillis();
+
+   @Test(dependsOnMethods = "testDeployAndStartServer")
+   public void testListServers() {
+      List<Server> servers = api().listServers().concat().toList();
+      assertNotNull(servers);
+      boolean foundDeployedServer = false;
+      for (Server s : servers) {
+         assertNotNull(s);
+         if (s.name().equals(deployedServerName)) {
+            foundDeployedServer = true;
+         }
+      }
+      assertTrue(foundDeployedServer, "Did not find deployed server " + 
deployedServerName);
+   }
+
+   @Test
+   public void testDeployAndStartServer() {
+      Boolean started = Boolean.TRUE;
+      NetworkInfo networkInfo = NetworkInfo
+            .create(NETWORK_DOMAIN_ID, NIC.builder().vlanId(VLAN_ID).build(), 
Lists.<NIC>newArrayList());
+      List<Disk> disks = 
ImmutableList.of(Disk.builder().scsiId(0).speed("STANDARD").build());
+      serverId = api().deployServer(deployedServerName, IMAGE_ID, started, 
networkInfo, "P$$ssWwrrdGoDd!", disks, null);
+      assertNotNull(serverId);
+      waitForServerStatus(api(), serverId, true, true, 30 * 60 * 1000, 
"Error");
+      waitForServerState(api(), serverId, State.NORMAL, 30 * 60 * 1000, 
"Error");
+   }
+
+   @Test(dependsOnMethods = "testDeployAndStartServer")
+   public void testReconfigureServer() {
+      api().reconfigureServer(serverId, 4, CpuSpeed.HIGHPERFORMANCE.name(), 1);
+      waitForServerState(api(), serverId, State.NORMAL, 30 * 60 * 1000, 
"Error");
+   }
+
+   @Test(dependsOnMethods = "testDeployAndStartServer")
+   public void testRebootServer() {
+      api().rebootServer(serverId);
+      waitForServerState(api(), serverId, State.NORMAL, 30 * 60 * 1000, 
"Error");
+      waitForVmToolsRunning(api(), serverId, 30 * 60 * 1000, "Error");
+   }
+
+   @Test(dependsOnMethods = "testRebootServer")
+   public void testPowerOffServer() {
+      api().powerOffServer(serverId);
+      waitForServerStatus(api(), serverId, false, true, 30 * 60 * 1000, 
"Error");
+   }
+
+   @Test(dependsOnMethods = "testPowerOffServer")
+   public void testStartServer() {
+      api().startServer(serverId);
+      waitForServerStatus(api(), serverId, true, true, 30 * 60 * 1000, 
"Error");
+      waitForVmToolsRunning(api(), serverId, 30 * 60 * 1000, "Error");
+   }
+
+   @Test(dependsOnMethods = "testStartServer")
+   public void testShutdownServer() {
+      api().shutdownServer(serverId);
+      waitForServerStatus(api(), serverId, false, true, 30 * 60 * 1000, 
"Error");
+   }
+
+   @Test(dependsOnMethods = "testShutdownServer")
+   public void testCloneServer() {
+      CloneServerOptions options = 
CloneServerOptions.builder().clusterId("").description("")
+            .guestOsCustomization(false).build();
+      cloneImageId = api().cloneServer(serverId, "ServerApiLiveTest-" + 
System.currentTimeMillis(), options);
+      assertNotNull(cloneImageId);
+      waitForServerState(api(), serverId, State.NORMAL, 30 * 60 * 1000, 
"Error");
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void testDeleteServer() {
+      if (serverId != null) {
+         api().deleteServer(serverId);
+         waitForServerState(api(), serverId, State.DELETED, 30 * 60 * 1000, 
"Error");
+      }
+   }
+
+   private ServerApi api() {
+      return api.getServerApi();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiMockTest.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiMockTest.java
 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiMockTest.java
new file mode 100644
index 0000000..f1db2d4
--- /dev/null
+++ 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/ServerApiMockTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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.dimensiondata.cloudcontrol.features;
+
+import com.google.common.collect.Lists;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+import org.jclouds.dimensiondata.cloudcontrol.domain.CPU;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Disk;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NIC;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkInfo;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
+import 
org.jclouds.dimensiondata.cloudcontrol.domain.options.CloneServerOptions;
+import 
org.jclouds.dimensiondata.cloudcontrol.domain.options.CreateServerOptions;
+import 
org.jclouds.dimensiondata.cloudcontrol.internal.BaseAccountAwareCloudControlMockTest;
+import org.jclouds.http.Uris;
+import org.jclouds.location.suppliers.ZoneIdsSupplier;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.HttpMethod;
+import java.util.List;
+import java.util.Set;
+
+import static javax.ws.rs.HttpMethod.GET;
+import static javax.ws.rs.HttpMethod.POST;
+import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Mock tests for the {@link ServerApi} class.
+ */
+@Test(groups = "unit", testName = "ServerApiMockTest", singleThreaded = true)
+public class ServerApiMockTest extends BaseAccountAwareCloudControlMockTest {
+
+   public void testDeployServerReturnsUnexpectedError() throws 
InterruptedException {
+      server.enqueue(responseUnexpectedError());
+
+      NetworkInfo networkInfo = NetworkInfo
+            .create("networkDomainId", NIC.builder().vlanId("vlanId").build(), 
Lists.<NIC>newArrayList());
+      try {
+         serverApi().deployServer(ServerApiMockTest.class.getSimpleName(), 
"imageId", true, networkInfo,
+               "administratorPassword");
+         failBecauseExceptionWasNotThrown(ResourceNotFoundException.class);
+      } catch (ResourceNotFoundException e) {
+         assertNotNull(e);
+         assertSent(POST, 
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/deployServer");
+      }
+   }
+
+   public void testDeployServerWithSpecificCpu() throws InterruptedException {
+      server.enqueue(jsonResponse("/deployServerResponse.json"));
+
+      NetworkInfo networkInfo = NetworkInfo
+            .create("networkDomainId", NIC.builder().vlanId("vlanId").build(), 
Lists.<NIC>newArrayList());
+
+      CreateServerOptions createServerOptions = CreateServerOptions.builder()
+            
.cpu(CPU.builder().count(1).speed("HIGHPERFORMANCE").coresPerSocket(2).build()).build();
+      final String serverId = serverApi()
+            .deployServer(ServerApiMockTest.class.getSimpleName(), "imageId", 
true, networkInfo,
+                  "administratorPassword", Lists.<Disk>newArrayList(), 
createServerOptions);
+      assertEquals(serverId, "7b62aae5-bdbe-4595-b58d-c78f95db2a7f");
+      RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/deployServer");
+      assertBodyContains(recordedRequest, 
"\"cpu\":{\"count\":1,\"speed\":\"HIGHPERFORMANCE\",\"coresPerSocket\":2}");
+   }
+
+   public void testClone() throws Exception {
+      server.enqueue(jsonResponse("/cloneServerResponse.json"));
+      CloneServerOptions cloneServerOptions = 
CloneServerOptions.builder().description("description")
+            .clusterId("EU6-02").guestOsCustomization(true).build();
+      final String imageId = serverApi()
+            .cloneServer("9ed47330-5561-11e5-8c14-b8ca3a5d9ef8", 
"serverNewImageName", cloneServerOptions);
+      assertEquals(imageId, "3389ffe8-c3fc-11e3-b29c-001517c4643e");
+
+      RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/cloneServer");
+
+      assertBodyContains(recordedRequest,
+            
"{\"id\":\"9ed47330-5561-11e5-8c14-b8ca3a5d9ef8\",\"imageName\":\"serverNewImageName\","
+                  + 
"\"description\":\"description\",\"clusterId\":\"EU6-02\",\"guestOsCustomization\":true}");
+   }
+
+   public void testListServers() throws Exception {
+      server.enqueue(jsonResponse("/servers.json"));
+      List<Server> servers = serverApi().listServers().concat().toList();
+      Uris.UriBuilder uriBuilder = getListServerUriBuilder();
+      assertSent(GET, uriBuilder.toString());
+      assertEquals(servers.size(), 1);
+      for (Server s : servers) {
+         assertNotNull(s);
+      }
+   }
+
+   private Uris.UriBuilder getListServerUriBuilder() {
+      Uris.UriBuilder uriBuilder = 
Uris.uriBuilder("/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/server");
+      Set<String> zones = 
ctx.utils().injector().getInstance(ZoneIdsSupplier.class).get();
+      for (String zone : zones) {
+         uriBuilder.addQuery("datacenterId", zone);
+      }
+      return uriBuilder;
+   }
+
+   public void testListServers_404() throws Exception {
+      server.enqueue(response404());
+      assertTrue(serverApi().listServers().concat().isEmpty());
+      assertSent(HttpMethod.GET, getListServerUriBuilder().toString());
+   }
+
+   public void testGetServer() throws Exception {
+      server.enqueue(jsonResponse("/server.json"));
+      Server found = serverApi().getServer("12345");
+      assertSent(GET, 
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/server/12345");
+      assertNotNull(found);
+      assertNotNull(found.guest().vmTools());
+   }
+
+   public void testGetServer_404() throws Exception {
+      server.enqueue(response404());
+      serverApi().getServer("12345");
+      assertSent(GET, 
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/server/12345");
+   }
+
+   public void testDeleteServer() throws Exception {
+      server.enqueue(jsonResponse("/deleteServer.json"));
+      serverApi().deleteServer("12345");
+      final RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/deleteServer");
+      assertBodyContains(recordedRequest, "{\"id\":\"12345\"}");
+   }
+
+   public void testDeleteServer_404() throws Exception {
+      server.enqueue(response404());
+      serverApi().deleteServer("12345");
+      assertSent(POST, 
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/deleteServer");
+   }
+
+   public void testPowerOffServer() throws Exception {
+      server.enqueue(jsonResponse("/powerOffServer.json"));
+      serverApi().powerOffServer("12345");
+      final RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/powerOffServer");
+      assertBodyContains(recordedRequest, "{\"id\":\"12345\"}");
+   }
+
+   public void testRebootServer() throws Exception {
+      server.enqueue(jsonResponse("/rebootServer.json"));
+      serverApi().rebootServer("12345");
+      final RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/rebootServer");
+      assertBodyContains(recordedRequest, "{\"id\":\"12345\"}");
+   }
+
+   public void testReconfigureServer() throws Exception {
+      server.enqueue(jsonResponse("/reconfigureServer.json"));
+      serverApi().reconfigureServer("12345", 2, "STANDARD", 2);
+      final RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/reconfigureServer");
+      assertBodyContains(recordedRequest,
+            
"{\"id\":\"12345\",\"cpuCount\":2,\"cpuSpeed\":\"STANDARD\",\"coresPerSocket\":2}");
+   }
+
+   public void testShutdownServer() throws Exception {
+      server.enqueue(jsonResponse("/rebootServer.json"));
+      serverApi().shutdownServer("12345");
+      final RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/shutdownServer");
+      assertBodyContains(recordedRequest, "{\"id\":\"12345\"}");
+   }
+
+   public void testStartServer() throws Exception {
+      server.enqueue(jsonResponse("/rebootServer.json"));
+      serverApi().startServer("12345");
+      final RecordedRequest recordedRequest = assertSent(POST,
+            
"/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/startServer");
+      assertBodyContains(recordedRequest, "{\"id\":\"12345\"}");
+   }
+
+   private ServerApi serverApi() {
+      return api.getServerApi();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java
----------------------------------------------------------------------
diff --git 
a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java
 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java
index d25f6d8..ab5cfff 100644
--- 
a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java
+++ 
b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java
@@ -27,6 +27,12 @@ import org.testng.annotations.Test;
 @Test(groups = "live")
 public class BaseDimensionDataCloudControlApiLiveTest extends 
BaseApiLiveTest<DimensionDataCloudControlApi> {
 
+   protected static final String NETWORK_DOMAIN_ID = System
+         .getProperty("networkDomainId", 
"690de302-bb80-49c6-b401-8c02bbefb945");
+   protected static final String VLAN_ID = System.getProperty("vlanId", 
"6b25b02e-d3a2-4e69-8ca7-9bab605deebd");
+   protected static final String IMAGE_ID = System.getProperty("imageId", 
"4c02126c-32fc-4b4c-9466-9824c1b5aa0f");
+   protected static final String DATACENTER = System.getProperty("datacenter", 
"NW20-EPC-LAB04");
+
    public BaseDimensionDataCloudControlApiLiveTest() {
       provider = "dimensiondata-cloudcontrol";
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/cloneServerResponse.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/cloneServerResponse.json 
b/dimensiondata/src/test/resources/cloneServerResponse.json
new file mode 100644
index 0000000..7d713c1
--- /dev/null
+++ b/dimensiondata/src/test/resources/cloneServerResponse.json
@@ -0,0 +1,16 @@
+{
+  "requestId": "na/2016-04-14T13:37:20/62f06368-c3fb-11e3-b29c-001517c4643e",
+  "operation": "CLONE_SERVER",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request to Clone Server '9ed47330-5561-11e5-8c14-b8ca3a5d9ef8' 
has been accepted",
+  "info": [
+    {
+      "name": "imageId",
+      "value": "3389ffe8-c3fc-11e3-b29c-001517c4643e"
+    },
+    {
+      "name": "clusterId",
+      "value": "EU6-02"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/deleteServer.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/deleteServer.json 
b/dimensiondata/src/test/resources/deleteServer.json
new file mode 100644
index 0000000..67e1ea9
--- /dev/null
+++ b/dimensiondata/src/test/resources/deleteServer.json
@@ -0,0 +1,9 @@
+{
+  "operation": "DELETE_SERVER",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request to Delete Server 
(Id:5b00a2ab-c665-4cd6-8291-0b931374fb3d) has been accepted and is being 
processed",
+  "info": [],
+  "warning": [],
+  "error": [],
+  "requestId": 
"NA9/2015-03-08T05:47:02.731-04:00/22303753-7e22-4741-9e80-9da944a1f116"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/deployServerResponse.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/deployServerResponse.json 
b/dimensiondata/src/test/resources/deployServerResponse.json
new file mode 100644
index 0000000..6846c0a
--- /dev/null
+++ b/dimensiondata/src/test/resources/deployServerResponse.json
@@ -0,0 +1,14 @@
+{
+  "operation": "DEPLOY_SERVER",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request to deploy Server 'Production FTPS Server' has been 
accepted and is being processed.",
+  "info": [
+    {
+      "name": "serverId",
+      "value": "7b62aae5-bdbe-4595-b58d-c78f95db2a7f"
+    }
+  ],
+  "warning": [],
+  "error": [],
+  "requestId": 
"na9_20160321T074626030-0400_7e9fffe7-190b-46f2-9107-9d52fe57d0ad"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/powerOffServer.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/powerOffServer.json 
b/dimensiondata/src/test/resources/powerOffServer.json
new file mode 100644
index 0000000..3b6ede3
--- /dev/null
+++ b/dimensiondata/src/test/resources/powerOffServer.json
@@ -0,0 +1,9 @@
+{
+  "operation": "POWER_OFF_SERVER",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request to reboot Server 'Production Server' has been and is 
being processed.",
+  "info": [],
+  "warning": [],
+  "error": [],
+  "requestId": 
"na9_20160321T074626030-0400_7e9fffe7-190b-46f2-9107-9d52fe57d0ad"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/rebootServer.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/rebootServer.json 
b/dimensiondata/src/test/resources/rebootServer.json
new file mode 100644
index 0000000..121ec39
--- /dev/null
+++ b/dimensiondata/src/test/resources/rebootServer.json
@@ -0,0 +1,9 @@
+{
+  "operation": "REBOOT_SERVER",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request reconfigure Server 'Production Server' has been and is 
being processed.",
+  "info": [],
+  "warning": [],
+  "error": [],
+  "requestId": 
"na9_20160321T074626030-0400_7e9fffe7-190b-46f2-9107-9d52fe57d0ad"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/reconfigureServer.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/reconfigureServer.json 
b/dimensiondata/src/test/resources/reconfigureServer.json
new file mode 100644
index 0000000..d9f30df
--- /dev/null
+++ b/dimensiondata/src/test/resources/reconfigureServer.json
@@ -0,0 +1,9 @@
+{
+  "operation": "RECONFIGURE_SERVER",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request to power off Server 'Production Server' has been and is 
being processed.",
+  "info": [],
+  "warning": [],
+  "error": [],
+  "requestId": 
"na9_20160321T074626030-0400_7e9fffe7-190b-46f2-9107-9d52fe57d0ad"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/server.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/server.json 
b/dimensiondata/src/test/resources/server.json
new file mode 100644
index 0000000..9ece773
--- /dev/null
+++ b/dimensiondata/src/test/resources/server.json
@@ -0,0 +1,60 @@
+{
+  "name": "ServerApiLiveTest",
+  "cpu": {
+    "count": 2,
+    "speed": "STANDARD",
+    "coresPerSocket": 1
+  },
+  "memoryGb": 4,
+  "disk": [
+    {
+      "id": "918f12ba-5e5e-4cd6-87bd-60c18293c24d",
+      "scsiId": 0,
+      "sizeGb": 20,
+      "speed": "STANDARD",
+      "state": "NORMAL"
+    }
+  ],
+  "networkInfo": {
+    "primaryNic": {
+      "id": "f0c00cab-bfa3-4c51-8c0a-c52fdac1ae4b",
+      "privateIpv4": "10.0.0.7",
+      "ipv6": "2a00:47c0: 111: 1131: 5851: 1950:411c: 3dd8",
+      "vlanId": "7bd12a4d-4e83-4254-a266-174aa5f55187",
+      "vlanName": "jclouds vlan",
+      "networkAdapter": "E1000",
+      "macAddress": "00: 50: 56: bb: 53: 1e",
+      "key": 4000,
+      "state": "NORMAL"
+    },
+    "additionalNic": [],
+    "networkDomainId": "d122949b-8990-46d6-98f0-91c8676fc720"
+  },
+  "softwareLabel": [],
+  "sourceImageId": "56eb0b7c-15a7-4b63-b373-05b962e37554",
+  "createTime": "2017-07-03T16: 29: 33.000Z",
+  "deployed": true,
+  "started": true,
+  "state": "NORMAL",
+  "guest": {
+    "operatingSystem": {
+      "id": "REDHAT764",
+      "displayName": "REDHAT7/64",
+      "family": "UNIX"
+    },
+    "vmTools": {
+      "type": "VMWARE_TOOLS",
+      "versionStatus": "CURRENT",
+      "runningStatus": "NOT_RUNNING",
+      "apiVersion": 9356
+    },
+    "osCustomization": true
+  },
+  "virtualHardware": {
+    "version": "vmx-10",
+    "upToDate": true
+  },
+  "tag": [],
+  "id": "cb08c7ba-7a51-4e32-8d39-05d2270f8f8b",
+  "datacenterId": "EU6"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/f9ee0d6b/dimensiondata/src/test/resources/servers.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/servers.json 
b/dimensiondata/src/test/resources/servers.json
new file mode 100644
index 0000000..c0de4e8
--- /dev/null
+++ b/dimensiondata/src/test/resources/servers.json
@@ -0,0 +1,85 @@
+{
+  "server": [
+    {
+      "name": "parser-test-server-name",
+      "description": "parser-test-server-description",
+      "cluster": {
+        "id": "NA9-01",
+        "name": "SAP Cluster"
+      },
+      "cpu": {
+        "count": 2,
+        "speed": "STANDARD",
+        "coresPerSocket": 1
+      },
+      "memoryGb": 4,
+      "disk": [
+        {
+          "id": "0ba67812-d7b7-4c3f-b114-870fbea24d42",
+          "scsiId": 0,
+          "sizeGb": 10,
+          "speed": "STANDARD",
+          "state": "NORMAL"
+        }
+      ],
+      "networkInfo": {
+        "primaryNic": {
+          "id": "980a9fdd-4ea2-478b-85b4-f016349f1738",
+          "privateIpv4": "10.0.0.8",
+          "ipv6": "2607:f480:111:1575:c47:7479:2af8:3f1a",
+          "vlanId": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+          "vlanName": "vlan1",
+          "networkAdapter": "E1000",
+          "macAddress": "11-2A-3B-C4-E5-66",
+          "key": "4000",
+          "state": "NORMAL"
+        },
+        "additionalNic": [],
+        "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945"
+      },
+      "softwareLabel": [],
+      "sourceImageId": "1e44ab3f-2426-45ec-a1b5-827b2ce58836",
+      "createTime": "2016-03-10T13:05:21.000Z",
+      "deployed": true,
+      "started": true,
+      "state": "NORMAL",
+      "guest": {
+        "operatingSystem": {
+          "id": "CENTOS564",
+          "displayName": "CENTOS5/64",
+          "family": "UNIX"
+        },
+        "vmTools": {
+          "type": "VMWARE_TOOLS",
+          "versionStatus": "NEED_UPGRADE",
+          "runningStatus": "RUNNING",
+          "apiVersion": 9354
+        },
+        "osCustomization": true
+      },
+      "virtualHardware": {
+        "version": "vmx-08",
+        "upToDate": false
+      },
+      "consistencyGroup": {
+        "id": "1234ef-1238933-2344adce-1098",
+        "name": "Test Consistency Group",
+        "status": "DRS_MODE",
+        "serverRole": "TARGET"
+      },
+      "tag": [
+        {
+          "tagKeyId": "883b91b3-702f-11e6-81fa-acaf67f59a21",
+          "tagKeyName": "Department",
+          "value": "IT"
+        }
+      ],
+      "id": "b8246ba4-847d-475b-b296-f76787a69ca8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 1,
+  "totalCount": 1,
+  "pageSize": 250
+}
\ No newline at end of file

Reply via email to