You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by im...@apache.org on 2014/11/26 12:54:57 UTC

[27/41] stratos git commit: adding cloudstack dependancy

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java
new file mode 100644
index 0000000..2f601e9
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.features;
+
+import java.util.Set;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.Volume;
+import org.jclouds.cloudstack.filters.AuthenticationFilter;
+import org.jclouds.cloudstack.options.ListVolumesOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.OnlyElement;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Unwrap;
+
+/**
+ * Provides synchronous access to cloudstack via their REST API.
+ * <p/>
+ *
+ * @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" />
+ */
+@RequestFilters(AuthenticationFilter.class)
+@QueryParams(keys = "response", values = "json")
+public interface VolumeApi {
+   /**
+    * Create a volume with given name and diskOfferingId
+    *
+    * @param name           name of the volume
+    * @param diskOfferingId the ID of the disk offering.
+    * @param zoneId         the ID of the availability zone
+    * @return AsyncCreateResponse job response used to track creation
+    */
+   @Named("listVolumes")
+   @GET
+   @QueryParams(keys = { "command", "listAll" }, values = { "listVolumes", "true" })
+   @SelectJson("volume")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptySetOnNotFoundOr404.class)
+   Set<Volume> listVolumes(ListVolumesOptions... options);
+
+   /**
+    * Create a volume with given name, size and diskOfferingId
+    *
+    * @param name           name of the volume
+    * @param diskOfferingId the ID of the disk offering (the offering should have the custom disk size flag set)
+    * @param zoneId         the ID of the availability zone
+    * @param size           the size of volume required (in GB)
+    * @return AsyncCreateResponse job response used to track creation
+    */
+   @Named("listVolumes")
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = { "command", "listAll" }, values = { "listVolumes", "true" })
+   @SelectJson("volume")
+   @OnlyElement
+   @Fallback(NullOnNotFoundOr404.class)
+   Volume getVolume(@QueryParam("id") String id);
+
+
+   /**
+    * Create a volume with given name and snapshotId
+    *
+    * @param name       name of the volume
+    * @param snapshotId Snapshot id to be used while creating the volume
+    * @param zoneId     the ID of the availability zone
+    * @return AsyncCreateResponse job response used to track creation
+    */
+   @Named("createVolume")
+   @GET
+   @QueryParams(keys = "command", values = "createVolume")
+   @Unwrap
+   @Consumes(MediaType.APPLICATION_JSON)
+   AsyncCreateResponse createVolumeFromDiskOfferingInZone(@QueryParam("name") String name,
+                                                                            @QueryParam("diskofferingid") String diskOfferingId,
+                                                                            @QueryParam("zoneid") String zoneId);
+
+   /**
+    * List volumes
+    *
+    * @return volume list, empty if not found
+    */
+   @GET
+   @QueryParams(keys = "command", values = "createVolume")
+   @Unwrap
+   @Consumes(MediaType.APPLICATION_JSON)
+   AsyncCreateResponse createVolumeFromCustomDiskOfferingInZone(@QueryParam("name") String name,
+                                                                            @QueryParam("diskofferingid") String diskOfferingId,
+                                                                            @QueryParam("zoneid") String zoneId,
+                                                                            @QueryParam("size") int size);
+
+   /**
+    * Get volume by id
+    *
+    * @param id the volume id to retrieve
+    * @return volume or null if not found
+    */
+   @Named("createVolume")
+   @GET
+   @QueryParams(keys = "command", values = "createVolume")
+   @Unwrap
+   @Consumes(MediaType.APPLICATION_JSON)
+   AsyncCreateResponse createVolumeFromSnapshotInZone(@QueryParam("name") String name,
+                                                                        @QueryParam("snapshotid") String snapshotId,
+                                                                        @QueryParam("zoneid") String zoneId);
+
+   /**
+    * Deletes a attached disk volume
+    *
+    * @param id id of the volume
+    */
+   @Named("attachVolume")
+   @GET
+   @QueryParams(keys = "command", values = "attachVolume")
+   @Unwrap
+   @Consumes(MediaType.APPLICATION_JSON)
+   AsyncCreateResponse attachVolume(@QueryParam("id") String volumeId,
+                                                      @QueryParam("virtualmachineid") String virtualMachineId);
+
+   /**
+    * Attaches a disk volume to a virtual machine.
+    *
+    * @param volumeId         the ID of the disk volume
+    * @param virtualMachineId the ID of the virtual machine
+    * @return AsyncCreateResponse job response used to track creation
+    */
+   @Named("detachVolume")
+   @GET
+   @QueryParams(keys = "command", values = "detachVolume")
+   @Unwrap
+   @Consumes(MediaType.APPLICATION_JSON)
+   AsyncCreateResponse detachVolume(@QueryParam("id") String volumeId);
+
+   /**
+    * Detaches a disk volume to a virtual machine.
+    *
+    * @param volumeId         the ID of the disk volume
+    * @return AsyncCreateResponse job response used to track creation
+    */
+   @Named("deleteVolume")
+   @GET
+   @QueryParams(keys = "command", values = "deleteVolume")
+   @Fallback(VoidOnNotFoundOr404.class)
+   void deleteVolume(@QueryParam("id") String id);
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java
new file mode 100644
index 0000000..d7e8ff3
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.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.cloudstack.features;
+
+import java.util.Set;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.cloudstack.domain.Zone;
+import org.jclouds.cloudstack.filters.AuthenticationFilter;
+import org.jclouds.cloudstack.options.ListZonesOptions;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.OnlyElement;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+
+/**
+ * Provides synchronous access to cloudstack via their REST API.
+ * <p/>
+ * 
+ * @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" />
+ */
+@RequestFilters(AuthenticationFilter.class)
+@QueryParams(keys = "response", values = "json")
+public interface ZoneApi {
+
+   /**
+    * Lists zones
+    * 
+    * @param options
+    *           if present, how to constrain the list.
+    * @return zones matching query, or empty set, if no zones are found
+    */
+   @Named("listZones")
+   @GET
+   @QueryParams(keys = { "command", "listAll" }, values = { "listZones", "true" })
+   @SelectJson("zone")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(EmptySetOnNotFoundOr404.class)
+   Set<Zone> listZones(ListZonesOptions... options);
+
+   /**
+    * get a specific zone by id
+    * 
+    * @param id
+    *           zone to get
+    * @return zone or null if not found
+    */
+   @Named("listZones")
+   @GET
+   @QueryParams(keys = { "command", "listAll" }, values = { "listZones", "true" })
+   @SelectJson("zone")
+   @OnlyElement
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Fallback(NullOnNotFoundOr404.class)
+   Zone getZone(@QueryParam("id") String id);
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java
new file mode 100644
index 0000000..f08c0e8
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.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.cloudstack.filters;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.domain.LoginResponse;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequest.Builder;
+
+import com.google.common.base.Supplier;
+import com.google.common.net.HttpHeaders;
+
+/**
+ * 
+ * @see <a href="http://docs.cloud.com/CloudStack_Documentation/Customizing_the_CloudStack_UI#Cross_Site_Request_Forgery_%28CSRF%29"
+ *      />
+ */
+@Singleton
+public class AddSessionKeyAndJSessionIdToRequest implements AuthenticationFilter {
+
+   private final Supplier<LoginResponse> loginResponseSupplier;
+
+   @Inject
+   public AddSessionKeyAndJSessionIdToRequest(Supplier<LoginResponse> loginResponseSupplier) {
+      this.loginResponseSupplier = loginResponseSupplier;
+   }
+
+   @Override
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      LoginResponse loginResponse = loginResponseSupplier.get();
+      Builder<?> builder = request.toBuilder();
+      builder.replaceHeader(HttpHeaders.COOKIE, "JSESSIONID=" + loginResponse.getJSessionId());
+      builder.replaceQueryParam("sessionkey", loginResponse.getSessionKey());
+      return builder.build();
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java
new file mode 100644
index 0000000..1e567a6
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.filters;
+
+import org.jclouds.http.HttpRequestFilter;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Marker interface that determines how we authenticate http requests in cloudstack. default to sign
+ * requests as opposed to login.
+ */
+@ImplementedBy(QuerySigner.class)
+public interface AuthenticationFilter extends HttpRequestFilter {
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java
new file mode 100644
index 0000000..04610cc
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.filters;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.io.BaseEncoding.base64;
+import static com.google.common.io.ByteStreams.readBytes;
+import static org.jclouds.Constants.LOGGER_SIGNATURE;
+import static org.jclouds.crypto.Macs.asByteProcessor;
+import static org.jclouds.http.Uris.uriBuilder;
+import static org.jclouds.http.utils.Queries.queryParser;
+import static org.jclouds.util.Strings2.toInputStream;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.util.Map;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.base.Joiner;
+import org.jclouds.crypto.Crypto;
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.http.internal.SignatureWire;
+import org.jclouds.location.Provider;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RequestSigner;
+import org.jclouds.util.Strings2;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Multimap;
+import com.google.common.io.ByteProcessor;
+
+/**
+ * 
+ * @see <a href= "http://download.cloud.com/releases/2.2.0/api/user/2.2api_security_details.html" />
+ */
+@Singleton
+public class QuerySigner implements AuthenticationFilter, RequestSigner {
+
+   private final SignatureWire signatureWire;
+   private final Supplier<Credentials> creds;
+   private final Crypto crypto;
+   private final HttpUtils utils;
+
+   @Resource
+   @Named(LOGGER_SIGNATURE)
+   private Logger signatureLog = Logger.NULL;
+
+   @Inject
+   public QuerySigner(SignatureWire signatureWire, @Provider Supplier<Credentials> creds, Crypto crypto, HttpUtils utils) {
+      this.signatureWire = signatureWire;
+      this.creds = creds;
+      this.crypto = crypto;
+      this.utils = utils;
+   }
+
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      checkNotNull(request, "request must be present");
+      Multimap<String, String> decodedParams = queryParser().apply(request.getEndpoint().getRawQuery());
+      addSigningParams(decodedParams);
+      String stringToSign = createStringToSign(request, decodedParams);
+      String signature = sign(stringToSign);
+      addSignature(decodedParams, signature);
+      request = request.toBuilder().endpoint(uriBuilder(request.getEndpoint()).query(decodedParams).build()).build();
+      utils.logRequest(signatureLog, request, "<<");
+      return request;
+   }
+
+   @VisibleForTesting
+   void addSignature(Multimap<String, String> params, String signature) {
+      params.replaceValues("signature", ImmutableList.of(signature));
+   }
+
+   @VisibleForTesting
+   public String sign(String toSign) {
+      String signature;
+      try {
+         ByteProcessor<byte[]> hmacSHA1 = asByteProcessor(crypto.hmacSHA1(creds.get().credential.getBytes()));
+         signature = base64().encode(readBytes(toInputStream(toSign), hmacSHA1));
+         if (signatureWire.enabled())
+            signatureWire.input(toInputStream(signature));
+         return signature;
+      } catch (InvalidKeyException e) {
+         throw propagate(e);
+      } catch (IOException e) {
+         throw propagate(e);
+      }
+   }
+
+   @VisibleForTesting
+   public String createStringToSign(HttpRequest request, Multimap<String, String> decodedParams) {
+      utils.logRequest(signatureLog, request, ">>");
+      // encode each parameter value first,
+      ImmutableSortedSet.Builder<String> builder = ImmutableSortedSet.naturalOrder();
+      for (Map.Entry<String, String> entry : decodedParams.entries())
+         builder.add(entry.getKey() + "=" + Strings2.urlEncode(entry.getValue()));
+      // then, lower case the entire query string
+      String stringToSign = Joiner.on('&').join(builder.build()).toLowerCase();
+      if (signatureWire.enabled())
+         signatureWire.output(stringToSign);
+
+      return stringToSign;
+   }
+
+   @VisibleForTesting
+   void addSigningParams(Multimap<String, String> params) {
+      params.replaceValues("apiKey", ImmutableList.of(creds.get().identity));
+      params.removeAll("signature");
+   }
+
+   public String createStringToSign(HttpRequest input) {
+      Multimap<String, String> decodedParams = queryParser().apply(input.getEndpoint().getQuery());
+      addSigningParams(decodedParams);
+      return createStringToSign(input, decodedParams);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java
new file mode 100644
index 0000000..50185ed
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.util.concurrent.Futures.immediateFuture;
+import static org.jclouds.Fallbacks.valOnNotFoundOr404;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+import org.jclouds.Fallback;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public final class CloudStackFallbacks {
+   private CloudStackFallbacks() {
+   }
+
+   /**
+    * CloudStack is currently sending 431 errors with the text "Unable to find account owner for ip ". In this case, we
+    * have to ignore as there's no means for us to avoid the problem, or action to take.
+    */
+   public static final class VoidOnNotFoundOr404OrUnableToFindAccountOwner implements Fallback<Void> {
+      @Override
+      public ListenableFuture<Void> create(Throwable t) throws Exception {
+         return immediateFuture(createOrPropagate(t));
+      }
+
+      @Override
+      public Void createOrPropagate(Throwable t) throws Exception {
+         IllegalStateException e = getFirstThrowableOfType(checkNotNull(t, "throwable"), IllegalStateException.class);
+         if (e != null && e.getMessage().indexOf("Unable to find account owner for") != -1) {
+            return null;
+         } else {
+            return valOnNotFoundOr404(null, t);
+         }
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java
new file mode 100644
index 0000000..dd15e19
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.FirewallRule;
+import org.jclouds.cloudstack.domain.PublicIPAddress;
+import org.jclouds.cloudstack.options.CreateFirewallRuleOptions;
+import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.ImmutableSet.Builder;
+
+@Singleton
+public class CreateFirewallRulesForIP {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final CloudStackApi client;
+   private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult;
+   private final LoadingCache<String, Set<FirewallRule>> getFirewallRulesByVirtualMachine;
+
+   @Inject
+   public CreateFirewallRulesForIP(CloudStackApi client,
+         BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult,
+         LoadingCache<String, Set<FirewallRule>> getFirewallRulesByVirtualMachine) {
+      this.client = checkNotNull(client, "client");
+      this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult,
+            "blockUntilJobCompletesAndReturnResult");
+      this.getFirewallRulesByVirtualMachine = checkNotNull(getFirewallRulesByVirtualMachine,
+            "getFirewallRulesByVirtualMachine");
+   }
+
+   public Set<FirewallRule> apply(PublicIPAddress ip, Iterable<Integer> ports) {
+      return apply(ip, "tcp", ports);
+   }
+
+   public Set<FirewallRule> apply(PublicIPAddress ip, String protocol, Iterable<Integer> ports) {
+      checkState(ip.getVirtualMachineId() != null,
+            "ip %s should be static NATed to a virtual machine before applying rules", ip);
+      if (Iterables.isEmpty(ports))
+         return ImmutableSet.<FirewallRule> of();
+      Builder<AsyncCreateResponse> responses = ImmutableSet.builder();
+      for (int port : ports) {
+          AsyncCreateResponse response = client.getFirewallApi().createFirewallRuleForIpAndProtocol(ip.getId(), FirewallRule.Protocol.fromValue(protocol),
+                                                                                                       CreateFirewallRuleOptions.Builder.startPort(port).endPort(port));
+         logger.debug(">> creating firewall rule IPAddress(%s) for protocol(%s), port(%s); response(%s)",
+               ip.getId(), protocol, port, response);
+         responses.add(response);
+      }
+      Builder<FirewallRule> rules = ImmutableSet.builder();
+      for (AsyncCreateResponse response : responses.build()) {
+         FirewallRule rule = blockUntilJobCompletesAndReturnResult.<FirewallRule> apply(response);
+         rules.add(rule);
+         getFirewallRulesByVirtualMachine.asMap().put(ip.getVirtualMachineId(), ImmutableSet.of(rule));
+      }
+      return rules.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java
new file mode 100644
index 0000000..dd09f77
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.IPForwardingRule;
+import org.jclouds.cloudstack.domain.PublicIPAddress;
+import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.ImmutableSet.Builder;
+
+@Singleton
+public class CreatePortForwardingRulesForIP {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final CloudStackApi client;
+   private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult;
+   private final LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine;
+
+   @Inject
+   public CreatePortForwardingRulesForIP(CloudStackApi client,
+         BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult,
+         LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine) {
+      this.client = checkNotNull(client, "client");
+      this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult,
+            "blockUntilJobCompletesAndReturnResult");
+      this.getIPForwardingRulesByVirtualMachine = checkNotNull(getIPForwardingRulesByVirtualMachine,
+            "getIPForwardingRulesByVirtualMachine");
+   }
+
+   public Set<IPForwardingRule> apply(PublicIPAddress ip, Iterable<Integer> ports) {
+      return apply(ip, "tcp", ports);
+   }
+
+   public Set<IPForwardingRule> apply(PublicIPAddress ip, String protocol, Iterable<Integer> ports) {
+      checkState(ip.getVirtualMachineId() != null,
+            "ip %s should be static NATed to a virtual machine before applying rules", ip);
+      if (Iterables.isEmpty(ports))
+         return ImmutableSet.<IPForwardingRule> of();
+      Builder<AsyncCreateResponse> responses = ImmutableSet.builder();
+      for (int port : ports) {
+         AsyncCreateResponse response = client.getNATApi().createIPForwardingRule(ip.getId(), protocol, port);
+         logger.debug(">> creating IP forwarding rule IPAddress(%s) for protocol(%s), port(%s); response(%s)",
+               ip.getId(), protocol, port, response);
+         responses.add(response);
+      }
+      Builder<IPForwardingRule> rules = ImmutableSet.builder();
+      for (AsyncCreateResponse response : responses.build()) {
+         IPForwardingRule rule = blockUntilJobCompletesAndReturnResult.<IPForwardingRule> apply(response);
+         rules.add(rule);
+         getIPForwardingRulesByVirtualMachine.asMap().put(ip.getVirtualMachineId(), ImmutableSet.of(rule));
+      }
+      return rules.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java
new file mode 100644
index 0000000..8360977
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.cloudstack.predicates.SecurityGroupPredicates.portInRangeForCidr;
+import static org.jclouds.cloudstack.predicates.ZonePredicates.supportsSecurityGroups;
+
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.SecurityGroup;
+import org.jclouds.cloudstack.domain.Zone;
+import org.jclouds.cloudstack.domain.ZoneSecurityGroupNamePortsCidrs;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+
+@Singleton
+public class CreateSecurityGroupIfNeeded implements Function<ZoneSecurityGroupNamePortsCidrs, SecurityGroup> {
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+   protected final CloudStackApi client;
+   protected final Supplier<LoadingCache<String, Zone>> zoneIdToZone;
+   protected final Predicate<String> jobComplete;
+
+   @Inject
+   public CreateSecurityGroupIfNeeded(CloudStackApi client,
+                                      Predicate<String> jobComplete,
+                                      Supplier<LoadingCache<String, Zone>> zoneIdToZone) {
+      this.client = checkNotNull(client, "client");
+      this.jobComplete = checkNotNull(jobComplete, "jobComplete");
+      this.zoneIdToZone = zoneIdToZone;
+   }
+
+   @Override
+   public SecurityGroup apply(ZoneSecurityGroupNamePortsCidrs input) {
+      checkNotNull(input, "input");
+
+      String zoneId = input.getZone();
+      Zone zone = zoneIdToZone.get().getUnchecked(zoneId);
+
+      checkArgument(supportsSecurityGroups().apply(zone),
+                    "Security groups are required, but the zone %s does not support security groups", zoneId);
+      logger.debug(">> creating securityGroup %s", input);
+      try {
+
+         SecurityGroup securityGroup = client.getSecurityGroupApi().createSecurityGroup(input.getName());
+
+         logger.debug("<< created securityGroup(%s)", securityGroup);
+         ImmutableSet<String> cidrs;
+         if (!input.getCidrs().isEmpty()) {
+            cidrs = ImmutableSet.copyOf(input.getCidrs());
+         } else {
+            cidrs = ImmutableSet.of("0.0.0.0/0");
+         }
+         for (int port : input.getPorts()) {
+            authorizeGroupToItselfAndToTCPPortAndCidr(client, securityGroup, port, cidrs);
+         }
+         return securityGroup;
+      } catch (IllegalStateException e) {
+         logger.trace("<< trying to find securityGroup(%s): %s", input, e.getMessage());
+         SecurityGroup group = client.getSecurityGroupApi().getSecurityGroupByName(input.getName());
+         logger.debug("<< reused securityGroup(%s)", group.getId());
+         return group;
+      }
+   }
+
+   private void authorizeGroupToItselfAndToTCPPortAndCidr(CloudStackApi client,
+                                                          SecurityGroup securityGroup,
+                                                          int port,
+                                                          Set<String> cidrs) {
+      for (String cidr : cidrs) {
+         logger.debug(">> authorizing securityGroup(%s) permission to %s on port %d", securityGroup, cidr, port);
+         if (!portInRangeForCidr(port, cidr).apply(securityGroup)) {
+            jobComplete.apply(client.getSecurityGroupApi().authorizeIngressPortsToCIDRs(securityGroup.getId(),
+                                                                                           "TCP",
+                                                                                           port,
+                                                                                           port,
+                                                                                           ImmutableSet.of(cidr)));
+            logger.debug("<< authorized securityGroup(%s) permission to %s on port %d", securityGroup, cidr, port);
+         }
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java
new file mode 100644
index 0000000..cddb19d
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.google.common.base.Function;
+
+/**
+ * Convert a Date object into a "yyyy-MM-dd" String
+ */
+public class DateToYyyyMmDd implements Function<Object, String> {
+
+   public String apply(Object input) {
+      checkNotNull(input, "input cannot be null");
+      checkArgument(input instanceof Date, "input must be a Date");
+
+      return new SimpleDateFormat("yyyy-MM-dd").format((Date)input);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java
new file mode 100644
index 0000000..3fc73ab
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.FirewallRule;
+import org.jclouds.cloudstack.options.ListFirewallRulesOptions;
+
+@Singleton
+public class GetFirewallRulesByVirtualMachine extends CacheLoader<String, Set<FirewallRule>> {
+   private final CloudStackApi client;
+
+   @Inject
+   public GetFirewallRulesByVirtualMachine(CloudStackApi client) {
+      this.client = checkNotNull(client, "client");
+   }
+
+   /**
+    * @throws org.jclouds.rest.ResourceNotFoundException
+    *          when there is no ip forwarding rule available for the VM
+    */
+   @Override
+   public Set<FirewallRule> load(String input) {
+      String publicIPId = client.getVirtualMachineApi().getVirtualMachine(input).getPublicIPId();
+      Set<FirewallRule> rules = client.getFirewallApi()
+         .listFirewallRules(ListFirewallRulesOptions.Builder.ipAddressId(publicIPId));
+      return rules != null ? rules : ImmutableSet.<FirewallRule>of();
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java
new file mode 100644
index 0000000..02e6fa1
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.IPForwardingRule;
+
+import com.google.common.cache.CacheLoader;
+
+@Singleton
+public class GetIPForwardingRulesByVirtualMachine extends CacheLoader<String, Set<IPForwardingRule>> {
+   private final CloudStackApi client;
+
+   @Inject
+   public GetIPForwardingRulesByVirtualMachine(CloudStackApi client) {
+      this.client = checkNotNull(client, "client");
+   }
+
+   /**
+    * @throws org.jclouds.rest.ResourceNotFoundException
+    *          when there is no ip forwarding rule available for the VM
+    */
+   @Override
+   public Set<IPForwardingRule> load(String input) {
+      return client.getNATApi().getIPForwardingRulesForVirtualMachine(input);
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java
new file mode 100644
index 0000000..3095729
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.domain.AsyncJob;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.UnwrapOnlyJsonValue;
+
+import com.google.common.base.Function;
+import com.google.inject.Inject;
+
+@Singleton
+public class ParseAsyncJobFromHttpResponse implements Function<HttpResponse, AsyncJob<?>> {
+   private final UnwrapOnlyJsonValue<AsyncJob<Map<String, JsonBall>>> parser;
+   private final ParseTypedAsyncJob parseTyped;
+
+   @Inject
+   public ParseAsyncJobFromHttpResponse(ParseTypedAsyncJob parseTyped,
+         UnwrapOnlyJsonValue<AsyncJob<Map<String, JsonBall>>> parser) {
+      this.parseTyped = checkNotNull(parseTyped, "parseTyped");
+      this.parser = checkNotNull(parser, "parser");
+   }
+
+   public AsyncJob<?> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      AsyncJob<Map<String, JsonBall>> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      return parseTyped.apply(toParse);
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java
new file mode 100644
index 0000000..59f479f
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.domain.AsyncJob;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+@Singleton
+public class ParseAsyncJobsFromHttpResponse implements Function<HttpResponse, Set<AsyncJob<?>>> {
+   private final ParseFirstJsonValueNamed<Set<AsyncJob<Map<String, JsonBall>>>> parser;
+   private final ParseTypedAsyncJob parseTyped;
+
+   @Inject
+   public ParseAsyncJobsFromHttpResponse(ParseTypedAsyncJob parseTyped, GsonWrapper gsonView) {
+      this.parseTyped = checkNotNull(parseTyped, "parseTyped");
+      this.parser = new ParseFirstJsonValueNamed<Set<AsyncJob<Map<String, JsonBall>>>>(
+         checkNotNull(gsonView, "gsonView"),
+         new TypeLiteral<Set<AsyncJob<Map<String, JsonBall>>>>() { },
+         "asyncjobs");
+   }
+
+   public Set<AsyncJob<?>> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      Set<AsyncJob<Map<String, JsonBall>>> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      return ImmutableSet.copyOf(Iterables.transform(toParse, parseTyped));
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java
new file mode 100644
index 0000000..552a6e8
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+@Singleton
+public class ParseEventTypesFromHttpResponse implements Function<HttpResponse, Set<String>> {
+   private final ParseFirstJsonValueNamed<Set<EventType>> parser;
+
+   private static class EventType {
+      private String name;
+
+       @Override
+       public boolean equals(Object o) {
+           if (this == o) return true;
+           if (o == null || getClass() != o.getClass()) return false;
+           
+           EventType that = (EventType) o;
+           
+           if (!Objects.equal(name, that.name)) return false;
+           
+           return true;
+       }
+       
+       @Override
+       public int hashCode() {
+           return Objects.hashCode(name);
+       }
+   }
+
+   @Inject
+   public ParseEventTypesFromHttpResponse(GsonWrapper gsonView) {
+      this.parser = new ParseFirstJsonValueNamed<Set<EventType>>(checkNotNull(gsonView, "gsonView"),
+            new TypeLiteral<Set<EventType>>() {
+            }, "eventtype");
+   }
+
+   public Set<String> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      Set<EventType> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      Builder<String> builder = ImmutableSet.builder();
+      for (EventType entry : toParse)
+         builder.add(entry.name);
+      return builder.build();
+   }
+}
+
+

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java
new file mode 100644
index 0000000..936e5aa
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+
+@Singleton
+public class ParseIdToNameEntryFromHttpResponse implements Function<HttpResponse, Map.Entry<String, String>> {
+   private final ParseIdToNameFromHttpResponse parser;
+
+   @Inject
+   public ParseIdToNameEntryFromHttpResponse(ParseIdToNameFromHttpResponse parser) {
+      this.parser = checkNotNull(parser, "parser");
+   }
+
+   public Map.Entry<String, String> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      Map<String, String> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      return Iterables.getFirst(toParse.entrySet(), null);
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java
new file mode 100644
index 0000000..d2ba0a7
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+@Singleton
+public class ParseIdToNameFromHttpResponse implements Function<HttpResponse, Map<String, String>> {
+   private final ParseFirstJsonValueNamed<Set<IdName>> parser;
+
+   private static class IdName {
+      private String id;
+      private String name;
+
+       @Override
+       public boolean equals(Object o) {
+           if (this == o) return true;
+           if (o == null || getClass() != o.getClass()) return false;
+           
+           IdName that = (IdName) o;
+           
+           if (!Objects.equal(id, that.id)) return false;
+           if (!Objects.equal(name, that.name)) return false;
+           
+           return true;
+       }
+       
+       @Override
+       public int hashCode() {
+           return Objects.hashCode(id, name);
+       }
+   }
+
+   @Inject
+   public ParseIdToNameFromHttpResponse(GsonWrapper gsonView) {
+      this.parser = new ParseFirstJsonValueNamed<Set<IdName>>(checkNotNull(gsonView, "gsonView"),
+            new TypeLiteral<Set<IdName>>() {
+            }, "oscategory");
+   }
+
+   public Map<String, String> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      Set<IdName> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      Builder<String, String> builder = ImmutableSortedMap.naturalOrder();
+      for (IdName entry : toParse)
+         builder.put(entry.id, entry.name);
+      return builder.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java
new file mode 100644
index 0000000..317aa28
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.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.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.get;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import org.jclouds.cloudstack.domain.LoginResponse;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+public class ParseLoginResponseFromHttpResponse implements Function<HttpResponse, LoginResponse> {
+
+   private ParseFirstJsonValueNamed<LoginResponse> parser;
+
+   @Inject
+   ParseLoginResponseFromHttpResponse(GsonWrapper gson) {
+      this.parser = new ParseFirstJsonValueNamed<LoginResponse>(checkNotNull(gson, "gsonView"),
+         new TypeLiteral<LoginResponse>(){}, "loginresponse");
+   }
+
+   @Override
+   public LoginResponse apply(HttpResponse response) {
+      checkNotNull(response, "response");
+
+      LoginResponse login =  parser.apply(response);
+      checkNotNull(login, "loginResponse");
+
+      String jSessionId = get(Splitter.on("=").split(get(Splitter.on(";").trimResults().split(
+         getOnlyElement(response.getHeaders().get("Set-Cookie"))), 0)), 1);
+      
+      return LoginResponse.builder().fromLoginResponse(login).jSessionId(jSessionId).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java
new file mode 100644
index 0000000..f30c6a4
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+@Singleton
+public class ParseNamesFromHttpResponse implements Function<HttpResponse, Set<String>> {
+   private final ParseFirstJsonValueNamed<Set<Name>> parser;
+
+   private static class Name {
+      private String name;
+
+       @Override
+       public boolean equals(Object o) {
+           if (this == o) return true;
+           if (o == null || getClass() != o.getClass()) return false;
+           
+           Name that = (Name) o;
+           
+           if (!Objects.equal(name, that.name)) return false;
+           
+           return true;
+       }
+       
+       @Override
+       public int hashCode() {
+           return Objects.hashCode(name);
+       }
+   }
+
+   @Inject
+   public ParseNamesFromHttpResponse(GsonWrapper gsonView) {
+      this.parser = new ParseFirstJsonValueNamed<Set<Name>>(checkNotNull(gsonView, "gsonView"),
+            new TypeLiteral<Set<Name>>() {
+            }, "hypervisor");
+   }
+
+   public Set<String> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      Set<Name> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      Builder<String> builder = ImmutableSet.builder();
+      for (Name entry : toParse)
+         builder.add(entry.name);
+      return builder.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java
new file mode 100644
index 0000000..0082ea8
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.domain.Account;
+import org.jclouds.cloudstack.domain.AsyncJob;
+import org.jclouds.cloudstack.domain.AsyncJobError;
+import org.jclouds.cloudstack.domain.FirewallRule;
+import org.jclouds.cloudstack.domain.IPForwardingRule;
+import org.jclouds.cloudstack.domain.LoadBalancerRule;
+import org.jclouds.cloudstack.domain.Network;
+import org.jclouds.cloudstack.domain.PortForwardingRule;
+import org.jclouds.cloudstack.domain.PublicIPAddress;
+import org.jclouds.cloudstack.domain.SecurityGroup;
+import org.jclouds.cloudstack.domain.Snapshot;
+import org.jclouds.cloudstack.domain.Template;
+import org.jclouds.cloudstack.domain.TemplateExtraction;
+import org.jclouds.cloudstack.domain.User;
+import org.jclouds.cloudstack.domain.VirtualMachine;
+import org.jclouds.cloudstack.domain.Volume;
+import org.jclouds.cloudstack.domain.AsyncJob.Builder;
+import org.jclouds.cloudstack.domain.AsyncJobError.ErrorCode;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.json.Json;
+import org.jclouds.logging.Logger;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+
+@Singleton
+public class ParseTypedAsyncJob implements Function<AsyncJob<Map<String, JsonBall>>, AsyncJob<?>> {
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   @Inject(optional = true)
+   @VisibleForTesting
+   @Named("jclouds.cloudstack.jobresult-type-map")
+   Map<String, Class<?>> typeMap = ImmutableMap.<String, Class<?>>builder()
+      .put("user", User.class)
+      .put("account", Account.class)
+      .put("securitygroup", SecurityGroup.class)
+      .put("portforwardingrule", PortForwardingRule.class)
+      .put("ipforwardingrule", IPForwardingRule.class)
+      .put("firewallrule", FirewallRule.class)
+      .put("network", Network.class)
+      .put("ipaddress", PublicIPAddress.class)
+      .put("virtualmachine", VirtualMachine.class)
+      .put("loadbalancer", LoadBalancerRule.class)
+      .put("snapshot", Snapshot.class)
+      .put("template", Template.class)
+      .put("volume", Volume.class).build();
+   private final Json json;
+
+   @Inject
+   public ParseTypedAsyncJob(Json json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   public AsyncJob<?> apply(AsyncJob<Map<String, JsonBall>> toParse) {
+      AsyncJob<?> result = toParse;
+      if (toParse.getResult() != null) {
+         if (toParse.getResult().size() == 1) {
+            @SuppressWarnings({"unchecked", "rawtypes"})
+            Builder<?, Object> builder = AsyncJob.Builder.fromAsyncJobUntyped((AsyncJob) toParse);
+            if (toParse.getResult().containsKey("success")) {
+               builder.result(null);
+            } else {
+               Entry<String, JsonBall> entry = Iterables.get(toParse.getResult().entrySet(), 0);
+               if ("template".equals(entry.getKey())) {
+                  // Sometimes Cloudstack will say 'template' and the payload is a Template object.
+                  // Sometimes Cloudstack will say 'template' and the payload is a TemplateExtraction object.
+                  // The 'state' field only exists on TemplateExtraction, so we can test this to work out what we have actually been given.
+                  Template template = json.fromJson(entry.getValue().toString(), Template.class);
+                  TemplateExtraction templateExtraction = json.fromJson(entry.getValue().toString(), TemplateExtraction.class);
+                  boolean isTemplate = Strings.isNullOrEmpty(templateExtraction.getState());
+                  builder.result(isTemplate ? template : templateExtraction);
+               } else if (typeMap.containsKey(entry.getKey())) {
+                  builder.result(json.fromJson(entry.getValue().toString(), typeMap.get(entry.getKey())));
+               } else {
+                  logger.warn(
+                     "type key %s not configured.  please override default for Map<String, Class<?>> bound to name jclouds.cloudstack.jobresult-type-map",
+                     entry.getKey());
+                  builder.result(entry.getValue().toString());
+               }
+            }
+            result = builder.build();
+         } else if (toParse.getResult().containsKey("errorcode")) {
+            @SuppressWarnings({"unchecked", "rawtypes"})
+            Builder<?, Object> builder = AsyncJob.Builder.fromAsyncJobUntyped((AsyncJob) toParse);
+            builder.result(null);  // avoid classcastexceptions
+            builder.error(AsyncJobError.builder().errorCode(ErrorCode.fromValue(toParse.getResult().get("errorcode").toString()))
+                  .errorText(toParse.getResult().containsKey("errortext") ? toParse.getResult().get("errortext").toString().replace("\"", "") : null)
+                  .build());
+            result = builder.build();
+         } else if (toParse.getResult().size() > 1) {
+            logger.warn("unexpected size of async job result; expecting a map with a single element",
+               toParse.getResult());
+         }
+      }
+      return result;
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java
new file mode 100644
index 0000000..7ea19b2
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.and;
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.cloudstack.options.AssociateIPAddressOptions.Builder.networkId;
+import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.allocatedOnly;
+import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.associatedWithNetwork;
+import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.available;
+import static org.jclouds.compute.reference.ComputeServiceConstants.COMPUTE_LOGGER;
+
+import java.util.NoSuchElementException;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.AsyncCreateResponse;
+import org.jclouds.cloudstack.domain.Network;
+import org.jclouds.cloudstack.domain.PublicIPAddress;
+import org.jclouds.cloudstack.features.AddressApi;
+import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+
+@Singleton
+public class ReuseOrAssociateNewPublicIPAddress implements Function<Network, PublicIPAddress> {
+   private final CloudStackApi client;
+   private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult;
+   @Resource
+   @Named(COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   @Inject
+   public ReuseOrAssociateNewPublicIPAddress(CloudStackApi client,
+         BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult) {
+      this.client = checkNotNull(client, "client");
+      this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult,
+            "blockUntilJobCompletesAndReturnResult");
+   }
+
+   /**
+    * Finds existing addresses who are ready for use and not assigned to a
+    * machine.
+    * 
+    * @param networkId
+    *           network id to search
+    * @param client
+    *           address client
+    * @return address to use
+    * @throws NoSuchElementException
+    *            if there's no existing ip address that is free for use
+    */
+   public static PublicIPAddress findAvailableAndAssociatedWithNetwork(String networkId, AddressApi client) {
+      return find(client.listPublicIPAddresses(allocatedOnly(true).networkId(networkId)),
+            and(associatedWithNetwork(networkId), available()));
+   }
+
+   public static PublicIPAddress associateIPAddressInNetwork(Network network, CloudStackApi client,
+         BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult) {
+      AsyncCreateResponse job = client.getAddressApi().associateIPAddressInZone(network.getZoneId(),
+            networkId(network.getId()));
+      PublicIPAddress ip = blockUntilJobCompletesAndReturnResult.<PublicIPAddress> apply(job);
+      assert ip.getZoneId().equals(network.getZoneId());
+      return ip;
+   }
+
+   @Override
+   public PublicIPAddress apply(Network input) {
+      try {
+         logger.debug(">> looking for existing address in network(%s)", input.getId());
+         PublicIPAddress returnVal = findAvailableAndAssociatedWithNetwork(input.getId(), client.getAddressApi());
+         logger.debug("<< reused address(%s)", returnVal.getId());
+         return returnVal;
+      } catch (NoSuchElementException e) {
+         logger.debug(">> associating new address in network(%s)", input.getId());
+         PublicIPAddress returnVal = associateIPAddressInNetwork(input, client, blockUntilJobCompletesAndReturnResult);
+         logger.debug("<< associated address(%s)", returnVal.getId());
+         return returnVal;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/a4a03688/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java
----------------------------------------------------------------------
diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java
new file mode 100644
index 0000000..87fc128
--- /dev/null
+++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.cloudstack.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.cloudstack.CloudStackApi;
+import org.jclouds.cloudstack.domain.Network;
+import org.jclouds.cloudstack.domain.PublicIPAddress;
+import org.jclouds.cloudstack.domain.VirtualMachine;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.inject.assistedinject.Assisted;
+
+@Singleton
+public class StaticNATVirtualMachineInNetwork implements Function<VirtualMachine, PublicIPAddress> {
+   public interface Factory {
+      StaticNATVirtualMachineInNetwork create(Network in);
+   }
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final CloudStackApi client;
+   private final ReuseOrAssociateNewPublicIPAddress reuseOrAssociate;
+   private final Network network;
+
+   @Inject
+   public StaticNATVirtualMachineInNetwork(CloudStackApi client,
+         ReuseOrAssociateNewPublicIPAddress reuseOrAssociate, @Assisted Network network) {
+      this.client = checkNotNull(client, "client");
+      this.reuseOrAssociate = checkNotNull(reuseOrAssociate, "reuseOrAssociate");
+      this.network = checkNotNull(network, "network");
+   }
+
+   public PublicIPAddress apply(VirtualMachine vm) {
+      PublicIPAddress ip;
+      for (ip = reuseOrAssociate.apply(network); !ip.isStaticNAT() || ip.getVirtualMachineId() != vm.getId(); ip = reuseOrAssociate
+            .apply(network)) {
+         // check to see if someone already grabbed this ip
+         if (ip.getVirtualMachineId() != null && ip.getVirtualMachineId() != vm.getId())
+            continue;
+         try {
+            logger.debug(">> static NATing IPAddress(%s) to virtualMachine(%s)", ip.getId(), vm.getId());
+            client.getNATApi().enableStaticNATForVirtualMachine(vm.getId(), ip.getId());
+            ip = client.getAddressApi().getPublicIPAddress(ip.getId());
+            if (ip.isStaticNAT() && ip.getVirtualMachineId().equals(vm.getId()))
+               break;
+         } catch (IllegalStateException e) {
+            // very likely an ip conflict, so retry;
+         }
+         return ip;
+      }
+      return ip;
+   }
+}