You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2015/04/02 12:41:07 UTC

[2/2] jclouds-labs git commit: [JCLOUDS-846] StorageAccountApi completed + mock and live tests

[JCLOUDS-846] StorageAccountApi completed + mock and live tests


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

Branch: refs/heads/master
Commit: aac957447270e6bc78d62de628cfb539add5045f
Parents: e6a3ce3
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Mar 31 11:54:39 2015 +0200
Committer: Ignasi Barrera <na...@apache.org>
Committed: Thu Apr 2 12:38:00 2015 +0200

----------------------------------------------------------------------
 .../CreateStorageServiceParamsToXML.java        |  76 +++++
 .../binders/StorageServiceKeyTypeToXML.java     |  43 +++
 .../binders/StorageServiceParamsToXML.java      |  53 ----
 .../UpdateStorageServiceParamsToXML.java        |  86 ++++++
 ...ServiceAndVirtualNetworkThenCreateNodes.java |  11 +-
 .../domain/CreateStorageServiceParams.java      | 161 +++++++++++
 .../azurecompute/domain/StorageService.java     | 197 ++++++++++++-
 .../azurecompute/domain/StorageServiceKeys.java |  54 ++++
 .../domain/StorageServiceParams.java            | 104 -------
 .../domain/UpdateStorageServiceParams.java      | 190 +++++++++++++
 .../features/StorageAccountApi.java             |  83 ++++--
 .../azurecompute/features/SubscriptionApi.java  |   7 +-
 .../xml/ExtendedPropertiesHandler.java          |  55 ++++
 .../xml/ListStorageServicesHandler.java         |  12 +-
 .../azurecompute/xml/StorageServiceHandler.java |  61 +++-
 .../xml/StorageServiceKeysHandler.java          |  70 +++++
 .../xml/StorageServicePropertiesHandler.java    | 140 +++++++++-
 .../features/StorageAccountApiLiveTest.java     | 118 ++++++++
 .../features/StorageAccountApiMockTest.java     | 228 +++++++++++++++
 .../features/SubscriptionApiMockTest.java       |  60 ++++
 .../internal/BaseAzureComputeApiLiveTest.java   |  24 +-
 .../xml/ListRoleSizesHandlerTest.java           |  64 +++++
 .../xml/ListStorageServiceHandlerTest.java      |  79 ++++++
 .../resources/createstorageserviceparams.xml    |   1 +
 .../resources/isavailablestorageservice.xml     |   1 +
 azurecompute/src/test/resources/rolesizes.xml   | 276 ++-----------------
 .../src/test/resources/storageaccountkeys.xml   |   1 +
 .../resources/storageaccountregeneratekeys.xml  |   1 +
 .../src/test/resources/storageservices.xml      |  34 +++
 .../resources/updatestorageserviceparams.xml    |   1 +
 30 files changed, 1796 insertions(+), 495 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/binders/CreateStorageServiceParamsToXML.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/binders/CreateStorageServiceParamsToXML.java b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/CreateStorageServiceParamsToXML.java
new file mode 100644
index 0000000..9221062
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/CreateStorageServiceParamsToXML.java
@@ -0,0 +1,76 @@
+/*
+ * 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.azurecompute.binders;
+
+import static com.google.common.base.Throwables.propagate;
+
+import org.jclouds.azurecompute.domain.CreateStorageServiceParams;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.BaseEncoding;
+import com.jamesmurty.utils.XMLBuilder;
+import java.util.Map;
+
+public final class CreateStorageServiceParamsToXML implements Binder {
+
+   @Override
+   @SuppressWarnings("unchecked")
+   public <R extends HttpRequest> R bindToRequest(final R request, final Object input) {
+      final CreateStorageServiceParams params = CreateStorageServiceParams.class.cast(input);
+
+      try {
+         final XMLBuilder builder = XMLBuilder.create(
+                 "CreateStorageServiceInput", "http://schemas.microsoft.com/windowsazure").
+                 e("ServiceName").t(params.serviceName()).up();
+
+         if (params.description() != null) {
+            builder.e("Description").t(params.description()).up();
+         }
+
+         if (params.label() != null) {
+            builder.e("Label").t(BaseEncoding.base64().encode(params.label().getBytes(Charsets.UTF_8))).up();
+         }
+
+         if (params.location() != null) {
+            builder.e("Location").t(params.location()).up();
+         }
+         if (params.affinityGroup() != null) {
+            builder.e("AffinityGroup").t(params.affinityGroup()).up();
+         }
+
+         if (params.extendedProperties() != null) {
+            final XMLBuilder extProps = builder.e("ExtendedProperties");
+            for (Map.Entry<String, String> entry : params.extendedProperties().entrySet()) {
+               final XMLBuilder extProp = extProps.e("ExtendedProperty");
+               extProp.e("Name").t(entry.getKey()).up();
+               extProp.e("Value").t(entry.getValue()).up();
+               extProp.up();
+            }
+            extProps.up();
+         }
+
+         builder.e("AccountType").t(params.accountType().name()).up();
+
+         return (R) request.toBuilder().payload(builder.asString()).build();
+      } catch (Exception e) {
+         throw propagate(e);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceKeyTypeToXML.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceKeyTypeToXML.java b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceKeyTypeToXML.java
new file mode 100644
index 0000000..abc6da5
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceKeyTypeToXML.java
@@ -0,0 +1,43 @@
+/*
+ * 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.azurecompute.binders;
+
+import com.jamesmurty.utils.XMLBuilder;
+import org.jclouds.azurecompute.domain.StorageServiceKeys;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import static com.google.common.base.Throwables.propagate;
+
+public class StorageServiceKeyTypeToXML implements Binder {
+
+   @Override
+   @SuppressWarnings("unchecked")
+   public <R extends HttpRequest> R bindToRequest(final R request, final Object input) {
+      final StorageServiceKeys.KeyType params = StorageServiceKeys.KeyType.class.cast(input);
+
+      try {
+         final XMLBuilder builder = XMLBuilder.create(
+                 "RegenerateKeys", "http://schemas.microsoft.com/windowsazure").
+                 e("KeyType").t(params.name()).up();
+         return (R) request.toBuilder().payload(builder.asString()).build();
+      } catch (Exception e) {
+         throw propagate(e);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceParamsToXML.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceParamsToXML.java b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceParamsToXML.java
deleted file mode 100644
index ea06e50..0000000
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/binders/StorageServiceParamsToXML.java
+++ /dev/null
@@ -1,53 +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.azurecompute.binders;
-
-import static com.google.common.base.Throwables.propagate;
-
-import org.jclouds.azurecompute.domain.StorageServiceParams;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.rest.Binder;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.BaseEncoding;
-import com.jamesmurty.utils.XMLBuilder;
-
-public final class StorageServiceParamsToXML implements Binder {
-
-   @Override
-   @SuppressWarnings("unchecked")
-   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
-      StorageServiceParams params = StorageServiceParams.class.cast(input);
-
-      try {
-         XMLBuilder builder = XMLBuilder.create(
-                 "CreateStorageServiceInput", "http://schemas.microsoft.com/windowsazure")
-                 .e("ServiceName").t(params.name()).up()
-                 //.e("Description").up()
-                 .e("Label").t(BaseEncoding.base64().encode(params.label().getBytes(Charsets.UTF_8))).up()
-                 .e("Location").t(params.location()).up()
-                 //.e("GeoReplicationEnabled").up()
-                 //.e("ExtendedProperties").up()
-                 //.e("SecondaryReadEnabled").up()
-                 .e("AccountType").t(params.accountType().name()).up();
-         return (R) request.toBuilder().payload(builder.asString()).build();
-      } catch (Exception e) {
-         throw propagate(e);
-      }
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/binders/UpdateStorageServiceParamsToXML.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/binders/UpdateStorageServiceParamsToXML.java b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/UpdateStorageServiceParamsToXML.java
new file mode 100644
index 0000000..4d80f9a
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/binders/UpdateStorageServiceParamsToXML.java
@@ -0,0 +1,86 @@
+/*
+ * 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.azurecompute.binders;
+
+import static com.google.common.base.Throwables.propagate;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.BaseEncoding;
+import com.jamesmurty.utils.XMLBuilder;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+import org.jclouds.azurecompute.domain.UpdateStorageServiceParams;
+
+public final class UpdateStorageServiceParamsToXML implements Binder {
+
+   @Override
+   @SuppressWarnings("unchecked")
+   public <R extends HttpRequest> R bindToRequest(final R request, final Object input) {
+      final UpdateStorageServiceParams params = UpdateStorageServiceParams.class.cast(input);
+
+      try {
+         final XMLBuilder builder = XMLBuilder.create(
+                 "UpdateStorageServiceInput", "http://schemas.microsoft.com/windowsazure");
+
+         if (params.description() != null) {
+            builder.e("Description").t(params.description()).up();
+         }
+
+         if (params.label() != null) {
+            builder.e("Label").t(BaseEncoding.base64().encode(params.label().getBytes(Charsets.UTF_8))).up();
+         }
+
+         if (params.geoReplicationEnabled() != null) {
+            builder.e("geoReplicationEnabled").t(params.geoReplicationEnabled().toString()).up();
+         }
+
+         if (params.extendedProperties() != null) {
+            final XMLBuilder extProps = builder.e("ExtendedProperties");
+            for (Map.Entry<String, String> entry : params.extendedProperties().entrySet()) {
+               final XMLBuilder extProp = extProps.e("ExtendedProperty");
+               extProp.e("Name").t(entry.getKey()).up();
+               extProp.e("Value").t(entry.getValue()).up();
+               extProp.up();
+            }
+            extProps.up();
+         }
+
+         if (params.customDomains() != null) {
+            final XMLBuilder custDomains = builder.e("CustomDomains");
+            for (UpdateStorageServiceParams.CustomDomain domain : params.customDomains()) {
+               final XMLBuilder custDomain = custDomains.e("CustomDomain");
+               custDomain.e("Name").t(domain.name()).up();
+               custDomain.e("UseSubDomainName").t(domain.useSubDomainName().toString()).up();
+               custDomain.up();
+            }
+            custDomains.up();
+         }
+
+         if (params.accountType() != null) {
+            builder.e("AccountType").t(params.accountType().name()).up();
+         }
+
+         return (R) request.toBuilder().payload(builder.asString()).build();
+      } catch (Exception e) {
+         throw propagate(e);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes.java b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes.java
index 3a52a5e..6f70229 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes.java
@@ -37,7 +37,7 @@ import org.jclouds.azurecompute.config.AzureComputeProperties;
 import org.jclouds.azurecompute.domain.NetworkConfiguration;
 import org.jclouds.azurecompute.domain.NetworkSecurityGroup;
 import org.jclouds.azurecompute.domain.StorageService;
-import org.jclouds.azurecompute.domain.StorageServiceParams;
+import org.jclouds.azurecompute.domain.CreateStorageServiceParams;
 import org.jclouds.azurecompute.options.AzureComputeTemplateOptions;
 import org.jclouds.compute.config.CustomizationResponse;
 import org.jclouds.compute.domain.NodeMetadata;
@@ -217,11 +217,12 @@ public class GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes
                     + "Please, try by choosing a different `storageAccountName` in templateOptions and try again", name));
          }
          logger.debug("Creating a storage service account '%s' in location '%s' ...", name, location);
-         final String createStorateServiceRequestId = api.getStorageAccountApi().create(StorageServiceParams.builder()
-                 .name(name)
+         final String createStorateServiceRequestId = api.getStorageAccountApi().create(
+                 CreateStorageServiceParams.builder()
+                 .serviceName(name)
                  .label(name)
                  .location(location)
-                 .accountType(StorageServiceParams.Type.valueOf(type))
+                 .accountType(StorageService.AccountType.valueOf(type))
                  .build());
          if (!operationSucceededPredicate.apply(createStorateServiceRequestId)) {
             final String warnMessage = format("Create storage service account has not been completed within %sms.",
@@ -280,7 +281,7 @@ public class GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes
    }
 
    private boolean checkAvailability(final String name) {
-      return api.getStorageAccountApi().checkAvailable(name).result();
+      return api.getStorageAccountApi().isAvailable(name).result();
    }
 
    private static String generateStorageServiceName(final String prefix) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CreateStorageServiceParams.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CreateStorageServiceParams.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CreateStorageServiceParams.java
new file mode 100644
index 0000000..64bd9c3
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CreateStorageServiceParams.java
@@ -0,0 +1,161 @@
+/*
+ * 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.azurecompute.domain;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.jclouds.azurecompute.domain.StorageService.AccountType;
+import org.jclouds.javax.annotation.Nullable;
+
+@AutoValue
+public abstract class CreateStorageServiceParams {
+
+   CreateStorageServiceParams() {
+   } // For AutoValue only!
+
+   /**
+    * A name for the storage account that is unique within Azure. Storage account names must be between 3 and 24
+    * characters in length and use numbers and lower-case letters only.
+    */
+   public abstract String serviceName();
+
+   /**
+    * A description for the storage account. The description may be up to 1024 characters in length.
+    */
+   @Nullable
+   public abstract String description();
+
+   /**
+    * A label for the storage account specified as a base64-encoded string. The label may be up to 100 characters in
+    * length. The label can be used identify the storage account for your tracking purposes.
+    */
+   public abstract String label();
+
+   /**
+    * Required if AffinityGroup is not specified. The location where the storage account is created.
+    */
+   @Nullable
+   public abstract String location();
+
+   /**
+    * Required if Location is not specified. The name of an existing affinity group in the specified subscription.
+    */
+   @Nullable
+   public abstract String affinityGroup();
+
+   /**
+    * Represents the name of an extended cloud service property. Each extended property must have both a defined name
+    * and value. You can have a maximum of 50 extended property name/value pairs.
+    *
+    * <p/>
+    * The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in
+    * the Name, and the name must start with a letter. Each extended property value has a maximum length of 255
+    * characters.
+    */
+   @Nullable
+   public abstract Map<String, String> extendedProperties();
+
+   /**
+    * Specifies whether the account supports locally-redundant storage, geo-redundant storage, zone-redundant storage,
+    * or read access geo-redundant storage.
+    */
+   public abstract AccountType accountType();
+
+   public Builder toBuilder() {
+      return builder().fromCreateStorageServiceParams(this);
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static final class Builder {
+
+      private String serviceName;
+
+      private String description;
+
+      private String label;
+
+      private String location;
+
+      private String affinityGroup;
+
+      private Map<String, String> extendedProperties;
+
+      private AccountType accountType;
+
+      public Builder serviceName(final String serviceName) {
+         this.serviceName = serviceName;
+         return this;
+      }
+
+      public Builder description(final String description) {
+         this.description = description;
+         return this;
+      }
+
+      public Builder label(final String label) {
+         this.label = label;
+         return this;
+      }
+
+      public Builder location(final String location) {
+         this.location = location;
+         return this;
+      }
+
+      public Builder affinityGroup(final String affinityGroup) {
+         this.affinityGroup = affinityGroup;
+         return this;
+      }
+
+      public Builder extendedProperties(final Map<String, String> extendedProperties) {
+         this.extendedProperties = extendedProperties;
+         return this;
+      }
+
+      public Builder accountType(final AccountType accountType) {
+         this.accountType = accountType;
+         return this;
+      }
+
+      public CreateStorageServiceParams build() {
+         return CreateStorageServiceParams.create(serviceName, description, label, location, affinityGroup,
+                 extendedProperties, accountType);
+      }
+
+      public Builder fromCreateStorageServiceParams(final CreateStorageServiceParams storageServiceParams) {
+         return serviceName(storageServiceParams.serviceName()).
+                 description(storageServiceParams.description()).
+                 label(storageServiceParams.label()).
+                 location(storageServiceParams.location()).
+                 affinityGroup(storageServiceParams.affinityGroup()).
+                 extendedProperties(storageServiceParams.extendedProperties()).
+                 accountType(storageServiceParams.accountType());
+      }
+   }
+
+   private static CreateStorageServiceParams create(
+           final String serviceName, final String description, final String label, final String location,
+           final String affinityGroup, final Map<String, String> extendedProperties, final AccountType accountType) {
+
+      return new AutoValue_CreateStorageServiceParams(serviceName, description, label, location, affinityGroup,
+              extendedProperties == null ? null : ImmutableMap.copyOf(extendedProperties), accountType);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageService.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageService.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageService.java
index adb04d9..bab3415 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageService.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageService.java
@@ -16,49 +16,226 @@
  */
 package org.jclouds.azurecompute.domain;
 
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import java.net.URL;
-
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 import org.jclouds.javax.annotation.Nullable;
 
-import com.google.auto.value.AutoValue;
-
 @AutoValue
 public abstract class StorageService {
 
+   public enum AccountType {
+
+      Standard_LRS,
+      Standard_ZRS,
+      Standard_GRS,
+      Standard_RAGRS,
+      Premium_LRS,
+      UNRECOGNIZED;
+
+      public static AccountType fromString(final String text) {
+         if (text != null) {
+            for (AccountType type : AccountType.values()) {
+               if (text.equalsIgnoreCase(type.name())) {
+                  return type;
+               }
+            }
+         }
+         return UNRECOGNIZED;
+      }
+   }
+
+   public enum RegionStatus {
+
+      Available,
+      Unavailable,
+      UNRECOGNIZED;
+
+      public static RegionStatus fromString(final String text) {
+         if (text != null) {
+            for (RegionStatus status : RegionStatus.values()) {
+               if (text.equalsIgnoreCase(status.name())) {
+                  return status;
+               }
+            }
+         }
+         return UNRECOGNIZED;
+      }
+
+   }
+
+   public enum Status {
+
+      Creating,
+      Created,
+      Deleting,
+      Deleted,
+      Changing,
+      ResolvingDns,
+      UNRECOGNIZED;
+
+      public static Status fromString(final String text) {
+         if (text != null) {
+            for (Status status : Status.values()) {
+               if (text.equalsIgnoreCase(status.name())) {
+                  return status;
+               }
+            }
+         }
+         return UNRECOGNIZED;
+      }
+   }
+
    @AutoValue
    public abstract static class StorageServiceProperties {
 
       StorageServiceProperties() {
       } // For AutoValue only!
 
+      /**
+       * A description for the storage account. The description can be up to 1024 characters in length.
+       */
       @Nullable
       public abstract String description();
 
-      public abstract String status();
+      /**
+       * Required if Location is not specified. The name of an existing affinity group associated with this
+       * subscription.
+       */
+      @Nullable
+      public abstract String affinityGroup();
 
+      /**
+       * Required if AffinityGroup is not specified. The location where the storage account will be created.
+       */
+      @Nullable
       public abstract String location();
 
-      public abstract String accountType();
+      /**
+       * A name for the hosted service that is base-64 encoded. The name can be up to 100 characters in length. The name
+       * can be used identify the storage account for your tracking purposes
+       */
+      public abstract String label();
+
+      /**
+       * The status of the storage account.
+       */
+      public abstract Status status();
+
+      /**
+       * Specifies the endpoints of the storage account.
+       */
+      @Nullable
+      public abstract List<URL> endpoints();
+
+      /**
+       * Indicates the primary geographical region in which the storage account exists at this time.
+       */
+      public abstract String geoPrimaryRegion();
+
+      /**
+       * Indicates whether the primary storage region is available.
+       */
+      public abstract RegionStatus statusOfPrimary();
+
+      /**
+       * A timestamp that indicates the most recent instance of a failover to the secondary region. In case of multiple
+       * failovers only the latest failover date and time maintained
+       */
+      @Nullable
+      public abstract Date lastGeoFailoverTime();
+
+      /**
+       * Indicates the geographical region in which the storage account is being replicated.
+       */
+      @Nullable
+      public abstract String geoSecondaryRegion();
+
+      /**
+       * Indicates whether the secondary storage region is available.
+       */
+      @Nullable
+      public abstract RegionStatus statusOfSecondary();
+
+      /**
+       * Specifies the time that the storage account was created.
+       */
+      public abstract Date creationTime();
 
-      public static StorageServiceProperties create(final String description, final String status,
-              final String location, final String accountType) {
+      /**
+       * Specifies the custom domains that are associated with the storage account.
+       */
+      @Nullable
+      public abstract List<String> customDomains();
 
-         return new AutoValue_StorageService_StorageServiceProperties(description, status, location, accountType);
+      /**
+       * Specifies the secondary endpoints of the storage account.
+       */
+      @Nullable
+      public abstract List<URL> secondaryEndpoints();
+
+      /**
+       * Specifies whether the account supports locally-redundant storage, geo-redundant storage, zone-redundant
+       * storage, or read access geo-redundant storage.
+       */
+      public abstract AccountType accountType();
+
+      public static StorageServiceProperties create(final String description, final String affinityGroup,
+              final String location, final String label, final Status status, final List<URL> endpoints,
+              final String geoPrimaryRegion, final RegionStatus statusOfPrimary,
+              final Date lastGeoFailoverTime, final String geoSecondaryRegion, final RegionStatus statusOfSecondary,
+              final Date creationTime, final List<String> customDomains, final List<URL> secondaryEndpoints,
+              final AccountType accountType) {
+
+         return new AutoValue_StorageService_StorageServiceProperties(description, affinityGroup, location,
+                 label, status, endpoints == null ? null : ImmutableList.copyOf(endpoints),
+                 geoPrimaryRegion, statusOfPrimary, lastGeoFailoverTime, geoSecondaryRegion, statusOfSecondary,
+                 creationTime, customDomains,
+                 secondaryEndpoints == null ? null : ImmutableList.copyOf(secondaryEndpoints), accountType);
       }
    }
 
    StorageService() {
    } // For AutoValue only!
 
+   /**
+    * Specifies the URI of the storage account.
+    */
    public abstract URL url();
 
+   /**
+    * Specifies the name of the storage account. This name is the DNS prefix name and can be used to access blobs,
+    * queues, and tables in the storage account.
+    */
    public abstract String serviceName();
 
+   /**
+    * Specifies the properties of the storage account.
+    */
    public abstract StorageServiceProperties storageServiceProperties();
 
+   /**
+    * Specifies the name and value of an extended property that was added to the storage account.
+    */
+   @Nullable
+   public abstract Map<String, String> extendedProperties();
+
+   /**
+    * Indicates whether the storage account is able to perform virtual machine related operations. If so, this element
+    * returns a string containing PersistentVMRole. Otherwise, this element will not be present.
+    */
+   @Nullable
+   public abstract String capability();
+
    public static StorageService create(final URL url, final String serviceName,
-           final StorageServiceProperties storageServiceProperties) {
+           final StorageServiceProperties storageServiceProperties, final Map<String, String> extendedProperties,
+           final String capability) {
 
-      return new AutoValue_StorageService(url, serviceName, storageServiceProperties);
+      return new AutoValue_StorageService(url, serviceName, storageServiceProperties,
+              extendedProperties == null ? null : ImmutableMap.copyOf(extendedProperties), capability);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceKeys.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceKeys.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceKeys.java
new file mode 100644
index 0000000..43f2ce0
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceKeys.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.domain;
+
+import com.google.auto.value.AutoValue;
+import java.net.URL;
+
+@AutoValue
+public abstract class StorageServiceKeys {
+
+   public enum KeyType {
+
+      Primary,
+      Secondary;
+
+   }
+
+   StorageServiceKeys() {
+   } // For AutoValue only!
+
+   /**
+    * The Service Management API request URI used to perform Get Storage Account Properties requests against the storage
+    * account.
+    */
+   public abstract URL url();
+
+   /**
+    * The primary access key for the storage account.
+    */
+   public abstract String primary();
+
+   /**
+    * The secondary access key for the storage account.
+    */
+   public abstract String secondary();
+
+   public static StorageServiceKeys create(final URL url, final String primary, final String secondary) {
+      return new AutoValue_StorageServiceKeys(url, primary, secondary);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceParams.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceParams.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceParams.java
deleted file mode 100644
index dfb38fe..0000000
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/StorageServiceParams.java
+++ /dev/null
@@ -1,104 +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.azurecompute.domain;
-
-import com.google.auto.value.AutoValue;
-
-// TODO: check which can be null.
-@AutoValue
-public abstract class StorageServiceParams {
-
-   public enum Type {
-
-      Standard_LRS,
-      Standard_ZRS,
-      Standard_GRS,
-      Standard_RAGRS,
-      Premium_LRS;
-
-   }
-
-   StorageServiceParams() {
-   } // For AutoValue only!
-
-   /**
-    * The user-supplied name for this deployment.
-    */
-   public abstract String name();
-
-   public abstract String label();
-
-   public abstract String location();
-
-   public abstract Type accountType();
-
-   public Builder toBuilder() {
-      return builder().fromStorageServiceParams(this);
-   }
-
-   public static Builder builder() {
-      return new Builder();
-   }
-
-   public static final class Builder {
-
-      private String name;
-
-      private String label;
-
-      private String location;
-
-      private Type accountType;
-
-      public Builder name(final String name) {
-         this.name = name;
-         return this;
-      }
-
-      public Builder label(final String label) {
-         this.label = label;
-         return this;
-      }
-
-      public Builder location(final String location) {
-         this.location = location;
-         return this;
-      }
-
-      public Builder accountType(final Type accountType) {
-         this.accountType = accountType;
-         return this;
-      }
-
-      public StorageServiceParams build() {
-         return StorageServiceParams.create(name, label, location, accountType);
-      }
-
-      public Builder fromStorageServiceParams(final StorageServiceParams storageServiceParams) {
-         return name(storageServiceParams.name())
-                 .label(storageServiceParams.label())
-                 .location(storageServiceParams.location())
-                 .accountType(storageServiceParams.accountType());
-      }
-   }
-
-   private static StorageServiceParams create(
-           final String name, final String label, final String location, final Type accountType) {
-
-      return new AutoValue_StorageServiceParams(name, label, location, accountType);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/domain/UpdateStorageServiceParams.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/UpdateStorageServiceParams.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/UpdateStorageServiceParams.java
new file mode 100644
index 0000000..e62558d
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/UpdateStorageServiceParams.java
@@ -0,0 +1,190 @@
+/*
+ * 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.azurecompute.domain;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import org.jclouds.javax.annotation.Nullable;
+
+@AutoValue
+public abstract class UpdateStorageServiceParams {
+
+   public enum AccountType {
+
+      Standard_LRS,
+      Standard_GRS,
+      Standard_RAGRS;
+
+   }
+
+   /**
+    * Specifies information about a custom domain that is associated with the storage account.
+    */
+   @AutoValue
+   public abstract static class CustomDomain {
+
+      CustomDomain() {
+      } // For AutoValue only!
+
+      /**
+       * Specifies the name of the custom domain.
+       */
+      public abstract String name();
+
+      /**
+       * Indicates whether indirect CName validation is enabled.
+       */
+      public abstract Boolean useSubDomainName();
+
+      public static CustomDomain create(final String name, final boolean useSubDomainName) {
+         return new AutoValue_UpdateStorageServiceParams_CustomDomain(name, useSubDomainName);
+      }
+   }
+
+   UpdateStorageServiceParams() {
+   } // For AutoValue only!
+
+   /**
+    * Specifies a base-64 encoded name for the storage account. The label may be up to 100 characters in length. The
+    * label can be used identify the storage account for your tracking purposes. You must specify a value for either
+    * Label or Description, or for both.
+    */
+   @Nullable
+   public abstract String label();
+
+   /**
+    * A description for the storage account. The description may be up to 1024 characters in length. You must specify a
+    * value for either Label or Description, or for both.
+    */
+   @Nullable
+   public abstract String description();
+
+   /**
+    * Enables or disables geo-replication on the specified the storage. If set to true, the data in the storage account
+    * is replicated across more than one geographic location so as to enable resilience in the face of catastrophic
+    * service loss. If set to false, geo-replication is disabled. If the element is not included in the request body,
+    * the current value is left unchanged.
+    */
+   @Nullable
+   public abstract Boolean geoReplicationEnabled();
+
+   /**
+    * Represents the name of an extended cloud service property. Each extended property must have both a defined name
+    * and value. You can have a maximum of 50 extended property name/value pairs.
+    *
+    * <p/>
+    * The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in
+    * the Name, and the name must start with a letter. Each extended property value has a maximum length of 255
+    * characters.
+    */
+   @Nullable
+   public abstract Map<String, String> extendedProperties();
+
+   /**
+    * Specifies the custom domains that are associated with the storage account.
+    */
+   @Nullable
+   public abstract List<CustomDomain> customDomains();
+
+   /**
+    * Specifies whether the account supports locally-redundant storage, geo-redundant storage, or read access
+    * geo-redundant storage. Zone-redundant storage is not an option when you update a storage account.
+    */
+   @Nullable
+   public abstract AccountType accountType();
+
+   public Builder toBuilder() {
+      return builder().fromUpdateStorageServiceParams(this);
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static final class Builder {
+
+      private String label;
+
+      private String description;
+
+      private Boolean geoReplicationEnabled;
+
+      private Map<String, String> extendedProperties;
+
+      private List<CustomDomain> customDomains;
+
+      private AccountType accountType;
+
+      public Builder label(final String label) {
+         this.label = label;
+         return this;
+      }
+
+      public Builder description(final String description) {
+         this.description = description;
+         return this;
+      }
+
+      public Builder geoReplicationEnabled(final Boolean geoReplicationEnabled) {
+         this.geoReplicationEnabled = geoReplicationEnabled;
+         return this;
+      }
+
+      public Builder extendedProperties(final Map<String, String> extendedProperties) {
+         this.extendedProperties = extendedProperties;
+         return this;
+      }
+
+      public Builder customDomains(final List<CustomDomain> customDomains) {
+         this.customDomains = customDomains;
+         return this;
+      }
+
+      public Builder accountType(final AccountType accountType) {
+         this.accountType = accountType;
+         return this;
+      }
+
+      public UpdateStorageServiceParams build() {
+         return UpdateStorageServiceParams.create(label, description,
+                 geoReplicationEnabled, extendedProperties, customDomains, accountType);
+      }
+
+      public Builder fromUpdateStorageServiceParams(final UpdateStorageServiceParams storageServiceParams) {
+         return label(storageServiceParams.label()).
+                 description(storageServiceParams.description()).
+                 geoReplicationEnabled(storageServiceParams.geoReplicationEnabled()).
+                 extendedProperties(storageServiceParams.extendedProperties()).
+                 customDomains(storageServiceParams.customDomains()).
+                 accountType(storageServiceParams.accountType());
+      }
+   }
+
+   private static UpdateStorageServiceParams create(final String label, final String description,
+           final Boolean geoReplicationEnabled,
+           final Map<String, String> extendedProperties, final List<CustomDomain> customDomains,
+           final AccountType accountType) {
+
+      return new AutoValue_UpdateStorageServiceParams(label, description, geoReplicationEnabled,
+              extendedProperties == null ? null : ImmutableMap.copyOf(extendedProperties),
+              customDomains == null ? null : ImmutableList.copyOf(customDomains),
+              accountType);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/features/StorageAccountApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/StorageAccountApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/StorageAccountApi.java
index 92efd1d..336cdc7 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/features/StorageAccountApi.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/StorageAccountApi.java
@@ -16,8 +16,6 @@
  */
 package org.jclouds.azurecompute.features;
 
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-
 import java.util.List;
 
 import javax.inject.Named;
@@ -25,6 +23,7 @@ import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -32,39 +31,69 @@ import javax.ws.rs.core.MediaType;
 
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
-import org.jclouds.azurecompute.binders.StorageServiceParamsToXML;
+import org.jclouds.azurecompute.binders.StorageServiceKeyTypeToXML;
+import org.jclouds.azurecompute.binders.CreateStorageServiceParamsToXML;
+import org.jclouds.azurecompute.binders.UpdateStorageServiceParamsToXML;
 import org.jclouds.azurecompute.domain.Availability;
 import org.jclouds.azurecompute.domain.StorageService;
-import org.jclouds.azurecompute.domain.StorageServiceParams;
+import org.jclouds.azurecompute.domain.StorageServiceKeys;
+import org.jclouds.azurecompute.domain.StorageServiceKeys.KeyType;
+import org.jclouds.azurecompute.domain.CreateStorageServiceParams;
+import org.jclouds.azurecompute.domain.UpdateStorageServiceParams;
 import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
 import org.jclouds.azurecompute.xml.AvailabilityHandler;
 import org.jclouds.azurecompute.xml.ListStorageServicesHandler;
 import org.jclouds.azurecompute.xml.StorageServiceHandler;
+import org.jclouds.azurecompute.xml.StorageServiceKeysHandler;
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.QueryParams;
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.XMLResponseParser;
 
+/**
+ * The Service Management API includes operations for managing the storage accounts in your subscription.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/azure/ee460790">docs</a>
+ */
 @Path("/services/storageservices")
 @Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Produces(MediaType.APPLICATION_XML)
 @Consumes(MediaType.APPLICATION_XML)
 public interface StorageAccountApi {
 
    /**
+    * The List Storage Accounts operation lists the storage accounts that are available in the specified subscription.
+    */
+   @Named("ListStorageAccounts")
+   @GET
+   @XMLResponseParser(ListStorageServicesHandler.class)
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<StorageService> list();
+
+   /**
     * The Create Storage Account asynchronous operation creates a new storage account in Microsoft Azure.
-    *
     */
    @Named("CreateStorageAccount")
    @POST
-   @Produces(APPLICATION_XML)
    @ResponseParser(ParseRequestIdHeader.class)
-   String create(@BinderParam(StorageServiceParamsToXML.class) StorageServiceParams storageServiceParams);
+   String create(@BinderParam(CreateStorageServiceParamsToXML.class) CreateStorageServiceParams storageServiceParams);
+
+   /**
+    * The Check Storage Account Name Availability operation checks to see if the specified storage account name is
+    * available, or if it has already been taken.
+    */
+   @Named("CheckStorageAccountNameAvailability")
+   @GET
+   @Path("/operations/isavailable/{storageAccountName}")
+   @XMLResponseParser(AvailabilityHandler.class)
+   Availability isAvailable(@PathParam("storageAccountName") String storageAccountName);
 
    /**
-    * https://management.core.windows.net/<subscription-id>/services/storageservices
+    * The Get Storage Account Properties operation returns system properties for the specified storage account.
     */
-   @Named("GetStorageAccountDetails")
+   @Named("GetStorageAccountProperties")
    @GET
    @Path("/{storageAccountName}")
    @XMLResponseParser(StorageServiceHandler.class)
@@ -72,23 +101,35 @@ public interface StorageAccountApi {
    StorageService get(@PathParam("storageAccountName") String storageAccountName);
 
    /**
-    * The List Storage Accounts operation lists the storage accounts that are available in the specified subscription.
+    * The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account.
     */
-   @Named("ListStorageAccounts")
+   @Named("GetStorageAccountKeys")
    @GET
-   @XMLResponseParser(ListStorageServicesHandler.class)
-   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
-   List<StorageService> list();
+   @Path("/{storageAccountName}/keys")
+   @XMLResponseParser(StorageServiceKeysHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   StorageServiceKeys getKeys(@PathParam("storageAccountName") String storageAccountName);
+
+   @Named("RegenerateStorageAccountKeys")
+   @POST
+   @Path("/{storageAccountName}/keys")
+   @QueryParams(keys = "action", values = "regenerate")
+   @ResponseParser(ParseRequestIdHeader.class)
+   String regenerateKeys(
+           @PathParam("storageAccountName") String storageAccountName,
+           @BinderParam(StorageServiceKeyTypeToXML.class) KeyType keyType);
 
    /**
-    * The Check Storage Account Name Availability operation checks to see if the specified storage account name is
-    * available, or if it has already been taken.
+    * The Update Storage Account asynchronous operation updates the label, the description, and enables or disables the
+    * geo-replication status for the specified storage account.
     */
-   @Named("CheckStorageAccountNameAvailability")
-   @GET
-   @Path("/operations/isavailable/{storageAccountName}")
-   @XMLResponseParser(AvailabilityHandler.class)
-   Availability checkAvailable(@PathParam("storageAccountName") String storageAccountName);
+   @Named("UpdateStorageAccount")
+   @PUT
+   @Path("/{storageAccountName}")
+   @ResponseParser(ParseRequestIdHeader.class)
+   String update(
+           @PathParam("storageAccountName") String storageAccountName,
+           @BinderParam(UpdateStorageServiceParamsToXML.class) UpdateStorageServiceParams storageServiceParams);
 
    @Named("DeleteStorageAccount")
    @DELETE

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/features/SubscriptionApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/SubscriptionApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/SubscriptionApi.java
index 08fb45a..96161ea 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/features/SubscriptionApi.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/SubscriptionApi.java
@@ -17,6 +17,7 @@
 package org.jclouds.azurecompute.features;
 
 import static org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+
 import java.util.List;
 
 import javax.inject.Named;
@@ -34,18 +35,18 @@ import org.jclouds.rest.annotations.XMLResponseParser;
 /**
  * The Service Management API includes operations for retrieving information about a subscription.
  *
- * @see <a href="http://msdn.microsoft.com/en-us/library/gg715315.aspx">docs</a>
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg715315">docs</a>
  */
 @Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
-@Path("/rolesizes")
 @Consumes(MediaType.APPLICATION_XML)
 public interface SubscriptionApi {
 
    /**
-    * The List Role Sizes request may be specified as follows.
+    * The List Role Sizes operation lists the role sizes that are available under the specified subscription.
     */
    @Named("ListRoleSizes")
    @GET
+   @Path("/rolesizes")
    @XMLResponseParser(ListRoleSizesHandler.class)
    @Fallback(EmptyListOnNotFoundOr404.class)
    List<RoleSize> listRoleSizes();

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ExtendedPropertiesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ExtendedPropertiesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ExtendedPropertiesHandler.java
new file mode 100644
index 0000000..aed874d
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ExtendedPropertiesHandler.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.azurecompute.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import com.google.common.collect.Lists;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class ExtendedPropertiesHandler extends DefaultHandler {
+
+   private final List<String> extendedProperties = Lists.newArrayList();
+
+   private final StringBuilder currentText = new StringBuilder();
+
+   public Map<String, String> getResult() {
+      final Map<String, String> result = new HashMap<String, String>();
+      for (int i = 0; i < extendedProperties.size(); i += 2) {
+         result.put(extendedProperties.get(i), extendedProperties.get(i + 1));
+      }
+      extendedProperties.clear();
+      return result;
+   }
+
+   @Override
+   public void endElement(final String uri, final String localName, final String qName) {
+      if ("Name".equals(qName) || "Value".equals(qName)) {
+         extendedProperties.add(currentOrNull(currentText));
+      }
+
+      currentText.setLength(0);
+   }
+
+   @Override
+   public void characters(final char ch[], final int start, final int length) {
+      currentText.append(ch, start, length);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListStorageServicesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListStorageServicesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListStorageServicesHandler.java
index e8b5785..82a5b85 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListStorageServicesHandler.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListStorageServicesHandler.java
@@ -34,7 +34,7 @@ public class ListStorageServicesHandler extends ParseSax.HandlerForGeneratedRequ
    private final ImmutableList.Builder<StorageService> storageAccounts = ImmutableList.builder();
 
    @Inject
-   ListStorageServicesHandler(StorageServiceHandler storageServiceHandler) {
+   ListStorageServicesHandler(final StorageServiceHandler storageServiceHandler) {
       this.storageServiceHandler = storageServiceHandler;
    }
 
@@ -44,8 +44,8 @@ public class ListStorageServicesHandler extends ParseSax.HandlerForGeneratedRequ
    }
 
    @Override
-   public void startElement(String url, String name, String qName, Attributes attributes) {
-      if (qName.equals("StorageService")) {
+   public void startElement(final String url, final String name, final String qName, final Attributes attributes) {
+      if ("StorageService".equals(qName)) {
          inStorageService = true;
       }
       if (inStorageService) {
@@ -54,8 +54,8 @@ public class ListStorageServicesHandler extends ParseSax.HandlerForGeneratedRequ
    }
 
    @Override
-   public void endElement(String uri, String name, String qName) {
-      if (qName.equals("StorageService")) {
+   public void endElement(final String uri, final String name, final String qName) {
+      if ("StorageService".equals(qName)) {
          inStorageService = false;
          storageAccounts.add(storageServiceHandler.getResult());
       } else if (inStorageService) {
@@ -64,7 +64,7 @@ public class ListStorageServicesHandler extends ParseSax.HandlerForGeneratedRequ
    }
 
    @Override
-   public void characters(char ch[], int start, int length) {
+   public void characters(final char ch[], final int start, final int length) {
       if (inStorageService) {
          storageServiceHandler.characters(ch, start, length);
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceHandler.java
index 0ea9445..f18a647 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceHandler.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceHandler.java
@@ -20,16 +20,17 @@ import static org.jclouds.util.SaxUtils.currentOrNull;
 
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Map;
 
 import org.jclouds.azurecompute.domain.StorageService;
 import org.jclouds.http.functions.ParseSax;
 import org.xml.sax.Attributes;
 
 import com.google.common.base.Throwables;
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import org.jclouds.date.DateService;
 
-/**
- * @see <a href="http://msdn.microsoft.com/en-us/library/ee460787.aspx" >api</a>
- */
 public class StorageServiceHandler extends ParseSax.HandlerForGeneratedRequestWithResult<StorageService> {
 
    private URL url;
@@ -40,13 +41,27 @@ public class StorageServiceHandler extends ParseSax.HandlerForGeneratedRequestWi
 
    private boolean inStorageServiceProperties;
 
-   private final StorageServicePropertiesHandler storageServicePropertiesHandler = new StorageServicePropertiesHandler();
+   private final StorageServicePropertiesHandler storageServicePropertiesHandler;
+
+   private final Map<String, String> extendedProperties = Maps.newHashMap();
+
+   private boolean inExtendedProperties;
+
+   private final ExtendedPropertiesHandler extendedPropertiesHandler = new ExtendedPropertiesHandler();
+
+   private String capability;
 
    private final StringBuilder currentText = new StringBuilder();
 
+   @Inject
+   StorageServiceHandler(final DateService dateService) {
+      this.storageServicePropertiesHandler = new StorageServicePropertiesHandler(dateService);
+   }
+
    @Override
    public StorageService getResult() {
-      StorageService result = StorageService.create(url, serviceName, storageServiceProperties);
+      final StorageService result = StorageService.create(
+              url, serviceName, storageServiceProperties, extendedProperties, capability);
       resetState(); // handler is called in a loop.
       return result;
    }
@@ -55,24 +70,37 @@ public class StorageServiceHandler extends ParseSax.HandlerForGeneratedRequestWi
       serviceName = null;
       url = null;
       storageServiceProperties = null;
+      extendedProperties.clear();
+      capability = null;
    }
 
    @Override
-   public void startElement(String uri, String localName, String qName, Attributes attributes) {
-      if (qName.equals("StorageServiceProperties")) {
+   public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
+      if ("StorageServiceProperties".equals(qName)) {
          inStorageServiceProperties = true;
+      } else if (inStorageServiceProperties) {
+         storageServicePropertiesHandler.startElement(uri, localName, qName, attributes);
+      } else if ("ExtendedProperties".equals(qName)) {
+         inExtendedProperties = true;
       }
    }
 
    @Override
-   public void endElement(String ignoredUri, String ignoredName, String qName) {
-      if (qName.equals("StorageServiceProperties")) {
-         storageServiceProperties = storageServicePropertiesHandler.getResult();
+   public void endElement(final String ignoredUri, final String ignoredName, final String qName) {
+      if ("StorageServiceProperties".equals(qName)) {
          inStorageServiceProperties = false;
+         storageServiceProperties = storageServicePropertiesHandler.getResult();
       } else if (inStorageServiceProperties) {
          storageServicePropertiesHandler.endElement(ignoredUri, ignoredName, qName);
-      } else if (qName.equals("Url")) {
-         String urlText = currentOrNull(currentText);
+      } else if ("ExtendedProperties".equals(qName)) {
+         inExtendedProperties = false;
+         extendedProperties.putAll(extendedPropertiesHandler.getResult());
+      } else if (inExtendedProperties) {
+         extendedPropertiesHandler.endElement(ignoredUri, ignoredName, qName);
+      } else if ("ServiceName".equals(qName)) {
+         serviceName = currentOrNull(currentText);
+      } else if ("Url".equals(qName)) {
+         final String urlText = currentOrNull(currentText);
          if (urlText != null) {
             try {
                url = new URL(urlText);
@@ -80,16 +108,19 @@ public class StorageServiceHandler extends ParseSax.HandlerForGeneratedRequestWi
                throw Throwables.propagate(e);
             }
          }
-      } else if (qName.equals("ServiceName")) {
-         serviceName = currentOrNull(currentText);
+      } else if ("Capability".equals(qName)) {
+         capability = currentOrNull(currentText);
       }
+
       currentText.setLength(0);
    }
 
    @Override
-   public void characters(char ch[], int start, int length) {
+   public void characters(final char ch[], final int start, final int length) {
       if (inStorageServiceProperties) {
          storageServicePropertiesHandler.characters(ch, start, length);
+      } else if (inExtendedProperties) {
+         extendedPropertiesHandler.characters(ch, start, length);
       } else {
          currentText.append(ch, start, length);
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceKeysHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceKeysHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceKeysHandler.java
new file mode 100644
index 0000000..75073f8
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServiceKeysHandler.java
@@ -0,0 +1,70 @@
+/*
+ * 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.azurecompute.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import com.google.common.base.Throwables;
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.jclouds.azurecompute.domain.StorageServiceKeys;
+import org.jclouds.http.functions.ParseSax;
+
+public class StorageServiceKeysHandler extends ParseSax.HandlerForGeneratedRequestWithResult<StorageServiceKeys> {
+
+   private URL url;
+
+   private String primary;
+
+   private String secondary;
+
+   private final StringBuilder currentText = new StringBuilder();
+
+   @Override
+   public StorageServiceKeys getResult() {
+      final StorageServiceKeys result = StorageServiceKeys.create(url, primary, secondary);
+      url = null;
+      primary = null;
+      secondary = null;
+      return result;
+   }
+
+   @Override
+   public void endElement(final String ignoredUri, final String ignoredName, final String qName) {
+      if ("Url".equals(qName)) {
+         final String urlText = currentOrNull(currentText);
+         if (urlText != null) {
+            try {
+               url = new URL(urlText);
+            } catch (MalformedURLException e) {
+               throw Throwables.propagate(e);
+            }
+         }
+      } else if ("Primary".equals(qName)) {
+         primary = currentOrNull(currentText);
+      } else if ("Secondary".equals(qName)) {
+         secondary = currentOrNull(currentText);
+      }
+      
+      currentText.setLength(0);
+   }
+
+   @Override
+   public void characters(final char ch[], final int start, final int length) {
+      currentText.append(ch, start, length);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServicePropertiesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServicePropertiesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServicePropertiesHandler.java
index f1bcd92..37cbe96 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServicePropertiesHandler.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/StorageServicePropertiesHandler.java
@@ -16,46 +16,160 @@
  */
 package org.jclouds.azurecompute.xml;
 
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.io.BaseEncoding.base64;
 import static org.jclouds.util.SaxUtils.currentOrNull;
 
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+import java.util.List;
+
 import org.jclouds.azurecompute.domain.StorageService;
+import org.jclouds.azurecompute.domain.StorageService.AccountType;
+import org.jclouds.azurecompute.domain.StorageService.RegionStatus;
+import org.jclouds.azurecompute.domain.StorageService.Status;
+import org.jclouds.date.DateService;
 import org.jclouds.http.functions.ParseSax;
 
-public class StorageServicePropertiesHandler extends ParseSax.HandlerForGeneratedRequestWithResult<StorageService.StorageServiceProperties> {
+import org.xml.sax.Attributes;
+
+public class StorageServicePropertiesHandler
+        extends ParseSax.HandlerForGeneratedRequestWithResult<StorageService.StorageServiceProperties> {
 
    private String description;
 
-   private String status;
+   private String affinityGroup;
 
    private String location;
 
-   private String accountType;
+   private String label;
+
+   private StorageService.Status status;
+
+   private final List<URL> endpoints = Lists.newArrayList();
+
+   private boolean inEndpoints;
+
+   private String geoPrimaryRegion;
+
+   private StorageService.RegionStatus statusOfPrimary;
+
+   private Date lastGeoFailoverTime;
+
+   private String geoSecondaryRegion;
+
+   private StorageService.RegionStatus statusOfSecondary;
+
+   private Date creationTime;
+
+   private final List<String> customDomains = Lists.newArrayList();
+
+   private final List<URL> secondaryEndpoints = Lists.newArrayList();
+
+   private boolean inSecondaryEndpoints;
+
+   private AccountType accountType;
+
+   private final DateService dateService;
 
    private final StringBuilder currentText = new StringBuilder();
 
+   public StorageServicePropertiesHandler(final DateService dateService) {
+      this.dateService = dateService;
+   }
+
    @Override
    public StorageService.StorageServiceProperties getResult() {
-      StorageService.StorageServiceProperties result = StorageService.StorageServiceProperties.create(description, status, location, accountType);
-      description = status = location = accountType = null; // handler could be called in a loop.
+      final StorageService.StorageServiceProperties result = StorageService.StorageServiceProperties.create(
+              description, affinityGroup, location, label, status, endpoints,
+              geoPrimaryRegion, statusOfPrimary, lastGeoFailoverTime, geoSecondaryRegion, statusOfSecondary,
+              creationTime, customDomains, secondaryEndpoints, accountType);
+
+      description = affinityGroup = location = label = null;
+      status = null;
+      endpoints.clear();
+      geoPrimaryRegion = null;
+      statusOfPrimary = null;
+      lastGeoFailoverTime = null;
+      geoSecondaryRegion = null;
+      statusOfSecondary = null;
+      creationTime = null;
+      customDomains.clear();
+      secondaryEndpoints.clear();
+      accountType = null;
+
       return result;
    }
 
    @Override
-   public void endElement(String ignoredUri, String ignoredName, String qName) {
-      if (qName.equals("Description")) {
+   public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
+      if ("Endpoints".equals(qName)) {
+         inEndpoints = true;
+      } else if ("SecondaryEndpoints".equals(qName)) {
+         inSecondaryEndpoints = true;
+      }
+   }
+
+   @Override
+   public void endElement(final String ignoredUri, final String ignoredName, final String qName) {
+      if ("Description".equals(qName)) {
          description = currentOrNull(currentText);
-      } else if (qName.equals("Status")) {
-         status = currentOrNull(currentText);
-      } else if (qName.equals("Location")) {
+      } else if ("AffinityGroup".equals(qName)) {
+         affinityGroup = currentOrNull(currentText);
+      } else if ("Location".equals(qName)) {
          location = currentOrNull(currentText);
-      } else if (qName.equals("AccountType")) {
-         accountType = currentOrNull(currentText);
+      } else if ("Label".equals(qName)) {
+         label = new String(base64().decode(currentOrNull(currentText)), UTF_8);
+      } else if ("Status".equals(qName)) {
+         status = Status.fromString(currentOrNull(currentText));
+      } else if ("Endpoints".equals(qName)) {
+         inEndpoints = false;
+      } else if ("SecondaryEndpoints".equals(qName)) {
+         inSecondaryEndpoints = false;
+      } else if ("Endpoint".equals(qName)) {
+         final String urlText = currentOrNull(currentText);
+         try {
+            if (inEndpoints) {
+               endpoints.add(new URL(urlText));
+            } else if (inSecondaryEndpoints) {
+               secondaryEndpoints.add(new URL(urlText));
+            }
+         } catch (MalformedURLException e) {
+            throw Throwables.propagate(e);
+         }
+      } else if ("GeoPrimaryRegion".equals(qName)) {
+         geoPrimaryRegion = currentOrNull(currentText);
+      } else if ("StatusOfPrimary".equals(qName)) {
+         statusOfPrimary = RegionStatus.fromString(currentOrNull(currentText));
+      } else if ("LastGeoFailoverTime".equals(qName)) {
+         lastGeoFailoverTime = dateService.iso8601SecondsDateParse(currentOrNull(currentText));
+      } else if ("GeoSecondaryRegion".equals(qName)) {
+         geoSecondaryRegion = currentOrNull(currentText);
+      } else if ("StatusOfSecondary".equals(qName)) {
+         final String text = currentOrNull(currentText);
+         if (text != null) {
+            statusOfSecondary = RegionStatus.fromString(text);
+         }
+      } else if ("CreationTime".equals(qName)) {
+         creationTime = dateService.iso8601SecondsDateParse(currentOrNull(currentText));
+      } else if ("Name".equals(qName)) {
+         final String text = currentOrNull(currentText);
+         if (text != null) {
+            customDomains.add(text);
+         }
+      } else if ("AccountType".equals(qName)) {
+         accountType = AccountType.fromString(currentOrNull(currentText));
       }
+
       currentText.setLength(0);
    }
 
    @Override
-   public void characters(char ch[], int start, int length) {
+   public void characters(final char ch[], final int start, final int length) {
       currentText.append(ch, start, length);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/aac95744/azurecompute/src/test/java/org/jclouds/azurecompute/features/StorageAccountApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/StorageAccountApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/StorageAccountApiLiveTest.java
new file mode 100644
index 0000000..536be67
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/StorageAccountApiLiveTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.azurecompute.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.azurecompute.domain.CreateStorageServiceParams;
+import org.jclouds.azurecompute.domain.StorageService;
+import org.jclouds.azurecompute.domain.StorageServiceKeys;
+import org.jclouds.azurecompute.domain.UpdateStorageServiceParams;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiLiveTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "StorageAccountApiLiveTest")
+public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest {
+
+   private static final String NAME = String.format("%3.24s",
+           RAND + StorageAccountApiLiveTest.class.getSimpleName().toLowerCase());
+
+   private void check(final StorageService storage) {
+      assertNotNull(storage.url());
+      assertNotNull(storage.serviceName());
+      assertNotNull(storage.storageServiceProperties());
+      assertNotNull(storage.storageServiceProperties().accountType());
+      assertFalse(storage.storageServiceProperties().endpoints().isEmpty());
+      assertNotNull(storage.storageServiceProperties().creationTime());
+   }
+
+   public void testList() {
+      for (StorageService storage : api().list()) {
+         check(storage);
+      }
+   }
+
+   public void testIsAvailable() {
+      assertTrue(api().isAvailable(NAME).result());
+   }
+
+   @Test(dependsOnMethods = "testIsAvailable")
+   public void testCreate() {
+      final CreateStorageServiceParams params = CreateStorageServiceParams.builder().
+              serviceName(NAME).
+              description("description").
+              label("label").
+              location(LOCATION).
+              extendedProperties(ImmutableMap.of("property_name", "property_value")).
+              accountType(StorageService.AccountType.Standard_ZRS).
+              build();
+      final String requestId = api().create(params);
+      assertTrue(operationSucceeded.apply(requestId), requestId);
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testGet() {
+      final StorageService service = api().get(NAME);
+      assertNotNull(service);
+      assertEquals(service.serviceName(), NAME);
+      assertEquals(service.storageServiceProperties().description(), "description");
+      assertEquals(service.storageServiceProperties().location(), LOCATION);
+      assertEquals(service.storageServiceProperties().label(), "label");
+      assertEquals(service.storageServiceProperties().accountType(), StorageService.AccountType.Standard_ZRS);
+      assertTrue(service.extendedProperties().containsKey("property_name"));
+      assertEquals(service.extendedProperties().get("property_name"), "property_value");
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testGetKeys() {
+      final StorageServiceKeys keys = api().getKeys(NAME);
+      assertNotNull(keys);
+      assertNotNull(keys.url());
+      assertNotNull(keys.primary());
+      assertNotNull(keys.secondary());
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testRegenerateKeys() {
+      final String requestId = api().regenerateKeys(NAME, StorageServiceKeys.KeyType.Primary);
+      assertTrue(operationSucceeded.apply(requestId), requestId);
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testUpdate() {
+      final UpdateStorageServiceParams params = UpdateStorageServiceParams.builder().
+              extendedProperties(ImmutableMap.of("another_property_name", "another_property_value")).
+              build();
+      final String requestId = api().update(NAME, params);
+      assertTrue(operationSucceeded.apply(requestId), requestId);
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void testDelete() {
+      final String requestId = api().delete(NAME);
+      assertTrue(operationSucceeded.apply(requestId), requestId);
+   }
+
+   private StorageAccountApi api() {
+      return api.getStorageAccountApi();
+   }
+}