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 2016/04/19 16:34:23 UTC

jclouds-labs git commit: JCLOUDS-664 Azurecompute-arm StorageAccountApi

Repository: jclouds-labs
Updated Branches:
  refs/heads/master b1752c9a0 -> b82378c2b


JCLOUDS-664 Azurecompute-arm StorageAccountApi


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

Branch: refs/heads/master
Commit: b82378c2be69467fcae7197c6dfe0ea1571fd8fd
Parents: b1752c9
Author: Rita Zhang <ri...@gmail.com>
Authored: Wed Apr 13 15:07:19 2016 -0700
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Apr 19 16:28:09 2016 +0200

----------------------------------------------------------------------
 .../azurecompute/arm/AzureComputeApi.java       |  12 +
 .../azurecompute/arm/domain/Availability.java   |  32 ++
 .../azurecompute/arm/domain/ResourceGroup.java  |   4 +-
 .../azurecompute/arm/domain/StorageService.java | 183 ++++++++++
 .../arm/domain/StorageServiceKeys.java          |  39 +++
 .../arm/domain/StorageServiceUpdateParams.java  |  64 ++++
 .../arm/features/StorageAccountApi.java         | 166 +++++++++
 .../azurecompute/arm/functions/FalseOn204.java  |  40 +++
 .../arm/functions/ParseJobStatus.java           |  12 +-
 .../azurecompute/arm/util/GetEnumValue.java     |  36 ++
 .../arm/features/StorageAccountApiLiveTest.java | 133 +++++++
 .../arm/features/StorageAccountApiMockTest.java | 347 +++++++++++++++++++
 .../internal/BaseAzureComputeApiLiveTest.java   |  60 ++++
 .../internal/BaseAzureComputeApiMockTest.java   |   5 +
 .../resources/isavailablestorageservice.json    |   3 +
 .../src/test/resources/storageAccounts.json     |  90 +++++
 .../test/resources/storageCreateResponse.json   |   9 +
 .../src/test/resources/storageaccountkeys.json  |   4 +
 .../test/resources/storageaccountupdate.json    |   7 +
 .../src/test/resources/storageservices.json     |  30 ++
 20 files changed, 1265 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
index 1e7cb91..4204328 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java
@@ -21,8 +21,11 @@ import java.io.Closeable;
 import org.jclouds.azurecompute.arm.features.JobApi;
 import org.jclouds.azurecompute.arm.features.LocationApi;
 import org.jclouds.azurecompute.arm.features.ResourceGroupApi;
+import org.jclouds.azurecompute.arm.features.StorageAccountApi;
 import org.jclouds.rest.annotations.Delegate;
 
+import javax.ws.rs.PathParam;
+
 /**
  * The Azure Resource Manager API is a REST API for managing your services and deployments.
  * <p/>
@@ -49,4 +52,13 @@ public interface AzureComputeApi extends Closeable {
     */
    @Delegate
    LocationApi getLocationApi();
+
+   /**
+    * The Azure Resource Manager API includes operations for managing the storage accounts in your subscription.
+    *
+    * @see <https://msdn.microsoft.com/en-us/library/mt163683.aspx">docs</a>
+    */
+   @Delegate
+   StorageAccountApi getStorageAccountApi(@PathParam("resourceGroup") String resourceGroup);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java
new file mode 100644
index 0000000..eb8c341
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java
@@ -0,0 +1,32 @@
+/*
+ * 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.arm.domain;
+
+import com.google.auto.value.AutoValue;
+import org.jclouds.json.SerializedNames;
+
+@AutoValue
+public abstract class Availability {
+
+   public abstract String nameAvailable();
+
+   @SerializedNames({"nameAvailable"})
+   public static Availability create(final String nameAvailable) {
+      return new AutoValue_Availability(nameAvailable);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java
index 1be93ab..08c4185 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java
@@ -40,12 +40,12 @@ public abstract class ResourceGroup {
    public abstract String id();
    public abstract String name();
    public abstract String location();
-   @Nullable
+
    public abstract Map<String, String> tags();
    public abstract ResourceGroupProperties properties();
 
    @SerializedNames({"id", "name", "location", "tags", "properties"})
-   public static ResourceGroup create(String id, String name, String location, @Nullable Map<String, String> tags, ResourceGroupProperties properties) {
+   public static ResourceGroup create(String id, String name, String location, Map<String, String> tags, ResourceGroupProperties properties) {
       return new AutoValue_ResourceGroup(id, name, location, tags == null ? ImmutableMap.<String, String>builder().build() : ImmutableMap.copyOf(tags), properties);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java
new file mode 100644
index 0000000..08709d8
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java
@@ -0,0 +1,183 @@
+/*
+ * 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.arm.domain;
+
+import com.google.auto.value.AutoValue;
+import java.util.Date;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import org.jclouds.azurecompute.arm.util.GetEnumValue;
+
+@AutoValue
+public abstract class StorageService {
+
+   public enum AccountType {
+
+      Standard_LRS,
+      Standard_ZRS,
+      Standard_GRS,
+      Standard_RAGRS,
+      Premium_LRS,
+      UNRECOGNIZED;
+
+       public static AccountType fromValue(final String text) {
+           return (AccountType) GetEnumValue.fromValueOrDefault(text, AccountType.UNRECOGNIZED);
+       }
+   }
+
+   public enum RegionStatus {
+
+       Available,
+       Unavailable,
+       UNRECOGNIZED;
+
+       public static RegionStatus fromValue(final String text) {
+           return (RegionStatus) GetEnumValue.fromValueOrDefault(text, RegionStatus.UNRECOGNIZED);
+       }
+
+   }
+
+   public enum Status {
+
+       Creating,
+       Created,
+       Deleting,
+       Deleted,
+       Changing,
+       ResolvingDns,
+       Succeeded,
+       UNRECOGNIZED;
+
+       public static Status fromValue(final String text) {
+           return (Status) GetEnumValue.fromValueOrDefault(text, Status.UNRECOGNIZED);
+       }
+   }
+
+   @AutoValue
+   public abstract static class StorageServiceProperties {
+
+       /**
+        * Specifies whether the account supports locally-redundant storage, geo-redundant storage, zone-redundant
+        * storage, or read access geo-redundant storage.
+        */
+       public abstract AccountType accountType();
+
+       /**
+        * Specifies the time that the storage account was created.
+        */
+       public abstract Date creationTime();
+
+       /**
+        * Specifies the endpoints of the storage account.
+        */
+       public abstract Map<String, String> primaryEndpoints();
+
+       /**
+       * A primaryLocation for the storage account.
+       */
+      @Nullable
+      public abstract String primaryLocation();
+
+      /**
+       * provisioningState for the storage group
+       */
+      @Nullable
+      public abstract Status provisioningState();
+
+       /**
+        * Specifies the secondary endpoints of the storage account.
+        */
+       public abstract Map<String, String> secondaryEndpoints();
+
+      /**
+       * Secondary location for the storage group
+       */
+      @Nullable
+      public abstract String secondaryLocation();
+
+      /**
+       * The status of primary endpoints
+       */
+      @Nullable
+      public abstract RegionStatus statusOfPrimary();
+
+      /**
+       * The secondary status of the storage account.
+       */
+      @Nullable
+      public abstract RegionStatus statusOfSecondary();
+
+
+      @SerializedNames({"accountType", "creationTime", "primaryEndpoints",  "primaryLocation",
+              "provisioningState", "secondaryEndpoints", "secondaryLocation", "statusOfPrimary", "statusOfSecondary"})
+      public static StorageServiceProperties create(final AccountType accountType, final Date creationTime,
+              final Map<String, String> primaryEndpoints, final String primaryLocation, final Status provisioningState,
+              final Map<String, String> secondaryEndpoints, final String secondaryLocation,
+              final RegionStatus statusOfPrimary, final RegionStatus statusOfSecondary) {
+
+         return new AutoValue_StorageService_StorageServiceProperties(accountType, creationTime,
+                 primaryEndpoints == null ? ImmutableMap.<String, String>builder().build() : ImmutableMap.copyOf(primaryEndpoints), primaryLocation, provisioningState,
+                 secondaryEndpoints == null ? ImmutableMap.<String, String>builder().build() : ImmutableMap.copyOf(secondaryEndpoints), secondaryLocation, statusOfPrimary, statusOfSecondary);
+      }
+   }
+
+   /**
+    * Specifies the id of the storage account.
+    */
+   @Nullable
+   public abstract String id();
+
+   /**
+    * 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.
+    */
+   @Nullable
+   public abstract String name();
+
+   /**
+    * Specifies the location of the storage account.
+    */
+   public abstract String location();
+
+   /**
+    * Specifies the tags of the storage account.
+    */
+   public abstract Map<String, String> tags();
+
+   /**
+    * Specifies the type of the storage account.
+    */
+   @Nullable
+   public abstract String type();
+
+   /**
+    * Specifies the properties of the storage account.
+    */
+   public abstract StorageServiceProperties storageServiceProperties();
+
+
+   @SerializedNames({"id", "name", "location", "tags", "type", "properties"})
+   public static StorageService create(final String id,  final String name,  final String location,
+                                       final Map<String, String> tags,  final String type,
+                                       final StorageServiceProperties storageServiceProperties) {
+      return new AutoValue_StorageService(id,  name,  location,  tags == null ? ImmutableMap.<String, String>builder().build() : ImmutableMap.copyOf(tags), type, storageServiceProperties);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java
new file mode 100644
index 0000000..63cb70b
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.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.azurecompute.arm.domain;
+
+import com.google.auto.value.AutoValue;
+import org.jclouds.json.SerializedNames;
+
+@AutoValue
+public abstract class StorageServiceKeys {
+
+   /**
+    * The primary access key for the storage account.
+    */
+   public abstract String key1();
+
+   /**
+    * The secondary access key for the storage account.
+    */
+   public abstract String key2();
+
+   @SerializedNames({"key1", "key2"})
+   public static StorageServiceKeys create(final String key1, final String key2) {
+      return new AutoValue_StorageServiceKeys(key1, key2);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java
new file mode 100644
index 0000000..85b8b6d
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java
@@ -0,0 +1,64 @@
+/*
+ * 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.arm.domain;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+import java.util.Map;
+
+@AutoValue
+public abstract class StorageServiceUpdateParams {
+
+   @AutoValue
+   public abstract static class StorageServiceUpdateProperties {
+
+       /**
+        * Specifies whether the account supports locally-redundant storage, geo-redundant storage, zone-redundant
+        * storage, or read access geo-redundant storage.
+        * Note: This implementation is for version 2015-10-01 and earlier.
+        * For version 2016-01-01 or later, refer to https://msdn.microsoft.com/en-us/library/mt163639.aspx
+        */
+       @Nullable
+       public abstract StorageService.AccountType accountType();
+
+
+      @SerializedNames({"accountType"})
+      public static StorageServiceUpdateProperties create(final StorageService.AccountType accountType) {
+
+         return new AutoValue_StorageServiceUpdateParams_StorageServiceUpdateProperties(accountType);
+      }
+   }
+
+   /**
+    * Specifies the tags of the storage account.
+    */
+   public abstract Map<String, String> tags();
+
+   /**
+    * Specifies the properties of the storage account.
+    */
+   public abstract StorageServiceUpdateProperties storageServiceProperties();
+
+
+   @SerializedNames({"tags", "properties"})
+   public static StorageServiceUpdateParams create(final Map<String, String> tags,
+                                                   final StorageServiceUpdateProperties storageServiceProperties) {
+      return new AutoValue_StorageServiceUpdateParams(tags == null ? ImmutableMap.<String, String>builder().build() : ImmutableMap.copyOf(tags), storageServiceProperties);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java
new file mode 100644
index 0000000..8ebfc82
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java
@@ -0,0 +1,166 @@
+/*
+ * 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.arm.features;
+
+import javax.inject.Named;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.POST;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks;
+import org.jclouds.azurecompute.arm.domain.Availability;
+import org.jclouds.azurecompute.arm.domain.StorageService;
+import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
+import org.jclouds.azurecompute.arm.domain.StorageServiceUpdateParams;
+import org.jclouds.azurecompute.arm.functions.FalseOn204;
+import org.jclouds.azurecompute.arm.functions.URIParser;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.oauth.v2.filters.OAuthFilter;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PATCH;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import java.util.List;
+import java.util.Map;
+import java.net.URI;
+
+/**
+ * The Azure Resource Management API includes operations for managing the storage accounts in your subscription.
+ *
+ * @see <a href="https://msdn.microsoft.com/en-us/library/mt163683.aspx">docs</a>
+ */
+@Path("/")
+@RequestFilters(OAuthFilter.class)
+@QueryParams(keys = "api-version", values = "2015-06-15")
+@Consumes(MediaType.APPLICATION_JSON)
+public interface StorageAccountApi {
+
+   /**
+    * The List Storage Accounts operation lists the storage accounts that are available in the specified subscription
+    * and resource group.
+    * https://msdn.microsoft.com/en-us/library/mt163559.aspx
+    */
+   @Named("storageaccount:list")
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts")
+   @GET
+   @SelectJson("value")
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<StorageService> list();
+
+   /**
+    * The Create Storage Account asynchronous operation creates a new storage account in Microsoft Azure.
+    * https://msdn.microsoft.com/en-us/library/mt163564.aspx
+    * PUT
+    */
+   @Named("storageaccount:create")
+   @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties}%7D")
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}")
+   @Produces(MediaType.APPLICATION_JSON)
+   @ResponseParser(URIParser.class)
+   @MapBinder(BindToJsonPayload.class)
+   @PUT
+   URI create(@PathParam("storageAccountName") String storageAccountName,
+              @PayloadParam("location") String location,
+              @Nullable @PayloadParam("tags") Map<String, String> tags,
+              @PayloadParam("properties") Map<String, String> properties);
+
+   /**
+    * 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. https://msdn.microsoft.com/en-us/library/mt163642.aspx
+    * POST
+    */
+   @Named("CheckStorageAccountNameAvailability")
+   @POST
+   @Payload("%7B\"name\":\"{name}\",\"type\":\"Microsoft.Storage/storageAccounts\"%7D")
+   @Path("/providers/Microsoft.Storage/checkNameAvailability")
+   @Produces(MediaType.APPLICATION_JSON)
+   Availability isAvailable(@PayloadParam("name") String storageAccountName);
+
+   /**
+    * The Get Storage Account Properties operation returns system properties for the specified storage account.
+    * https://msdn.microsoft.com/en-us/library/mt163553.aspx
+    */
+   @Named("storageaccountproperty:get")
+   @GET
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   StorageService get(@PathParam("storageAccountName") String storageAccountName);
+
+   /**
+    * The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account.
+    * https://msdn.microsoft.com/en-us/library/mt163589.aspx
+    * POST
+    */
+   @Named("storageaccountkey:get")
+   @POST
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}/listKeys")
+   @Produces(MediaType.APPLICATION_JSON)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   StorageServiceKeys getKeys(@PathParam("storageAccountName") String storageAccountName);
+
+   /**
+    * https://msdn.microsoft.com/en-us/library/mt163567.aspx
+    * POST
+    */
+   @Named("RegenerateStorageAccountKeys")
+   @POST
+   @Payload("%7B\"keyName\":\"{keyName}\"%7D")
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccount}/regenerateKey")
+   @Produces(MediaType.APPLICATION_JSON)
+   StorageServiceKeys regenerateKeys(@PathParam("storageAccount") String storageAccount,
+                                     @PayloadParam("keyName") String keyName);
+
+   /**
+    * The Update Storage Account asynchronous operation updates the label, the description, and enables or disables the
+    * geo-replication status for the specified storage account. https://msdn.microsoft.com/en-us/library/mt163639.aspx
+    * PATCH
+    */
+   @Named("storageaccount:update")
+   @PATCH
+   @Payload("%7B\"tags\":{tags},\"properties\":{properties}%7D")
+   @MapBinder(BindToJsonPayload.class)
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}")
+   @Produces(MediaType.APPLICATION_JSON)
+   StorageServiceUpdateParams update(
+           @PathParam("storageAccountName") String storageAccountName,
+           @Nullable @PayloadParam("tags") Map<String, String> tags,
+           @PayloadParam("properties") StorageServiceUpdateParams.StorageServiceUpdateProperties properties);
+
+   /**
+    * https://msdn.microsoft.com/en-us/library/mt163652.aspx
+    * DELETE
+    */
+   @Named("storageaccount:delete")
+   @DELETE
+   @ResponseParser(FalseOn204.class)
+   @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}")
+   boolean delete(@PathParam("storageAccountName") String storageAccountName);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java
new file mode 100644
index 0000000..34c6d56
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java
@@ -0,0 +1,40 @@
+/*
+ * 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.arm.functions;
+import com.google.common.base.Function;
+import org.jclouds.http.HttpResponse;
+
+import javax.inject.Singleton;
+
+import static org.jclouds.http.HttpUtils.releasePayload;
+/**
+ * Parses an http response code from http responser
+ */
+@Singleton
+public class FalseOn204 implements Function<HttpResponse, Boolean> {
+   public Boolean apply(final HttpResponse from) {
+      releasePayload(from);
+      final int statusCode = from.getStatusCode();
+      if (statusCode == 200) {
+         return true;
+      }
+      if (statusCode == 204) {
+         return false;
+      }
+      throw new IllegalStateException("not expected response from: " + from);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java
index f39db90..5770582 100644
--- a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.azurecompute.arm.functions;
 import com.google.common.base.Function;
+import org.jclouds.azurecompute.arm.util.GetEnumValue;
 import org.jclouds.http.HttpResponse;
 
 import javax.inject.Singleton;
@@ -31,15 +32,8 @@ public class ParseJobStatus implements Function<HttpResponse, ParseJobStatus.Job
       FAILED,
       UNRECOGNIZED;
 
-      public static JobStatus fromString(final String text) {
-         if (text != null) {
-            for (JobStatus status : JobStatus.values()) {
-               if (text.equalsIgnoreCase(status.name())) {
-                  return status;
-               }
-            }
-         }
-         return UNRECOGNIZED;
+      public static JobStatus fromValue(final String text) {
+         return (JobStatus) GetEnumValue.fromValueOrDefault(text, JobStatus.UNRECOGNIZED);
       }
    }
    public JobStatus apply(final HttpResponse from) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java
new file mode 100644
index 0000000..4a61613
--- /dev/null
+++ b/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java
@@ -0,0 +1,36 @@
+/*
+ * 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.arm.util;
+
+import java.util.EnumSet;
+
+public class GetEnumValue {
+
+   @SuppressWarnings("unchecked")
+   public static <T extends Enum<T>> Enum<T> fromValueOrDefault(String text, Enum<T> defaultValue) {
+      if (text != null) {
+         EnumSet<T> elements = EnumSet.allOf(defaultValue.getDeclaringClass());
+         for (Enum<T> element : elements) {
+            if (text.equalsIgnoreCase(element.name())) {
+               return element;
+            }
+         }
+      }
+      return defaultValue;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java
new file mode 100644
index 0000000..9a13d77
--- /dev/null
+++ b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.arm.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.azurecompute.arm.domain.StorageService;
+import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
+import org.jclouds.azurecompute.arm.domain.StorageServiceUpdateParams;
+import org.jclouds.azurecompute.arm.functions.ParseJobStatus;
+import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest;
+import org.jclouds.util.Predicates2;
+import org.testng.annotations.Test;
+
+import java.net.URI;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+@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.id());
+      assertNotNull(storage.name());
+      assertNotNull(storage.storageServiceProperties());
+      assertNotNull(storage.storageServiceProperties().accountType());
+      assertFalse(storage.storageServiceProperties().primaryEndpoints().isEmpty());
+      assertNotNull(storage.storageServiceProperties().creationTime());
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testList() {
+      List<StorageService> storages = api().list();
+      assertTrue(storages.size() > 0);
+      for (StorageService storage : storages) {
+         check(storage);
+      }
+   }
+
+   @Test()
+   public void testIsAvailable() {
+      assertTrue(api().isAvailable(NAME).nameAvailable().equals("true"));
+   }
+
+   @Test(dependsOnMethods = "testIsAvailable")
+   public void testCreate() {
+      URI uri = api().create(NAME, LOCATION, ImmutableMap.of("property_name",
+              "property_value"), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString()));
+      if (uri != null){
+         assertTrue(uri.toString().contains("api-version"));
+
+         boolean jobDone = Predicates2.retry(new Predicate<URI>() {
+            @Override public boolean apply(URI uri) {
+               return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri);
+            }
+         }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri);
+         assertTrue(jobDone, "create operation did not complete in the configured timeout");
+      }
+      final StorageService service = api().get(NAME);
+      assertNotNull(service);
+      assertEquals(service.location(), LOCATION);
+      assertNotNull(service.storageServiceProperties().creationTime());
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testGet() {
+      final StorageService service = api().get(NAME);
+      assertNotNull(service);
+      assertEquals(service.name(), NAME);
+      assertEquals(service.storageServiceProperties().primaryLocation(), LOCATION);
+      assertEquals(service.storageServiceProperties().accountType(), StorageService.AccountType.Standard_LRS);
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testGetKeys() {
+      final StorageServiceKeys keys = api().getKeys(NAME);
+      assertNotNull(keys);
+      assertNotNull(keys.key1());
+      assertNotNull(keys.key2());
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testRegenerateKeys() {
+      StorageServiceKeys keys = api().regenerateKeys(NAME, "key1");
+      assertFalse(keys.key1().isEmpty());
+      assertFalse(keys.key2().isEmpty());
+   }
+
+   @Test(dependsOnMethods = "testCreate")
+   public void testUpdateTags() {
+      StorageServiceUpdateParams.StorageServiceUpdateProperties props =
+              StorageServiceUpdateParams.StorageServiceUpdateProperties.create(null);
+      final StorageServiceUpdateParams params = api().update(NAME,
+              ImmutableMap.of("another_property_name", "another_property_value"), props);
+      assertTrue(params.tags().containsKey("another_property_name"));
+      assertNull(params.storageServiceProperties().accountType());
+   }
+   @Test(dependsOnMethods = "testCreate")
+   public void testUpdateAccountType() {
+      StorageServiceUpdateParams.StorageServiceUpdateProperties props =
+              StorageServiceUpdateParams.StorageServiceUpdateProperties.create(StorageService.AccountType.Standard_GRS);
+      final StorageServiceUpdateParams params = api().update(NAME,
+              null, props);
+      assertTrue(params.tags().isEmpty());
+      assertEquals(params.storageServiceProperties().accountType(), StorageService.AccountType.Standard_GRS);
+   }
+
+   private StorageAccountApi api() {
+      return api.getStorageAccountApi(getResourceGroupName());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java
new file mode 100644
index 0000000..39ecd2b
--- /dev/null
+++ b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java
@@ -0,0 +1,347 @@
+/*
+ * 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.arm.features;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import org.jclouds.azurecompute.arm.domain.StorageService;
+import org.jclouds.azurecompute.arm.domain.Availability;
+import org.jclouds.azurecompute.arm.domain.StorageServiceKeys;
+import org.jclouds.azurecompute.arm.domain.StorageServiceUpdateParams;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.date.DateService;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.testng.annotations.Test;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Iterables.isEmpty;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertFalse;
+
+
+@Test(groups = "unit", testName = "StorageAccountApiMockTest", singleThreaded = true)
+public class StorageAccountApiMockTest extends BaseAzureComputeApiMockTest {
+
+   private String subsriptionId = "SUBSCRIPTIONID";
+   private String resourceGroup = "resourceGroup";
+
+   public void testList() throws Exception {
+      server.enqueue(jsonResponse("/storageAccounts.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      List<StorageService> list = storageAPI.list();
+      assertEquals(list, expected());
+
+      assertSent(server, "GET", "/subscriptions/" + subsriptionId +
+              "/resourcegroups/resourceGroup/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15");
+   }
+
+   public void testListReturns404() throws InterruptedException {
+      server.enqueue(response404());
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      List<StorageService> list = storageAPI.list();
+
+      assertTrue(isEmpty(list));
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/subscriptions/" + subsriptionId +
+              "/resourcegroups/resourceGroup/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15");
+   }
+
+   public void testCreate() throws Exception {
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      server.enqueue(response202WithHeader());
+
+      URI uri = storageAPI.create("name-of-storage-account", "westus",
+              ImmutableMap.of("property_name", "property_value"),
+              ImmutableMap.of("accountType", StorageService.AccountType.Premium_LRS.toString()));
+      assertNotNull(uri);
+
+      assertSent(server, "PUT", "/subscriptions/" + subsriptionId +
+              "/resourcegroups/resourceGroup/providers/Microsoft.Storage/" +
+              "storageAccounts/name-of-storage-account?api-version=2015-06-15", String.format("{\"location\":\"westus\",\"tags\":{\"property_name\":\"property_value\"},\"properties\":{\"accountType\":\"Premium_LRS\"}}"));
+   }
+
+   public void testCreateWithNullTag() throws Exception {
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      server.enqueue(response202WithHeader());
+
+      URI uri = storageAPI.create("name-of-storage-account", "westus",
+              null,
+              ImmutableMap.of("accountType", StorageService.AccountType.Premium_LRS.toString()));
+      assertNotNull(uri);
+
+      assertSent(server, "PUT", "/subscriptions/" + subsriptionId +
+              "/resourcegroups/resourceGroup/providers/Microsoft.Storage/" +
+              "storageAccounts/name-of-storage-account?api-version=2015-06-15", String.format("{\"location\":\"westus\",\"properties\":{\"accountType\":\"Premium_LRS\"}}"));
+   }
+
+   public void testIsAvailable() throws Exception {
+      server.enqueue(jsonResponse("/isavailablestorageservice.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      assertEquals(storageAPI.isAvailable("TESTSTORAGE"),
+              Availability.create("true"));
+
+      assertSent(server, "POST", "/subscriptions/" + subsriptionId +
+              "/providers/Microsoft.Storage/checkNameAvailability?api-version=2015-06-15", String.format("{\"name\":\"TESTSTORAGE\",\"type\":\"Microsoft.Storage/storageAccounts\"}"));
+   }
+
+   public void testGet() throws Exception {
+      server.enqueue(jsonResponse("/storageservices.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      assertEquals(storageAPI.get("TESTSTORAGE"), expected().get(0));
+
+      assertSent(server, "GET", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15");
+   }
+
+   public void testNullGet() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      assertNull(storageAPI.get("TESTSTORAGE"));
+
+      assertSent(server, "GET", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15");
+   }
+
+   public void testGetKeys() throws Exception {
+      server.enqueue(jsonResponse("/storageaccountkeys.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      assertEquals(storageAPI.getKeys("TESTSTORAGE"), StorageServiceKeys.create(
+              "bndO7lydwDkMo4Y0mFvmfLyi2f9aZY7bwfAVWoJWv4mOVK6E9c/exLnFsSm/NMWgifLCfxC/c6QBTbdEvWUA7w==",
+              "/jMLLT3kKqY4K+cUtJTbh7pCBdvG9EMKJxUvaJJAf6W6aUiZe1A1ulXHcibrqRVA2RJE0oUeXQGXLYJ2l85L7A=="));
+
+      assertSent(server, "POST", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE/listKeys?api-version=2015-06-15");
+   }
+
+   public void testNullGetKeys() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      assertNull(storageAPI.getKeys("TESTSTORAGE"));
+
+      assertSent(server, "POST", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE/listKeys?api-version=2015-06-15");
+   }
+
+   public void testRegenerateKeys() throws Exception {
+      server.enqueue(jsonResponse("/storageaccountkeys.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      assertEquals(storageAPI.regenerateKeys("TESTSTORAGE", "key1"), StorageServiceKeys.create(
+              "bndO7lydwDkMo4Y0mFvmfLyi2f9aZY7bwfAVWoJWv4mOVK6E9c/exLnFsSm/NMWgifLCfxC/c6QBTbdEvWUA7w==",
+              "/jMLLT3kKqY4K+cUtJTbh7pCBdvG9EMKJxUvaJJAf6W6aUiZe1A1ulXHcibrqRVA2RJE0oUeXQGXLYJ2l85L7A=="));
+
+      assertSent(server, "POST", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE/regenerateKey?api-version=2015-06-15", String.format("{\"keyName\":\"key1\"}"));
+   }
+
+   public void testUpdate() throws Exception {
+      server.enqueue(jsonResponse("/storageaccountupdate.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      StorageServiceUpdateParams.StorageServiceUpdateProperties props =
+      StorageServiceUpdateParams.StorageServiceUpdateProperties.create(StorageService.AccountType.Standard_LRS);
+
+      final StorageServiceUpdateParams params = storageAPI.update("TESTSTORAGE",
+              ImmutableMap.of("another_property_name", "another_property_value"), props);
+
+      assertTrue(params.tags().containsKey("another_property_name"));
+
+      assertSent(server, "PATCH", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+         "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15", String.format("{\"properties\":{ \"accountType\": \"Standard_LRS\" },\"tags\":{\"another_property_name\":\"another_property_value\"}}"));
+   }
+
+   public void testUpdateWithNullTagAndNullProperty() throws Exception {
+      server.enqueue(jsonResponse("/storageaccountupdate.json"));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      StorageServiceUpdateParams.StorageServiceUpdateProperties props =
+              StorageServiceUpdateParams.StorageServiceUpdateProperties.create(null);
+
+      final StorageServiceUpdateParams params = storageAPI.update("TESTSTORAGE", null, props);
+
+      assertTrue(params.tags().containsKey("another_property_name"));
+
+      assertSent(server, "PATCH", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15", String.format("{\"properties\":{}}"));
+   }
+
+   public void testDelete() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      boolean status = storageAPI.delete("TESTSTORAGE");
+      assertTrue(status);
+
+      assertSent(server, "DELETE", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15");
+   }
+
+   public void testDelete204() throws Exception {
+
+      server.enqueue(new MockResponse().setResponseCode(204));
+
+      final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup);
+
+      boolean status = storageAPI.delete("TESTSTORAGE");
+      assertFalse(status);
+
+      assertSent(server, "DELETE", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup +
+              "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15");
+   }
+
+   private StorageService getStrorageAccount() {
+      DateService DATE_SERVICE = new SimpleDateFormatDateService();
+      Map<String, String> endpoints = new HashMap<String, String>();
+      endpoints.put("blob", "https://TESTSTORAGE.blob.core.windows.net/");
+      endpoints.put("file", "https://TESTSTORAGE.file.core.windows.net/");
+      endpoints.put("queue", "https://TESTSTORAGE.queue.core.windows.net/");
+      endpoints.put("table", "https://TESTSTORAGE.table.core.windows.net/");
+      Map<String, String> secondaryEndpoints = new HashMap<String, String>();
+      secondaryEndpoints.put("blob", "https://TESTSTORAGE-secondary.blob.core.windows.net/");
+      secondaryEndpoints.put("queue", "https://TESTSTORAGE-secondary.queue.core.windows.net/");
+      secondaryEndpoints.put("table", "https://TESTSTORAGE-secondary.table.core.windows.net/");
+
+
+      String location = "westus";
+      String secondaryLocation = "eastus";
+      final StorageService.StorageServiceProperties props = StorageService.StorageServiceProperties.create(
+              StorageService.AccountType.Standard_RAGRS,
+              DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T13:04:45.0890883Z"),
+              endpoints,
+              location,
+              StorageService.Status.Succeeded,
+              secondaryEndpoints, secondaryLocation,
+              StorageService.RegionStatus.Available,
+              StorageService.RegionStatus.Available);
+
+      final Map<String, String> tags = ImmutableMap.of(
+              "key1", "value1",
+              "key2", "value2");
+
+      return StorageService.create(
+              "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup" +
+                      "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE",
+              "TESTSTORAGE", location, tags, null, props);
+   }
+
+   private List<StorageService> expected() throws MalformedURLException {
+      DateService DATE_SERVICE = new SimpleDateFormatDateService();
+      Map<String, String> endpoints = new HashMap<String, String>();
+      endpoints.put("blob", "https://TESTSTORAGE.blob.core.windows.net/");
+      endpoints.put("file", "https://TESTSTORAGE.file.core.windows.net/");
+      endpoints.put("queue", "https://TESTSTORAGE.queue.core.windows.net/");
+      endpoints.put("table", "https://TESTSTORAGE.table.core.windows.net/");
+      Map<String, String> secondaryEndpoints = new HashMap<String, String>();
+      secondaryEndpoints.put("blob", "https://TESTSTORAGE-secondary.blob.core.windows.net/");
+      secondaryEndpoints.put("queue", "https://TESTSTORAGE-secondary.queue.core.windows.net/");
+      secondaryEndpoints.put("table", "https://TESTSTORAGE-secondary.table.core.windows.net/");
+      Map<String, String> endpoints2 = new HashMap<String, String>();
+      endpoints2.put("blob", "https://TESTSTORAGE2.blob.core.windows.net/");
+      endpoints2.put("file", "https://TESTSTORAGE2.file.core.windows.net/");
+      endpoints2.put("queue", "https://TESTSTORAGE2.queue.core.windows.net/");
+      endpoints2.put("table", "https://TESTSTORAGE2.table.core.windows.net/");
+      Map<String, String> secondaryEndpoints2 = new HashMap<String, String>();
+      secondaryEndpoints2.put("blob", "https://TESTSTORAGE2-secondary.blob.core.windows.net/");
+      secondaryEndpoints2.put("queue", "https://TESTSTORAGE2-secondary.queue.core.windows.net/");
+      secondaryEndpoints2.put("table", "https://TESTSTORAGE2-secondary.table.core.windows.net/");
+      Map<String, String> endpoints3 = new HashMap<String, String>();
+      endpoints3.put("blob", "https://TESTSTORAGE3.blob.core.windows.net/");
+      endpoints3.put("file", "https://TESTSTORAGE3.file.core.windows.net/");
+      endpoints3.put("queue", "https://TESTSTORAGE3.queue.core.windows.net/");
+      endpoints3.put("table", "https://TESTSTORAGE3.table.core.windows.net/");
+      Map<String, String> secondaryEndpoints3 = new HashMap<String, String>();
+      secondaryEndpoints3.put("blob", "https://TESTSTORAGE3-secondary.blob.core.windows.net/");
+      secondaryEndpoints3.put("queue", "https://TESTSTORAGE3-secondary.queue.core.windows.net/");
+      secondaryEndpoints3.put("table", "https://TESTSTORAGE3-secondary.table.core.windows.net/");
+
+
+      String location = "westus";
+      String secondaryLocation = "eastus";
+      final StorageService.StorageServiceProperties props = StorageService.StorageServiceProperties.create(
+              StorageService.AccountType.Standard_RAGRS,
+              DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T13:04:45.0890883Z"),
+              endpoints,
+              location,
+              StorageService.Status.Succeeded, secondaryEndpoints, secondaryLocation,
+              StorageService.RegionStatus.Available,
+              StorageService.RegionStatus.Available);
+      final StorageService.StorageServiceProperties props2 = StorageService.StorageServiceProperties.create(
+              StorageService.AccountType.Standard_RAGRS,
+              DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T13:11:43.8265672Z"),
+              endpoints2, location,
+              StorageService.Status.Succeeded, secondaryEndpoints2, secondaryLocation,
+              StorageService.RegionStatus.Available,
+              StorageService.RegionStatus.Available);
+      final StorageService.StorageServiceProperties props3 = StorageService.StorageServiceProperties.create(
+              StorageService.AccountType.Standard_RAGRS,
+              DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T14:12:59.5223315Z"),
+              endpoints3, location,
+              StorageService.Status.Succeeded, secondaryEndpoints3, secondaryLocation,
+              StorageService.RegionStatus.Available,
+              StorageService.RegionStatus.Available);
+
+      final Map<String, String> tags = ImmutableMap.of(
+              "key1", "value1",
+              "key2", "value2");
+
+      return ImmutableList.of(StorageService.create(
+              "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/" +
+                      "providers/Microsoft.Storage/storageAccounts/TESTSTORAGE",
+              "TESTSTORAGE", location, tags, "Microsoft.Storage/storageAccounts", props),
+              StorageService.create(
+                      "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/" +
+                              "providers/Microsoft.Storage/storageAccounts/TESTSTORAGE2",
+                      "TESTSTORAGE2", location, tags, "Microsoft.Storage/storageAccounts", props2),
+              StorageService.create(
+                      "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/" +
+                              "providers/Microsoft.Storage/storageAccounts/TESTSTORAGE3",
+                      "TESTSTORAGE3", location, tags, "Microsoft.Storage/storageAccounts", props3));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java
index fb2e42a..657ebf7 100644
--- a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java
+++ b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java
@@ -16,16 +16,41 @@
  */
 package org.jclouds.azurecompute.arm.internal;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
 
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
 import org.jclouds.azurecompute.arm.domain.ResourceGroup;
 
+import org.jclouds.azurecompute.arm.domain.StorageService;
+import org.jclouds.azurecompute.arm.features.StorageAccountApi;
+import org.jclouds.azurecompute.arm.functions.ParseJobStatus;
+import org.jclouds.util.Predicates2;
+import org.testng.Assert;
 import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest {
    public static final String LOCATION = "westeurope";
    private String resourceGroupName = null;
 
+   protected StorageService storageService;
+
+
+   private String storageServiceName = null;
+
+   protected String getStorageServiceName() {
+      if (storageServiceName == null) {
+         storageServiceName = String.format("%3.24s",
+                 System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase();
+      }
+      return storageServiceName;
+   }
+
    protected String getEndpoint() {
       String endpoint = null;
       if (System.getProperty("test.azurecompute-arm.endpoint") != null) {
@@ -56,10 +81,45 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest
    }
 
 
+   @BeforeClass
+   @Override
+   public void setup() {
+      super.setup();
+
+      storageService = getOrCreateStorageService(getStorageServiceName());
+   }
+
    @AfterClass(alwaysRun = true)
    @Override
    protected void tearDown() {
       super.tearDown();
+      Boolean status = api.getStorageAccountApi(getResourceGroupName()).delete(getStorageServiceName());
+      assertTrue(status.booleanValue());
       deleteResourceGroup(getResourceGroupName());
    }
+
+   protected StorageService getOrCreateStorageService(String storageServiceName) {
+      StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName());
+      StorageService ss = storageApi.get(storageServiceName);
+      if (ss != null) {
+         return ss;
+      }
+      URI uri = storageApi.create(storageServiceName, LOCATION, ImmutableMap.of("property_name",
+              "property_value"), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString()));
+      if (uri != null){
+         assertTrue(uri.toString().contains("api-version"));
+
+         boolean jobDone = Predicates2.retry(new Predicate<URI>() {
+            @Override public boolean apply(URI uri) {
+               return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri);
+            }
+         }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri);
+         assertTrue(jobDone, "create operation did not complete in the configured timeout");
+      }
+      ss = storageApi.get(storageServiceName);
+      Assert.assertEquals(ss.location(), LOCATION);
+
+      Logger.getAnonymousLogger().log(Level.INFO, "created storageService: {0}", ss);
+      return ss;
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java
index 5a228f4..82af978 100644
--- a/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java
+++ b/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java
@@ -96,6 +96,11 @@ public class BaseAzureComputeApiMockTest {
       return new MockResponse().setStatus("HTTP/1.1 202 Accepted");
    }
 
+
+   protected MockResponse response204() {
+      return new MockResponse().setStatus("HTTP/1.1 204 No Content");
+   }
+
    protected MockResponse response202WithHeader() {
       return new MockResponse()
               .setStatus("HTTP/1.1 202 Accepted")

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/resources/isavailablestorageservice.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/isavailablestorageservice.json b/azurecompute-arm/src/test/resources/isavailablestorageservice.json
new file mode 100644
index 0000000..b6f2459
--- /dev/null
+++ b/azurecompute-arm/src/test/resources/isavailablestorageservice.json
@@ -0,0 +1,3 @@
+{
+  "nameAvailable": true
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/resources/storageAccounts.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/storageAccounts.json b/azurecompute-arm/src/test/resources/storageAccounts.json
new file mode 100644
index 0000000..f5841df
--- /dev/null
+++ b/azurecompute-arm/src/test/resources/storageAccounts.json
@@ -0,0 +1,90 @@
+{
+  "value": [{
+    "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE",
+    "location": "westus",
+    "name": "TESTSTORAGE",
+    "properties": {
+      "accountType": "Standard_RAGRS",
+      "creationTime": "2016-02-24T13:04:45.0890883Z",
+      "primaryEndpoints": {
+        "blob": "https://TESTSTORAGE.blob.core.windows.net/",
+        "file": "https://TESTSTORAGE.file.core.windows.net/",
+        "queue": "https://TESTSTORAGE.queue.core.windows.net/",
+        "table": "https://TESTSTORAGE.table.core.windows.net/"
+      },
+      "primaryLocation": "westus",
+      "provisioningState": "Succeeded",
+      "secondaryEndpoints": {
+        "blob": "https://TESTSTORAGE-secondary.blob.core.windows.net/",
+        "queue": "https://TESTSTORAGE-secondary.queue.core.windows.net/",
+        "table": "https://TESTSTORAGE-secondary.table.core.windows.net/"
+      },
+      "secondaryLocation": "eastus",
+      "statusOfPrimary": "available",
+      "statusOfSecondary": "available"
+    },
+    "tags": {
+      "key1": "value1",
+      "key2": "value2"
+    },
+    "type": "Microsoft.Storage/storageAccounts"
+  }, {
+    "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE2",
+    "location": "westus",
+    "name": "TESTSTORAGE2",
+    "properties": {
+      "accountType": "Standard_RAGRS",
+      "creationTime": "2016-02-24T13:11:43.8265672Z",
+      "primaryEndpoints": {
+        "blob": "https://TESTSTORAGE2.blob.core.windows.net/",
+        "file": "https://TESTSTORAGE2.file.core.windows.net/",
+        "queue": "https://TESTSTORAGE2.queue.core.windows.net/",
+        "table": "https://TESTSTORAGE2.table.core.windows.net/"
+      },
+      "primaryLocation": "westus",
+      "provisioningState": "Succeeded",
+      "secondaryEndpoints": {
+        "blob": "https://TESTSTORAGE2-secondary.blob.core.windows.net/",
+        "queue": "https://TESTSTORAGE2-secondary.queue.core.windows.net/",
+        "table": "https://TESTSTORAGE2-secondary.table.core.windows.net/"
+      },
+      "secondaryLocation": "eastus",
+      "statusOfPrimary": "available",
+      "statusOfSecondary": "available"
+    },
+    "tags": {
+      "key1": "value1",
+      "key2": "value2"
+    },
+    "type": "Microsoft.Storage/storageAccounts"
+  }, {
+    "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE3",
+    "location": "westus",
+    "name": "TESTSTORAGE3",
+    "properties": {
+      "accountType": "Standard_RAGRS",
+      "creationTime": "2016-02-24T14:12:59.5223315Z",
+      "primaryEndpoints": {
+        "blob": "https://TESTSTORAGE3.blob.core.windows.net/",
+        "file": "https://TESTSTORAGE3.file.core.windows.net/",
+        "queue": "https://TESTSTORAGE3.queue.core.windows.net/",
+        "table": "https://TESTSTORAGE3.table.core.windows.net/"
+      },
+      "primaryLocation": "westus",
+      "provisioningState": "Succeeded",
+      "secondaryEndpoints": {
+        "blob": "https://TESTSTORAGE3-secondary.blob.core.windows.net/",
+        "queue": "https://TESTSTORAGE3-secondary.queue.core.windows.net/",
+        "table": "https://TESTSTORAGE3-secondary.table.core.windows.net/"
+      },
+      "secondaryLocation": "eastus",
+      "statusOfPrimary": "available",
+      "statusOfSecondary": "available"
+    },
+    "tags": {
+      "key1": "value1",
+      "key2": "value2"
+    },
+    "type": "Microsoft.Storage/storageAccounts"
+  }]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/resources/storageCreateResponse.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/storageCreateResponse.json b/azurecompute-arm/src/test/resources/storageCreateResponse.json
new file mode 100644
index 0000000..4fc9301
--- /dev/null
+++ b/azurecompute-arm/src/test/resources/storageCreateResponse.json
@@ -0,0 +1,9 @@
+{
+  "location": "westus",
+  "tags": {
+    "property_name": "property_value"
+  },
+  "properties": {
+    "accountType": "Premium_LRS"
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/resources/storageaccountkeys.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/storageaccountkeys.json b/azurecompute-arm/src/test/resources/storageaccountkeys.json
new file mode 100644
index 0000000..42de106
--- /dev/null
+++ b/azurecompute-arm/src/test/resources/storageaccountkeys.json
@@ -0,0 +1,4 @@
+{
+  "key1": "bndO7lydwDkMo4Y0mFvmfLyi2f9aZY7bwfAVWoJWv4mOVK6E9c/exLnFsSm/NMWgifLCfxC/c6QBTbdEvWUA7w==",
+  "key2": "/jMLLT3kKqY4K+cUtJTbh7pCBdvG9EMKJxUvaJJAf6W6aUiZe1A1ulXHcibrqRVA2RJE0oUeXQGXLYJ2l85L7A=="
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/resources/storageaccountupdate.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/storageaccountupdate.json b/azurecompute-arm/src/test/resources/storageaccountupdate.json
new file mode 100644
index 0000000..dafe560
--- /dev/null
+++ b/azurecompute-arm/src/test/resources/storageaccountupdate.json
@@ -0,0 +1,7 @@
+{
+  "properties": {
+  },
+  "tags": {
+    "another_property_name": "another_property_value"
+  }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/b82378c2/azurecompute-arm/src/test/resources/storageservices.json
----------------------------------------------------------------------
diff --git a/azurecompute-arm/src/test/resources/storageservices.json b/azurecompute-arm/src/test/resources/storageservices.json
new file mode 100644
index 0000000..b56a67b
--- /dev/null
+++ b/azurecompute-arm/src/test/resources/storageservices.json
@@ -0,0 +1,30 @@
+{
+   "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE",
+   "location": "westus",
+   "name": "TESTSTORAGE",
+   "properties": {
+      "accountType": "Standard_RAGRS",
+      "creationTime": "2016-02-24T13:04:45.0890883Z",
+      "primaryEndpoints": {
+         "blob": "https://TESTSTORAGE.blob.core.windows.net/",
+         "file": "https://TESTSTORAGE.file.core.windows.net/",
+         "queue": "https://TESTSTORAGE.queue.core.windows.net/",
+         "table": "https://TESTSTORAGE.table.core.windows.net/"
+      },
+      "primaryLocation": "westus",
+      "provisioningState": "Succeeded",
+      "secondaryEndpoints": {
+         "blob": "https://TESTSTORAGE-secondary.blob.core.windows.net/",
+         "queue": "https://TESTSTORAGE-secondary.queue.core.windows.net/",
+         "table": "https://TESTSTORAGE-secondary.table.core.windows.net/"
+      },
+      "secondaryLocation": "eastus",
+      "statusOfPrimary": "available",
+      "statusOfSecondary": "available"
+   },
+   "tags": {
+      "key1": "value1",
+      "key2": "value2"
+   },
+   "type": "Microsoft.Storage/storageAccounts"
+}
\ No newline at end of file