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

[3/4] jclouds-labs git commit: AzureCompute: initial work to support ComputeServiceAdapter

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/OSImageToImage.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/OSImageToImage.java b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/OSImageToImage.java
index 22d0f1a..c08aeed 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/OSImageToImage.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/OSImageToImage.java
@@ -16,13 +16,10 @@
  */
 package org.jclouds.azurecompute.compute.functions;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.inject.Inject;
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import org.jclouds.azurecompute.domain.OSImage;
 import org.jclouds.compute.domain.Image;
-
-import com.google.common.base.Function;
 import org.jclouds.compute.domain.ImageBuilder;
 import org.jclouds.compute.domain.OperatingSystem;
 import org.jclouds.compute.domain.OsFamily;
@@ -31,11 +28,14 @@ import org.jclouds.domain.LocationBuilder;
 import org.jclouds.domain.LocationScope;
 import org.jclouds.location.suppliers.all.JustProvider;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
 
 public class OSImageToImage implements Function<OSImage, Image> {
-   private static final String UNRECOGNIZED = "UNRECOGNIZED";
 
+   private static final String UNRECOGNIZED = "UNRECOGNIZED";
    private static final String UBUNTU = "Ubuntu";
    private static final String WINDOWS = "Windows";
    private static final String OPENLOGIC = "openLogic";
@@ -44,7 +44,7 @@ public class OSImageToImage implements Function<OSImage, Image> {
    private static final String OPENSUSE = "openSUSE";
    private static final String SUSE = "SUSE";
    private static final String SQL_SERVER = "SQL Server";
-   private static final String ORACLE_lINUX = "Orcale Linux";
+   private static final String ORACLE_lINUX = "Oracle Linux";
 
    private final JustProvider provider;
 
@@ -70,13 +70,10 @@ public class OSImageToImage implements Function<OSImage, Image> {
    }
 
    private Location createLocation(String input) {
-      if (input != null) {
-         return new LocationBuilder().id(input).scope(LocationScope.REGION).description(input).parent(
+      if (input == null) return null;
+      return new LocationBuilder().id(input).scope(LocationScope.REGION).description(input).parent(
                Iterables.getOnlyElement(provider.get())).metadata(ImmutableMap.<String, Object>of("name", input))
                .build();
-      } else {
-         return null;
-      }
    }
 
    public static Function<OSImage, OperatingSystem.Builder> osFamily() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/RoleSizeToHardware.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/RoleSizeToHardware.java b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/RoleSizeToHardware.java
index 97a9b2c..c778805 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/RoleSizeToHardware.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/RoleSizeToHardware.java
@@ -18,14 +18,44 @@ package org.jclouds.azurecompute.compute.functions;
 
 import org.jclouds.azurecompute.domain.RoleSize;
 import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Processor;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
 
 public class RoleSizeToHardware implements Function<RoleSize, Hardware> {
 
 	@Override
-	public Hardware apply(RoleSize input) {
-		return null;
-	}
+	public Hardware apply(RoleSize from) {
+		HardwareBuilder builder = new HardwareBuilder().ids(from.name().name())
+				  .name(from.name().name())
+				  .hypervisor("Hyper-V")
+				  .processors(ImmutableList.of(new Processor(from.cores(), 2)))
+				  .ram(from.memoryInMb());
+
+		// TODO volumes
+		/*
+		if (from.s() != null) {
+			builder.volumes(
+					  FluentIterable.from(from.getVirtualGuestBlockDevices()).filter(new Predicate<VirtualGuestBlockDevice>() {
+						  @Override
+						  public boolean apply(VirtualGuestBlockDevice input) {
+							  return input.getMountType().equals("Disk");
+						  }
+					  })
+								 .transform(new Function<VirtualGuestBlockDevice, Volume>() {
+									 @Override
+									 public Volume apply(VirtualGuestBlockDevice item) {
+										 float volumeSize = item.getVirtualDiskImage().getCapacity();
+										 return new VolumeImpl(
+													item.getId() + "",
+													from.isLocalDiskFlag() ? Volume.Type.LOCAL : Volume.Type.SAN,
+													volumeSize, null, item.getBootableFlag() == 1, false);
+									 }
+								 }).toSet());
+		}
+		*/
+		return builder.build();	}
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/internal/OperatingSystems.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/internal/OperatingSystems.java b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/internal/OperatingSystems.java
new file mode 100644
index 0000000..178d632
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/functions/internal/OperatingSystems.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.compute.functions.internal;
+
+import org.jclouds.azurecompute.domain.OSImage;
+import org.jclouds.compute.domain.OsFamily;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+
+public class OperatingSystems {
+
+   protected static final String CENTOS = "CentOS";
+   protected static final String SUSE = "SUSE";
+   protected static final String OPENSUSE = "openSUSE";
+   protected static final String UBUNTU = "Ubuntu";
+   protected static final String WINDOWS = "Windows";
+   private static final String MICROSOFT = "Microsoft";
+   public static final String WINDOWS_SERVER = "Windows Server";
+   public static final String MICROSOFT_SQL_SERVER = "Microsoft SQL Server";
+
+   public static Function<String, OsFamily> osFamily() {
+      return new Function<String, OsFamily>() {
+         @Override
+         public OsFamily apply(final String label) {
+            if (label != null) {
+               if (label.contains(CENTOS)) return OsFamily.CENTOS;
+               else if (label.contains(SUSE)) return OsFamily.SUSE;
+               else if (label.contains(UBUNTU)) return OsFamily.UBUNTU;
+               else if (label.contains(WINDOWS)) return OsFamily.WINDOWS;
+            }
+            return OsFamily.UNRECOGNIZED;
+         }
+      };
+   }
+
+   public static Function<OSImage, String> version() {
+      return new Function<OSImage, String>() {
+         @Override
+         public String apply(OSImage osImage) {
+            if (osImage.category().matches("Canonical|OpenLogic")) {
+               return Iterables.get(Splitter.on(" ").split(osImage.label()), 2);
+            } else if (osImage.category().matches(SUSE)) {
+               if (osImage.label().startsWith(OPENSUSE)) {
+                  return osImage.label().substring(OPENSUSE.length() + 1);
+               }
+               if (osImage.label().startsWith(SUSE)) {
+                  return Iterables.get(Splitter.on("-").split(osImage.name()), 4);
+               }
+            } else if (osImage.category().matches(MICROSOFT)) {
+               if (osImage.label().startsWith(WINDOWS_SERVER)) {
+                  return osImage.label().substring(WINDOWS_SERVER.length() + 1);
+               }
+               if (osImage.label().startsWith(MICROSOFT_SQL_SERVER)) {
+                  return osImage.label().substring(MICROSOFT_SQL_SERVER.length() + 1);
+               }
+            } else if (osImage.category().matches("RightScale with Linux|Public ")) {
+               Iterable<String> splittedLabel = Splitter.on("-").split(osImage.label());
+               if (Iterables.size(splittedLabel) > 2) {
+                  return Iterables.get(splittedLabel, 2);
+               }
+            }
+            return null;
+         }
+      };
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/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
new file mode 100644
index 0000000..1520509
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes.java
@@ -0,0 +1,270 @@
+/*
+ * 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.compute.strategy;
+
+import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Iterables.tryFind;
+import static java.lang.String.format;
+import static org.jclouds.azurecompute.compute.config.AzureComputeServiceContextModule.AzureComputeConstants;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.azurecompute.AzureComputeApi;
+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.options.AzureComputeTemplateOptions;
+import org.jclouds.compute.config.CustomizationResponse;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
+import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
+import org.jclouds.compute.strategy.ListNodesStrategy;
+import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+
+@Singleton
+public class GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet {
+
+   private static final String DEFAULT_STORAGE_ACCOUNT_PREFIX = "jclouds";
+   private static final String DEFAULT_STORAGE_SERVICE_TYPE = "Standard_GRS";
+   private static final String DEFAULT_VIRTUAL_NETWORK_NAME = "jclouds-virtual-network";
+   private static final String DEFAULT_ADDRESS_SPACE_ADDRESS_PREFIX = "10.0.0.0/20";
+   private static final String DEFAULT_SUBNET_NAME = "jclouds-1";
+   private static final String DEFAULT_SUBNET_ADDRESS_PREFIX = "10.0.0.0/23";
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final AzureComputeApi api;
+   private final Predicate<String> operationSucceededPredicate;
+   private final AzureComputeConstants azureComputeConstants;
+
+   @Inject
+   protected GetOrCreateStorageServiceAndVirtualNetworkThenCreateNodes(
+           CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy,
+           ListNodesStrategy listNodesStrategy,
+           GroupNamingConvention.Factory namingConvention,
+           @Named("jclouds.user-threads") ListeningExecutorService userExecutor,
+           CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
+           AzureComputeApi api,
+           Predicate<String> operationSucceededPredicate,
+           AzureComputeConstants azureComputeConstants) {
+      super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
+      this.api = api;
+      this.operationSucceededPredicate = operationSucceededPredicate;
+      this.azureComputeConstants = azureComputeConstants;
+   }
+
+   @Override
+   protected ListenableFuture<AtomicReference<NodeMetadata>> createNodeInGroupWithNameAndTemplate(String group, String name, Template template) {
+      return super.createNodeInGroupWithNameAndTemplate(group, name, template);
+   }
+
+   @Override
+   public Map<?, ListenableFuture<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
+
+      AzureComputeTemplateOptions templateOptions = template.getOptions().as(AzureComputeTemplateOptions.class);
+      String storageAccountName = templateOptions.getStorageAccountName().or(generateStorageServiceName(DEFAULT_STORAGE_ACCOUNT_PREFIX));
+      String location = template.getLocation().getId();
+      String storageAccountType = templateOptions.getStorageAccountType().or(DEFAULT_STORAGE_SERVICE_TYPE);
+      String virtualNetworkName = templateOptions.getVirtualNetworkName().or(DEFAULT_VIRTUAL_NETWORK_NAME);
+      String subnetName = templateOptions.getSubnetName().or(DEFAULT_SUBNET_NAME);
+      String addressSpaceAddressPrefix = templateOptions.getAddressSpaceAddressPrefix().or(DEFAULT_ADDRESS_SPACE_ADDRESS_PREFIX);
+      String subnetAddressPrefix = templateOptions.getSubnetAddressPrefix().or(DEFAULT_SUBNET_ADDRESS_PREFIX);
+      Set<String> networkSecurityGroupNames = templateOptions.getGroups().isEmpty() ? Sets.<String>newHashSet() : templateOptions.getGroups();
+
+      // get or create storage service
+      StorageService storageService = tryFindExistingStorageServiceAccountOrCreate(api, location, storageAccountName,
+              storageAccountType);
+      templateOptions.storageAccountName(storageService.serviceName());
+
+      // check existence or create virtual network
+      checkExistingVirtualNetworkNamedOrCreate(virtualNetworkName, location, subnetName, addressSpaceAddressPrefix, subnetAddressPrefix);
+      templateOptions.virtualNetworkName(virtualNetworkName);
+      templateOptions.subnetName(subnetName);
+
+      // add network security group to the subnet
+      if (!networkSecurityGroupNames.isEmpty()) {
+         String networkSecurityGroupName = Iterables.get(networkSecurityGroupNames, 0);
+         logger.warn("Only network security group '%s' will be applied to subnet '%s'.", networkSecurityGroupName, subnetName);
+         final NetworkSecurityGroup networkSecurityGroupAppliedToSubnet = api.getNetworkSecurityGroupApi().getNetworkSecurityGroupAppliedToSubnet(virtualNetworkName, subnetName);
+         if (networkSecurityGroupAppliedToSubnet != null) {
+            if (!networkSecurityGroupAppliedToSubnet.name().equals(networkSecurityGroupName)) {
+               logger.debug("Removing a networkSecurityGroup %s is already applied to subnet '%s' ...", networkSecurityGroupName, subnetName);
+               // remove existing nsg from subnet
+               String removeFromSubnetRequestId = api.getNetworkSecurityGroupApi().removeFromSubnet(virtualNetworkName, subnetName, networkSecurityGroupAppliedToSubnet.name());
+               if (!operationSucceededPredicate.apply(removeFromSubnetRequestId)) {
+                  final String warnMessage = format("Remove existing networkSecurityGroup(%s) to subnet(%s) has not been completed " +
+                          "within %sms.", networkSecurityGroupName, subnetName, azureComputeConstants.operationTimeout());
+                  logger.warn(warnMessage);
+                  String illegalStateExceptionMessage = format("%s. Please, try by increasing `%s` and try again",
+                          AzureComputeProperties.OPERATION_TIMEOUT, warnMessage);
+                  throw new IllegalStateException(illegalStateExceptionMessage);
+               }
+            }
+         }
+         // add nsg to subnet
+         logger.debug("Adding a networkSecurityGroup %s is already applied to subnet '%s' of virtual network %s ...", networkSecurityGroupName, subnetName, virtualNetworkName);
+         String addToSubnetId = api.getNetworkSecurityGroupApi().addToSubnet(virtualNetworkName, subnetName,
+                 NetworkSecurityGroup.create(networkSecurityGroupName, null, null, null));
+         if (!operationSucceededPredicate.apply(addToSubnetId)) {
+            final String warnMessage = format("Add networkSecurityGroup(%s) to subnet(%s) has not been completed " +
+                    "within %sms.", networkSecurityGroupName, subnetName, azureComputeConstants.operationTimeout());
+            logger.warn(warnMessage);
+            String illegalStateExceptionMessage = format("%s. Please, try by increasing `%s` and try again",
+                    AzureComputeProperties.OPERATION_TIMEOUT, warnMessage);
+            throw new IllegalStateException(illegalStateExceptionMessage);
+         }
+      }
+      return super.execute(group, count, template, goodNodes, badNodes, customizationResponses);
+   }
+
+   /**
+    * Tries to find a storage service account whose name matches the regex DEFAULT_STORAGE_ACCOUNT_PREFIX+"[a-z]{10}"
+    * in the location, otherwise it creates a new storage service account with name and type in the location
+    */
+   private StorageService tryFindExistingStorageServiceAccountOrCreate(AzureComputeApi api, String location, final String name, final String type) {
+      final List<StorageService> storageServices = api.getStorageAccountApi().list();
+      Predicate<StorageService> storageServicePredicate;
+      logger.debug("Looking for a suitable existing storage account ...");
+      storageServicePredicate = and(notNull(), new SameLocationAndCreatedStorageServicePredicate(location), new Predicate<StorageService>() {
+         @Override
+         public boolean apply(StorageService input) {
+            return input.serviceName().matches(format("^%s[a-z]{10}$", DEFAULT_STORAGE_ACCOUNT_PREFIX));
+         }
+      });
+      final Optional<StorageService> storageServiceOptional = tryFind(storageServices, storageServicePredicate);
+      if (storageServiceOptional.isPresent()) {
+         final StorageService storageService = storageServiceOptional.get();
+         logger.debug("Found a suitable existing storage service account '%s'", storageService);
+         return storageService;
+      } else {
+         // create
+         if (!checkAvailability(name)) {
+            logger.warn("The storage service account name %s is not available", name);
+            throw new IllegalStateException(format("Can't create a valid storage account with name %s. " +
+                    "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);
+         String createStorateServiceRequestId = api.getStorageAccountApi().create(StorageServiceParams.builder()
+                 .name(name)
+                 .label(name)
+                 .location(location)
+                 .accountType(StorageServiceParams.Type.valueOf(type))
+                 .build());
+         if (!operationSucceededPredicate.apply(createStorateServiceRequestId)) {
+            final String warnMessage = format("Create storage service account has not been completed within %sms.", azureComputeConstants.operationTimeout());
+            logger.warn(warnMessage);
+            String illegalStateExceptionMessage = format("%s. Please, try by increasing `%s` and try again",
+                    AzureComputeProperties.OPERATION_TIMEOUT, warnMessage);
+            throw new IllegalStateException(illegalStateExceptionMessage);
+         }
+         return api.getStorageAccountApi().get(name);
+      }
+   }
+
+   private void checkExistingVirtualNetworkNamedOrCreate(final String virtualNetworkName, String
+           location, String subnetName, String addressSpaceAddressPrefix, String subnetAddressPrefix) {
+      logger.debug("Looking for a virtual network named '%s' ...", virtualNetworkName);
+      Optional<NetworkConfiguration.VirtualNetworkSite> networkSiteOptional = getVirtualNetworkNamed(virtualNetworkName);
+      if (networkSiteOptional.isPresent()) return;
+      final NetworkConfiguration networkConfiguration = NetworkConfiguration.create(
+              NetworkConfiguration.VirtualNetworkConfiguration.create(null,
+                      ImmutableList.of(NetworkConfiguration.VirtualNetworkSite.create(
+                              UUID.randomUUID().toString(),
+                              virtualNetworkName,
+                              location,
+                              NetworkConfiguration.AddressSpace.create(addressSpaceAddressPrefix),
+                              ImmutableList.of(NetworkConfiguration.Subnet.create(subnetName, subnetAddressPrefix, null))))
+              )
+      );
+      logger.debug("Creating a virtual network with configuration '%s' ...", networkConfiguration);
+      String setNetworkConfigurationRequestId = api.getVirtualNetworkApi().set(networkConfiguration);
+      if (!operationSucceededPredicate.apply(setNetworkConfigurationRequestId)) {
+         final String warnMessage = format("Network configuration (%s) has not been completed within %sms.",
+                 networkConfiguration, azureComputeConstants.operationTimeout());
+         logger.warn(warnMessage);
+         String illegalStateExceptionMessage = format("%s. Please, try by increasing `%s` and try again",
+                 AzureComputeProperties.OPERATION_TIMEOUT, warnMessage);
+         throw new IllegalStateException(illegalStateExceptionMessage);
+      }   }
+
+   private Optional<NetworkConfiguration.VirtualNetworkSite> getVirtualNetworkNamed(final String virtualNetworkName) {
+      return FluentIterable.from(api.getVirtualNetworkApi().list())
+              .filter(new Predicate<NetworkConfiguration.VirtualNetworkSite>() {
+                 @Override
+                 public boolean apply(NetworkConfiguration.VirtualNetworkSite input) {
+                    return input.name().equals(virtualNetworkName);
+                 }
+              })
+              .first();
+   }
+
+   private boolean checkAvailability(String name) {
+      return api.getStorageAccountApi().checkAvailable(name).result();
+   }
+
+   private static String generateStorageServiceName(String prefix) {
+      String characters = "abcdefghijklmnopqrstuvwxyz";
+      StringBuilder builder = new StringBuilder();
+      builder.append(prefix);
+      int charactersLength = characters.length();
+      for (int i = 0; i < 10; i++) {
+         double index = Math.random() * charactersLength;
+         builder.append(characters.charAt((int) index));
+      }
+      return builder.toString();
+   }
+
+   private static class SameLocationAndCreatedStorageServicePredicate implements Predicate<StorageService> {
+      private final String location;
+
+      public SameLocationAndCreatedStorageServicePredicate(String location) {
+         this.location = location;
+      }
+
+      @Override
+      public boolean apply(StorageService input) {
+         return input.storageServiceProperties().location().equals(location) && input.storageServiceProperties().status().equals("Created");
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java
new file mode 100644
index 0000000..9250369
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/compute/strategy/UseNodeCredentialsButOverrideFromTemplate.java
@@ -0,0 +1,57 @@
+/*
+ * 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.compute.strategy;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.options.RunScriptOptions;
+import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate;
+import org.jclouds.domain.LoginCredentials;
+
+import com.google.common.base.Function;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * Azure needs the credentials to insert the node so the node credentials already take the Image credentials into
+ * account, as such only overriding the TemplateOptions credentials is required.
+ */
+@Singleton
+public class UseNodeCredentialsButOverrideFromTemplate extends PrioritizeCredentialsFromTemplate {
+
+
+   @Inject
+   public UseNodeCredentialsButOverrideFromTemplate(
+           Function<Template, LoginCredentials> credentialsFromImageOrTemplateOptions) {
+      super(credentialsFromImageOrTemplateOptions);
+   }
+
+   public LoginCredentials apply(Template template, LoginCredentials fromNode) {
+      RunScriptOptions options = checkNotNull(template.getOptions(), "template options are required");
+      LoginCredentials.Builder builder = LoginCredentials.builder(fromNode);
+      if (options.getLoginUser() != null)
+         builder.user(template.getOptions().getLoginUser());
+      if (options.getLoginPassword() != null)
+         builder.password(options.getLoginPassword());
+      if (options.getLoginPrivateKey() != null)
+         builder.privateKey(options.getLoginPrivateKey());
+      if (options.shouldAuthenticateSudo() != null && options.shouldAuthenticateSudo())
+         builder.authenticateSudo(true);
+      return builder.build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeHttpApiModule.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeHttpApiModule.java b/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeHttpApiModule.java
index 2d07471..96bdd50 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeHttpApiModule.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeHttpApiModule.java
@@ -21,18 +21,42 @@ import java.security.KeyStore;
 import javax.net.ssl.SSLContext;
 
 import org.jclouds.azurecompute.AzureComputeApi;
+import org.jclouds.azurecompute.handlers.AzureComputeErrorHandler;
 import org.jclouds.azurecompute.suppliers.KeyStoreSupplier;
 import org.jclouds.azurecompute.suppliers.SSLContextWithKeysSupplier;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.location.config.LocationModule;
+import org.jclouds.location.suppliers.ImplicitLocationSupplier;
+import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
 import org.jclouds.rest.ConfiguresHttpApi;
 import org.jclouds.rest.config.HttpApiModule;
 
 import com.google.common.base.Supplier;
+import com.google.inject.Scopes;
 import com.google.inject.TypeLiteral;
 
 @ConfiguresHttpApi
 public class AzureComputeHttpApiModule extends HttpApiModule<AzureComputeApi> {
+
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(AzureComputeErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(AzureComputeErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(AzureComputeErrorHandler.class);
+   }
+
+   @Override
+   protected void installLocations() {
+      install(new LocationModule());
+      bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Scopes.SINGLETON);
+   }
+   
    @Override
    protected void configure() {
+      install(new AzureComputeParserModule());
       super.configure();
       bind(new TypeLiteral<Supplier<SSLContext>>() {
       }).to(new TypeLiteral<SSLContextWithKeysSupplier>() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeParserModule.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeParserModule.java b/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeParserModule.java
new file mode 100644
index 0000000..cc001d1
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeParserModule.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.config;
+
+import org.jclouds.json.config.GsonModule;
+
+import com.google.inject.AbstractModule;
+
+public class AzureComputeParserModule extends AbstractModule {
+   @Override protected void configure() {
+      bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeProperties.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeProperties.java b/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeProperties.java
index 0981c7c..44ec8aa 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeProperties.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/config/AzureComputeProperties.java
@@ -21,16 +21,13 @@ package org.jclouds.azurecompute.config;
  * connections.
  */
 public class AzureComputeProperties {
-	/**
-	 * Every call to the Service Management API must include the subscription ID
-	 * for your subscription. The subscription ID is appended to the base URI,
-	 * as follows:
-	 *
-	 * <pre>
-	 * https://management.core.windows.net/${subscriptionId}
-	 * </pre>
-	 *
-	 * @see <a href="http://msdn.microsoft.com/en-us/library/ee460786">docs</a>
-	 */
-	public static final String SUBSCRIPTION_ID = "jclouds.azurecompute.subscription-id";
+
+	public static final String OPERATION_TIMEOUT = "jclouds.azurecompute.operation.timeout";
+
+   public static final String OPERATION_POLL_INITIAL_PERIOD = "jclouds.azurecompute..operation.poll.initial.period";
+
+   public static final String OPERATION_POLL_MAX_PERIOD = "jclouds.azurecompute.operation.poll.max.period";
+
+   public static final String TCP_RULE_FORMAT = "jclouds.azurecompute.tcp.rule.format";
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/domain/NetworkConfiguration.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/NetworkConfiguration.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/NetworkConfiguration.java
index c4f1e55..22df816 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/NetworkConfiguration.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/NetworkConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.azurecompute.domain;
 
+import static com.google.common.collect.ImmutableList.copyOf;
 import java.util.List;
 
 import org.jclouds.javax.annotation.Nullable;
@@ -74,12 +75,25 @@ public abstract class NetworkConfiguration {
 
    }
 
+   @AutoValue
+   public abstract static class VirtualNetworkConfiguration {
+
+      VirtualNetworkConfiguration() {
+      } // For AutoValue only!
+
+      @Nullable public abstract String dns();
+      @Nullable public abstract List<VirtualNetworkSite> virtualNetworkSites();
+
+      public static VirtualNetworkConfiguration create(String dns, List<VirtualNetworkSite> virtualNetworkSites) {
+         return new AutoValue_NetworkConfiguration_VirtualNetworkConfiguration(dns, copyOf(virtualNetworkSites));
+      }
+   }
+
    public NetworkConfiguration() {} // For AutoValue only!
 
-   @Nullable public abstract String dns();
-   @Nullable public abstract List<VirtualNetworkSite> virtualNetworkSites();
+   public abstract VirtualNetworkConfiguration virtualNetworkConfiguration();
 
-   public static NetworkConfiguration create(String dns, List<VirtualNetworkSite> virtualNetworkSites) {
-      return new AutoValue_NetworkConfiguration(dns, virtualNetworkSites);
+   public static NetworkConfiguration create(VirtualNetworkConfiguration virtualNetworkConfiguration) {
+      return new AutoValue_NetworkConfiguration(virtualNetworkConfiguration);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/domain/Role.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/Role.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/Role.java
index c0207af..bb387ef 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/Role.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/Role.java
@@ -120,13 +120,16 @@ public abstract class Role {
 
       @Nullable public abstract List<PublicIP> publicIPs();
 
+      @Nullable public abstract String networkSecurityGroup();
+
       ConfigurationSet() { // For AutoValue only!
       }
 
       public static ConfigurationSet create(String configurationSetType, List<InputEndpoint> inputEndpoints,
-                                            List<SubnetName> subnetNames, String staticVirtualNetworkIPAddress, List<PublicIP> publicIPs) {
+                                            List<SubnetName> subnetNames, String staticVirtualNetworkIPAddress,
+                                            List<PublicIP> publicIPs, String networkSecurityGroup) {
          return new AutoValue_Role_ConfigurationSet(configurationSetType, inputEndpoints, subnetNames,
-                 staticVirtualNetworkIPAddress, publicIPs);
+                 staticVirtualNetworkIPAddress, publicIPs, networkSecurityGroup);
       }
    }
 
@@ -158,7 +161,7 @@ public abstract class Role {
 
       public abstract String version();
 
-      public abstract List<ResourceExtensionParameterValue> resourceExtensionParameterValues();
+      @Nullable public abstract List<ResourceExtensionParameterValue> resourceExtensionParameterValues();
 
       public abstract String state();
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/features/DeploymentApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/DeploymentApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/DeploymentApi.java
index 69ceba6..2e771b4 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/features/DeploymentApi.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/DeploymentApi.java
@@ -75,4 +75,5 @@ public interface DeploymentApi {
    @Fallback(NullOnNotFoundOr404.class)
    @ResponseParser(ParseRequestIdHeader.class)
    String delete(@PathParam("name") String name);
+   
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/features/NetworkSecurityGroupApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/NetworkSecurityGroupApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/NetworkSecurityGroupApi.java
new file mode 100644
index 0000000..673413c
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/NetworkSecurityGroupApi.java
@@ -0,0 +1,167 @@
+/*
+ * 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.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import java.util.List;
+
+import javax.inject.Named;
+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;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.azurecompute.binders.NetworkSecurityGroupToXML;
+import org.jclouds.azurecompute.binders.RuleToXML;
+import org.jclouds.azurecompute.domain.NetworkSecurityGroup;
+import org.jclouds.azurecompute.domain.Rule;
+import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
+import org.jclouds.azurecompute.xml.ListNetworkSecurityGroupsHandler;
+import org.jclouds.azurecompute.xml.NetworkSecurityGroupHandler;
+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;
+
+@Path("/services/networking")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface NetworkSecurityGroupApi {
+
+   /**
+    * Lists all of the Network Security Groups for the subscription.
+    *
+    */
+   @Named("ListNetworkSecurityGroups")
+   @Path("/networksecuritygroups")
+   @GET
+   @XMLResponseParser(ListNetworkSecurityGroupsHandler.class)
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<NetworkSecurityGroup> list();
+
+   @Named("CreateNetworkSecurityGroup")
+   @Path("/networksecuritygroups")
+   @POST
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String create(@BinderParam(NetworkSecurityGroupToXML.class) NetworkSecurityGroup networkSecurityGroup);
+
+   /**
+    * Deletes the pecified Network Security Group from your subscription.
+    * If the Network Security group is still associated with some VM/Role/Subnet, the deletion will fail.
+    * In order to successfully delete the Network Security, it needs to be not used.
+    *
+    * @param networkSecurityGroupName
+    * @return request id
+    */
+   @Named("CreateNetworkSecurityGroup")
+   @Path("/networksecuritygroups/{networkSecurityGroupName}")
+   @DELETE
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String delete(@PathParam("networkSecurityGroupName") String networkSecurityGroupName);
+
+
+   /**
+    * Gets the Network Security Group applied to a specific subnet.
+    *
+    * @param virtualNetworkName
+    * @param subnetName
+    * @return
+    */
+   @Named("GetsNetworkSecurityGroupAppliedToSubnet")
+   @Path("/virtualnetwork/{virtualNetworkName}/subnets/{subnetName}/networksecuritygroups")
+   @GET
+   @XMLResponseParser(NetworkSecurityGroupHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   NetworkSecurityGroup getNetworkSecurityGroupAppliedToSubnet(@PathParam("virtualNetworkName") String virtualNetworkName,
+                            @PathParam("subnetName") String subnetName);
+
+   /**
+    * Gets the details for the specified Network Security Group in the subscription
+    *
+    * @param networkSecurityGroupName
+    * @return
+    */
+   @Named("GetDetailsNetworkSecurityGroup")
+   @Path("/networksecuritygroups/{networkSecurityGroupName}")
+   @GET
+   @QueryParams(keys = "detaillevel", values = "Full")
+   @XMLResponseParser(NetworkSecurityGroupHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   NetworkSecurityGroup getFullDetails(@PathParam("networkSecurityGroupName") String networkSecurityGroupName);
+
+   /**
+    *  Adds a Network Security Group to a subnet.
+    *
+    * @param virtualNetworkName
+    * @return
+    */
+   @Named("AddNetworkSecurityGroupToSubnet")
+   @Path("/virtualnetwork/{virtualNetworkName}/subnets/{subnetName}/networksecuritygroups")
+   @POST
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String addToSubnet(@PathParam("virtualNetworkName") String virtualNetworkName,
+                      @PathParam("subnetName") String subnetName,
+                      @BinderParam(NetworkSecurityGroupToXML.class) NetworkSecurityGroup networkSecurityGroup);
+
+   /**
+    * Removes a Network Security Group from a subnet
+    */
+   @Named("RemoveNetworkSecurityGroupToSubnet")
+   @Path("/virtualnetwork/{virtualNetworkName}/subnets/{subnetName}/networksecuritygroups/{networkSecurityGroupName}")
+   @DELETE
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String removeFromSubnet(@PathParam("virtualNetworkName") String virtualNetworkName,
+                      @PathParam("subnetName") String subnetName,
+                      @PathParam("networkSecurityGroupName") String networkSecurityGroupName);
+
+   /**
+    * Sets a new Network Security Rule to existing Network Security Group
+    *
+    *
+    */
+   @Named("SetNetworkSecurityRuleToNetworkSecurityGroup")
+   @Path("/networksecuritygroups/{networkSecurityGroupName}/rules/{ruleName}")
+   @PUT
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String setRule(@PathParam("networkSecurityGroupName") String networkSecurityGroupName,
+                      @PathParam("ruleName") String ruleName, @BinderParam(RuleToXML.class) Rule rule);
+
+   /**
+    * Deletes a rule from the specified Network Security Group.
+    *
+    */
+   @Named("SetNetworkSecurityRuleToNetworkSecurityGroup")
+   @Path("/networksecuritygroups/{networkSecurityGroupName}/rules/{ruleName}")
+   @DELETE
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String deleteRule(@PathParam("networkSecurityGroupName") String networkSecurityGroupName,
+                  @PathParam("ruleName") String ruleName);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/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
new file mode 100644
index 0000000..0a5837c
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/StorageAccountApi.java
@@ -0,0 +1,97 @@
+/*
+ * 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 javax.ws.rs.core.MediaType.APPLICATION_XML;
+import java.util.List;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.azurecompute.binders.StorageServiceParamsToXML;
+import org.jclouds.azurecompute.domain.Availability;
+import org.jclouds.azurecompute.domain.StorageService;
+import org.jclouds.azurecompute.domain.StorageServiceParams;
+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.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+@Path("/services/storageservices")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface StorageAccountApi {
+
+   /**
+    * 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);
+
+   /**
+    * https://management.core.windows.net/<subscription-id>/services/storageservices
+    */
+   @Named("GetStorageAccountDetails")
+   @GET
+   @Path("/{storageAccountName}")
+   @XMLResponseParser(StorageServiceHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   StorageService get(@PathParam("storageAccountName") String storageAccountName);
+
+   /**
+    * 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 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 checkAvailable(@PathParam("storageAccountName") String storageAccountName);
+
+   @Named("DeleteStorageAccount")
+   @DELETE
+   @Path("/{serviceName}")
+   @ResponseParser(ParseRequestIdHeader.class)
+   String delete(String serviceName);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/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
new file mode 100644
index 0000000..08fb45a
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/SubscriptionApi.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import java.util.List;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.azurecompute.domain.RoleSize;
+import org.jclouds.azurecompute.xml.ListRoleSizesHandler;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+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>
+ */
+@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.
+    */
+   @Named("ListRoleSizes")
+   @GET
+   @XMLResponseParser(ListRoleSizesHandler.class)
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<RoleSize> listRoleSizes();
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
index 9f54ed0..468b488 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
@@ -16,15 +16,23 @@
  */
 package org.jclouds.azurecompute.features;
 
+import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
+
 import javax.inject.Named;
 import javax.ws.rs.Consumes;
+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;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.azurecompute.binders.RoleToXML;
+import org.jclouds.azurecompute.domain.Role;
 import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.Headers;
 import org.jclouds.rest.annotations.Payload;
 import org.jclouds.rest.annotations.PayloadParam;
@@ -36,7 +44,7 @@ import org.jclouds.rest.annotations.ResponseParser;
  *
  * @see <a href="http://msdn.microsoft.com/en-us/library/jj157206">docs</a>
  */
-@Path("/services/hostedservices/{serviceName}/deployments/{deploymentName}/roleinstances")
+@Path("/services/hostedservices/{serviceName}/deployments/{deploymentName}")
 @Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
 @Consumes(MediaType.APPLICATION_XML)
 // NOTE: MS Docs refer to the commands as Role, but in the description, it is always Virtual Machine.
@@ -46,7 +54,7 @@ public interface VirtualMachineApi {
    @POST
    // Warning : the url in the documentation is WRONG ! @see
    // http://social.msdn.microsoft.com/Forums/pl-PL/WAVirtualMachinesforWindows/thread/7ba2367b-e450-49e0-89e4-46c240e9d213
-   @Path("/{name}/Operations")
+   @Path("/roleinstances/{name}/Operations")
    @Produces(MediaType.APPLICATION_XML)
    @ResponseParser(ParseRequestIdHeader.class)
    @Payload(value = "<RestartRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\"><OperationType>RestartRoleOperation</OperationType></RestartRoleOperation>")
@@ -57,7 +65,7 @@ public interface VirtualMachineApi {
     */
    @Named("CaptureRole")
    @POST
-   @Path("/{name}/Operations")
+   @Path("/roleinstances/{name}/Operations")
    @Produces(MediaType.APPLICATION_XML)
    @ResponseParser(ParseRequestIdHeader.class)
    @Payload(value = "<CaptureRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\"><OperationType>CaptureRoleOperation</OperationType><PostCaptureAction>Delete</PostCaptureAction><TargetImageLabel>{imageLabel}</TargetImageLabel><TargetImageName>{imageName}</TargetImageName></CaptureRoleOperation>")
@@ -69,7 +77,7 @@ public interface VirtualMachineApi {
     */
    @Named("ShutdownRole")
    @POST
-   @Path("/{name}/Operations")
+   @Path("/roleinstances/{name}/Operations")
    @Produces(MediaType.APPLICATION_XML)
    @ResponseParser(ParseRequestIdHeader.class)
    @Payload(value = "<ShutdownRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\"><OperationType>ShutdownRoleOperation</OperationType></ShutdownRoleOperation>")
@@ -80,9 +88,31 @@ public interface VirtualMachineApi {
     */
    @Named("StartRole")
    @POST
-   @Path("/{name}/Operations")
+   @Path("/roleinstances/{name}/Operations")
    @Produces(MediaType.APPLICATION_XML)
    @ResponseParser(ParseRequestIdHeader.class)
    @Payload(value = "<StartRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\"><OperationType>StartRoleOperation</OperationType></StartRoleOperation>")
    String start(@PathParam("name") String name);
+
+   /**
+    * https://msdn.microsoft.com/en-us/library/azure/jj157193.aspx
+    */
+   @Named("GetRole")
+   @GET
+   @Path("/roles/{roleName}")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   Role getRole(@PathParam("roleName") String roleName);
+
+   /**
+    * https://msdn.microsoft.com/library/azure/jj157187.aspx
+    */
+   @Named("UpdateRole")
+   @PUT
+   @Path("/roles/{roleName}")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String updateRole(@PathParam("roleName") String roleName, @BinderParam(RoleToXML.class) Role role);
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualNetworkApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualNetworkApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualNetworkApi.java
new file mode 100644
index 0000000..e091464
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualNetworkApi.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.features;
+
+import static org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
+
+import java.util.List;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.azurecompute.binders.NetworkConfigurationToXML;
+import org.jclouds.azurecompute.domain.NetworkConfiguration;
+import org.jclouds.azurecompute.domain.NetworkConfiguration.VirtualNetworkSite;
+import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
+import org.jclouds.azurecompute.xml.ListVirtualNetworkSitesHandler;
+import org.jclouds.azurecompute.xml.NetworkConfigurationHandler;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+@Path("/services/networking")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface VirtualNetworkApi {
+
+   /**
+    * The Get Network Configuration operation retrieves the network configuration file.
+    *
+    * @return The response body is a netcfg.cfg file.
+
+    */
+   @Named("GetVirtualNetworkConfiguration")
+   @Path("/media")
+   @GET
+   @XMLResponseParser(NetworkConfigurationHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   NetworkConfiguration getNetworkConfiguration();
+
+   @Named("ListVirtualNetworkSites")
+   @Path("/virtualnetwork")
+   @GET
+   @XMLResponseParser(ListVirtualNetworkSitesHandler.class)
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<VirtualNetworkSite> list();
+
+   @Named("SetVirtualNetworkConfiguration")
+   @Path("/media")
+   @PUT
+   @Produces(MediaType.TEXT_PLAIN)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String set(@BinderParam(NetworkConfigurationToXML.class) NetworkConfiguration networkConfiguration);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/options/AzureComputeTemplateOptions.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/options/AzureComputeTemplateOptions.java b/azurecompute/src/main/java/org/jclouds/azurecompute/options/AzureComputeTemplateOptions.java
new file mode 100644
index 0000000..3a986d9
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/options/AzureComputeTemplateOptions.java
@@ -0,0 +1,324 @@
+/*
+ * 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.options;
+
+import java.util.Map;
+
+import org.jclouds.compute.options.TemplateOptions;
+
+import com.google.common.base.Optional;
+
+/**
+ * Contains options supported by the
+ * {@link org.jclouds.compute.ComputeService#createNodesInGroup(String, int, org.jclouds.compute.options.TemplateOptions)} and
+ * {@link org.jclouds.compute.ComputeService#createNodesInGroup(String, int, org.jclouds.compute.options.TemplateOptions)}
+ * operations on the <em>gogrid</em> provider.
+ *
+ * <h2>Usage</h2> The recommended way to instantiate a
+ * {@link AzureComputeTemplateOptions} object is to statically import
+ * {@code AzureComputeTemplateOptions.*} and invoke a static creation method
+ * followed by an instance mutator (if needed):
+ * <p>
+ *
+ * <pre>
+ * import static org.jclouds.compute.options.AzureComputeTemplateOptions.Builder.*;
+ * ComputeService client = // get connection
+ * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
+ * Set&lt;? extends NodeMetadata&gt; set = client.createNodesInGroup(tag, 2, templateBuilder.build());
+ * </pre>
+ *
+ */
+public class AzureComputeTemplateOptions extends TemplateOptions implements Cloneable {
+
+   private Optional<String> virtualNetworkName = Optional.absent();
+   private Optional<String> addressSpaceAddressPrefix = Optional.absent();
+   private Optional<String> subnetName = Optional.absent();
+   private Optional<String> subnetAddressPrefix = Optional.absent();
+   private Optional<String> storageAccountName = Optional.absent();
+   private Optional<String> storageAccountType = Optional.absent();
+   private Optional<String> networkSecurityGroupName = Optional.absent();
+
+   @Override
+   public AzureComputeTemplateOptions clone() {
+      AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+      copyTo(options);
+      return options;
+   }
+
+   @Override
+   public void copyTo(TemplateOptions to) {
+      super.copyTo(to);
+      if (to instanceof AzureComputeTemplateOptions) {
+         AzureComputeTemplateOptions eTo = AzureComputeTemplateOptions.class.cast(to);
+         if (virtualNetworkName.isPresent()) {
+            eTo.virtualNetworkName(virtualNetworkName.get());
+         }
+         if (addressSpaceAddressPrefix.isPresent()) {
+            eTo.addressSpaceAddressPrefix(addressSpaceAddressPrefix.get());
+         }
+         if (subnetName.isPresent()) {
+            eTo.subnetName(subnetName.get());
+         }
+         if (networkSecurityGroupName.isPresent()) {
+            eTo.subnetName(networkSecurityGroupName.get());
+         }
+         if (subnetAddressPrefix.isPresent()) {
+            eTo.subnetAddressPrefix(subnetAddressPrefix.get());
+         }
+         if (storageAccountName.isPresent()) {
+            eTo.storageAccountName(storageAccountName.get());
+         }
+         if (storageAccountType.isPresent()) {
+            eTo.storageAccountType(storageAccountType.get());
+         }
+      }
+   }
+
+   public TemplateOptions virtualNetworkName(String virtualNetworkName) {
+      this.virtualNetworkName = Optional.of(virtualNetworkName);
+      return this;
+   }
+
+   public TemplateOptions addressSpaceAddressPrefix(String addressSpaceAddressPrefix) {
+      this.addressSpaceAddressPrefix = Optional.of(addressSpaceAddressPrefix);
+      return this;
+   }
+
+   public TemplateOptions subnetName(String subnetName) {
+      this.subnetName = Optional.of(subnetName);
+      return this;
+   }
+
+   public TemplateOptions networkSecurityGroupName(String networkSecurityGroupName) {
+      this.networkSecurityGroupName = Optional.of(networkSecurityGroupName);
+      return this;
+   }
+
+   public TemplateOptions subnetAddressPrefix(String subnetAddressPrefix) {
+      this.subnetAddressPrefix = Optional.of(subnetAddressPrefix);
+      return this;
+   }
+
+   public TemplateOptions storageAccountName(String storageAccountName) {
+      this.storageAccountName = Optional.of(storageAccountName);
+      return this;
+   }
+
+   public TemplateOptions storageAccountType(String storageAccountType) {
+      this.storageAccountType = Optional.of(storageAccountType);
+      return this;
+   }
+
+   public Optional<String> getVirtualNetworkName() {
+      return virtualNetworkName;
+   }
+
+   public Optional<String> getAddressSpaceAddressPrefix() {
+      return addressSpaceAddressPrefix;
+   }
+
+   public Optional<String> getSubnetName() { return subnetName; }
+
+   public Optional<String> getSubnetAddressPrefix() { return subnetAddressPrefix; }
+
+   public Optional<String> getStorageAccountName() {
+      return storageAccountName;
+   }
+
+   public Optional<String> getStorageAccountType() {
+      return storageAccountType;
+   }
+
+   public Optional<String> getNetworkSecurityGroupName() {
+      return networkSecurityGroupName;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see #virtualNetworkName
+       */
+      public static AzureComputeTemplateOptions virtualNetworkName(String virtualNetworkName) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.virtualNetworkName(virtualNetworkName));
+      }
+
+      /**
+       * @see #addressSpaceAddressPrefix
+       */
+      public static AzureComputeTemplateOptions addressSpaceAddressPrefix(String addressSpaceAddressPrefix) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.addressSpaceAddressPrefix(addressSpaceAddressPrefix));
+      }
+
+      /**
+       * @see #subnetName
+       */
+      public static AzureComputeTemplateOptions subnetName(String subnetName) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.subnetName(subnetName));
+      }
+
+      /**
+       * @see #networkSecurityGroupName
+       */
+      public static AzureComputeTemplateOptions networkSecurityGroupName(String networkSecurityGroupName) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.subnetName(networkSecurityGroupName));
+      }
+
+      /**
+       * @see #subnetAddressPrefix
+       */
+      public static AzureComputeTemplateOptions subnetAddressPrefix(String subnetAddressPrefix) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.subnetAddressPrefix(subnetAddressPrefix));
+      }
+
+      /**
+       * @see #storageAccountName
+       */
+      public static AzureComputeTemplateOptions storageAccountName(String storageAccountName) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.storageAccountName(storageAccountName));
+      }
+
+      /**
+       * @see #storageAccountType
+       */
+      public static AzureComputeTemplateOptions storageAccountType(String storageAccountType) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.storageAccountType(storageAccountType));
+      }
+
+      // methods that only facilitate returning the correct object type
+
+      /**
+       * @see org.jclouds.compute.options.TemplateOptions#inboundPorts(int...)
+       */
+      public static AzureComputeTemplateOptions inboundPorts(int... ports) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.inboundPorts(ports));
+      }
+
+      /**
+       * @see org.jclouds.compute.options.TemplateOptions#blockOnPort(int, int)
+       */
+      public static AzureComputeTemplateOptions blockOnPort(int port, int seconds) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.blockOnPort(port, seconds));
+      }
+
+      /**
+       * @see org.jclouds.compute.options.TemplateOptions#userMetadata(java.util.Map)
+       */
+      public static AzureComputeTemplateOptions userMetadata(Map<String, String> userMetadata) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.userMetadata(userMetadata));
+      }
+
+      /**
+       * @see org.jclouds.compute.options.TemplateOptions#userMetadata(String, String)
+       */
+      public static AzureComputeTemplateOptions userMetadata(String key, String value) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.userMetadata(key, value));
+      }
+
+      /**
+       * @see org.jclouds.compute.options.TemplateOptions#nodeNames(Iterable)
+       */
+      public static AzureComputeTemplateOptions nodeNames(Iterable<String> nodeNames) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.nodeNames(nodeNames));
+      }
+
+      /**
+       * @see org.jclouds.compute.options.TemplateOptions#networks(Iterable)
+       */
+      public static AzureComputeTemplateOptions networks(Iterable<String> networks) {
+         AzureComputeTemplateOptions options = new AzureComputeTemplateOptions();
+         return AzureComputeTemplateOptions.class.cast(options.networks(networks));
+      }
+   }
+
+   // methods that only facilitate returning the correct object type
+
+   /**
+    * @see org.jclouds.compute.options.TemplateOptions#blockOnPort(int, int)
+    */
+   @Override
+   public AzureComputeTemplateOptions blockOnPort(int port, int seconds) {
+      return AzureComputeTemplateOptions.class.cast(super.blockOnPort(port, seconds));
+   }
+
+   /**
+    * @see org.jclouds.compute.options.TemplateOptions#inboundPorts(int...)
+    */
+   @Override
+   public AzureComputeTemplateOptions inboundPorts(int... ports) {
+      return AzureComputeTemplateOptions.class.cast(super.inboundPorts(ports));
+   }
+
+   /**
+    * @see org.jclouds.compute.options.TemplateOptions#authorizePublicKey(String)
+    */
+   @Override
+   public AzureComputeTemplateOptions authorizePublicKey(String publicKey) {
+      return AzureComputeTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
+   }
+
+   /**
+    * @see org.jclouds.compute.options.TemplateOptions#installPrivateKey(String)
+    */
+   @Override
+   public AzureComputeTemplateOptions installPrivateKey(String privateKey) {
+      return AzureComputeTemplateOptions.class.cast(super.installPrivateKey(privateKey));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public AzureComputeTemplateOptions userMetadata(Map<String, String> userMetadata) {
+      return AzureComputeTemplateOptions.class.cast(super.userMetadata(userMetadata));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public AzureComputeTemplateOptions userMetadata(String key, String value) {
+      return AzureComputeTemplateOptions.class.cast(super.userMetadata(key, value));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public AzureComputeTemplateOptions nodeNames(Iterable<String> nodeNames) {
+      return AzureComputeTemplateOptions.class.cast(super.nodeNames(nodeNames));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public AzureComputeTemplateOptions networks(Iterable<String> networks) {
+      return AzureComputeTemplateOptions.class.cast(super.networks(networks));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/util/NetworkSecurityGroups.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/util/NetworkSecurityGroups.java b/azurecompute/src/main/java/org/jclouds/azurecompute/util/NetworkSecurityGroups.java
new file mode 100644
index 0000000..687da7e
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/util/NetworkSecurityGroups.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.jclouds.azurecompute.config.AzureComputeProperties;
+import org.jclouds.azurecompute.domain.NetworkSecurityGroup;
+import org.jclouds.azurecompute.domain.Rule;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+
+public class NetworkSecurityGroups {
+
+   public static List<Rule> getCustomRules(NetworkSecurityGroup networkSecurityGroup) {
+      final List<Rule> rules = networkSecurityGroup.rules();
+      return FluentIterable.from(rules)
+              .filter(Predicates.notNull())
+              .filter(new Predicate<Rule>() {
+                 @Override
+                 public boolean apply(Rule rule) {
+                    return rule.isDefault() == null || !rule.isDefault();
+                 }
+              })
+              .toSortedList(new Comparator<Rule>() {
+                 @Override
+                 public int compare(Rule r1, Rule r2) {
+                    int p1 = Integer.parseInt(r1.priority());
+                    int p2 = Integer.parseInt(r2.priority());
+                    return p1 < p2 ? -1 : p1 == p2 ? 0 : 1;
+
+                 }
+              });
+   }
+
+   public static int getFirstAvailablePriority(List<Rule> rules) {
+      int priority;
+      if (rules.isEmpty()) {
+         priority = 100;
+      } else {
+         priority = Integer.parseInt(Collections.max(rules, new Comparator<Rule>() {
+            @Override
+            public int compare(Rule rule1, Rule rule2) {
+               return Integer.valueOf(rule1.priority()).compareTo(Integer.valueOf(rule2.priority()));
+            }
+         }).priority()) + 1;
+      }
+      return priority;
+   }
+
+   public static String createRuleName(int fromPort, int toPort) {
+      return String.format(AzureComputeProperties.TCP_RULE_FORMAT, fromPort, toPort);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ConfigurationSetHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ConfigurationSetHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ConfigurationSetHandler.java
index 4e5b54b..8a2fb57 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ConfigurationSetHandler.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ConfigurationSetHandler.java
@@ -35,6 +35,7 @@ public class ConfigurationSetHandler extends ParseSax.HandlerForGeneratedRequest
    private List<SubnetName> subnetNames = Lists.newArrayList();
    private String staticVirtualNetworkIPAddress;
    private List<PublicIP> publicIPs = Lists.newArrayList();
+   private String networkSecurityGroup;
 
    private boolean inInputEndpoint;
    private boolean inSubnetNames;
@@ -50,13 +51,14 @@ public class ConfigurationSetHandler extends ParseSax.HandlerForGeneratedRequest
 
    @Override
    public ConfigurationSet getResult() {
-      ConfigurationSet result = ConfigurationSet.create(configurationSetType, inputEndpoint, subnetNames, staticVirtualNetworkIPAddress, publicIPs);
+      ConfigurationSet result = ConfigurationSet.create(configurationSetType, inputEndpoint, subnetNames,
+              staticVirtualNetworkIPAddress, publicIPs, networkSecurityGroup);
       resetState(); // handler is called in a loop.
       return result;
    }
 
    private void resetState() {
-      configurationSetType = staticVirtualNetworkIPAddress = null;
+      configurationSetType = staticVirtualNetworkIPAddress = networkSecurityGroup = null;
       inputEndpoint = Lists.newArrayList();
       subnetNames = Lists.newArrayList();
       publicIPs = Lists.newArrayList();
@@ -92,6 +94,8 @@ public class ConfigurationSetHandler extends ParseSax.HandlerForGeneratedRequest
          subnetNameHandler.endElement(ignoredUri, ignoredName, qName);
       } else if (qName.equals("ConfigurationSetType")) {
          configurationSetType = currentOrNull(currentText);
+      } else if (qName.equals("NetworkSecurityGroup")) {
+         networkSecurityGroup = currentOrNull(currentText);
       }
       currentText.setLength(0);
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/xml/NetworkConfigurationHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/NetworkConfigurationHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/NetworkConfigurationHandler.java
index 10666ec..648ddc0 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/NetworkConfigurationHandler.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/NetworkConfigurationHandler.java
@@ -16,54 +16,54 @@
  */
 package org.jclouds.azurecompute.xml;
 
-import static org.jclouds.util.SaxUtils.currentOrNull;
-
-import java.util.List;
-
 import org.jclouds.azurecompute.domain.NetworkConfiguration;
+import org.jclouds.azurecompute.domain.NetworkConfiguration.VirtualNetworkConfiguration;
 import org.jclouds.http.functions.ParseSax;
 import org.xml.sax.Attributes;
 
-import com.google.common.collect.Lists;
+import com.google.inject.Inject;
 
 public class NetworkConfigurationHandler extends ParseSax.HandlerForGeneratedRequestWithResult<NetworkConfiguration> {
 
-   private String dns;
-   private List<NetworkConfiguration.VirtualNetworkSite> virtualNetworkSites = Lists.newArrayList();
+   private VirtualNetworkConfiguration virtualNetworkConfiguration;
 
-   private boolean inVirtualNetworkSites;
-   private final VirtualNetworkSiteHandler virtualNetworkSiteHandler = new VirtualNetworkSiteHandler();
+   private boolean inVirtualNetworkConfiguration;
+   private final VirtualNetworkConfigurationHandler virtualNetworkConfigurationHandler;
+
+   @Inject
+   NetworkConfigurationHandler(VirtualNetworkConfigurationHandler virtualNetworkConfigurationHandler) {
+      this.virtualNetworkConfigurationHandler = virtualNetworkConfigurationHandler;
+   }
 
    private final StringBuilder currentText = new StringBuilder();
 
    @Override public void startElement(String url, String name, String qName, Attributes attributes) {
-      if (qName.equals("VirtualNetworkSite")) {
-         inVirtualNetworkSites = true;
+      if (qName.equals("VirtualNetworkConfiguration")) {
+         inVirtualNetworkConfiguration = true;
+      }
+      if (inVirtualNetworkConfiguration) {
+         virtualNetworkConfigurationHandler.startElement(url, name, qName, attributes);
       }
    }
 
    @Override
    public NetworkConfiguration getResult() {
-      return NetworkConfiguration.create(dns, virtualNetworkSites);
+      return NetworkConfiguration.create(virtualNetworkConfiguration);
    }
 
    @Override
    public void endElement(String ignoredUri, String ignoredName, String qName) {
-      if (qName.equals("Dns")) {
-         dns = currentOrNull(currentText);
-      } else if (qName.equals("VirtualNetworkSites")) {
-         inVirtualNetworkSites = false;
-      } else if (qName.equals("VirtualNetworkSite")) {
-         virtualNetworkSites.add(virtualNetworkSiteHandler.getResult());
-      } else if (inVirtualNetworkSites) {
-         virtualNetworkSiteHandler.endElement(ignoredUri, ignoredName, qName);
+      if (qName.equals("VirtualNetworkConfiguration")) {
+         virtualNetworkConfiguration = virtualNetworkConfigurationHandler.getResult();
+      } else if (inVirtualNetworkConfiguration) {
+         virtualNetworkConfigurationHandler.endElement(ignoredUri, ignoredName, qName);
       }
       currentText.setLength(0);
    }
 
    @Override public void characters(char ch[], int start, int length) {
-      if (inVirtualNetworkSites) {
-         virtualNetworkSiteHandler.characters(ch, start, length);
+      if (inVirtualNetworkConfiguration) {
+         virtualNetworkConfigurationHandler.characters(ch, start, length);
       } else
          currentText.append(ch, start, length);
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/e97ddaee/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ResourceExtensionParameterValueHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ResourceExtensionParameterValueHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ResourceExtensionParameterValueHandler.java
new file mode 100644
index 0000000..2ad6c14
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ResourceExtensionParameterValueHandler.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import org.jclouds.azurecompute.domain.Role.ResourceExtensionReference.ResourceExtensionParameterValue;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+
+public final class ResourceExtensionParameterValueHandler extends ParseSax.HandlerForGeneratedRequestWithResult<ResourceExtensionParameterValue> {
+   private String key;
+   private String value;
+   private String type;
+
+   private StringBuilder currentText = new StringBuilder();
+
+   @Override public void startElement(String uri, String localName, String qName, Attributes attributes) {
+   }
+
+   @Override public ResourceExtensionParameterValue getResult() {
+      ResourceExtensionParameterValue result = ResourceExtensionParameterValue.create(key, value, type);
+      resetState(); // handler is called in a loop.
+      return result;
+   }
+
+   private void resetState() {
+      key = value = type = null;
+   }
+
+   @Override public void endElement(String ignoredUri, String ignoredName, String qName) {
+      if (qName.equals("Key")) {
+         key = currentOrNull(currentText);
+      } else if (qName.equals("Value")) {
+         value = currentOrNull(currentText);
+      } else if (qName.equals("Type")) {
+         type = currentOrNull(currentText);
+      }
+      currentText.setLength(0);
+   }
+
+   @Override public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}