You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2021/06/29 23:37:40 UTC

[jclouds] branch master updated: JCLOUDS-1577 - Allow to provide Azure Plan Information when starting custom image based on Azure Marketplace image.

This is an automated email from the ASF dual-hosted git repository.

gaul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jclouds.git


The following commit(s) were added to refs/heads/master by this push:
     new 261f9d1  JCLOUDS-1577 - Allow to provide Azure Plan Information when starting custom image based on Azure Marketplace image.
261f9d1 is described below

commit 261f9d1fd5c190e9c11a9d65968693cee3df4008
Author: Miroslav Novak <mn...@redhat.com>
AuthorDate: Fri May 7 15:20:19 2021 +0200

    JCLOUDS-1577 - Allow to provide Azure Plan Information when starting custom image based on Azure Marketplace image.
---
 .../arm/compute/AzureComputeServiceAdapter.java    |  4 +-
 .../arm/compute/functions/VMImageToImage.java      | 43 +++++++++++--
 .../arm/compute/options/AzureTemplateOptions.java  | 70 +++++++++++++++++++++-
 3 files changed, 109 insertions(+), 8 deletions(-)

diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
index 6a21609..fbb1d74 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java
@@ -25,7 +25,7 @@ import static com.google.common.collect.Iterables.transform;
 import static com.google.common.collect.Lists.newArrayList;
 import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromSlashEncoded;
 import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName;
-import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata;
+import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.createMarketplacePlanIfPresent;
 import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS;
 import static org.jclouds.azurecompute.arm.domain.IdReference.extractName;
 import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup;
@@ -171,7 +171,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
       // custom names in the configured group
       templateOptions.getUserMetadata().put(GROUP_KEY, group);
       Map<String, String> metadataAndTags = metadataAndTagsAsCommaDelimitedValue(templateOptions);
-      Plan plan = getMarketplacePlanFromImageMetadata(image);
+      Plan plan = createMarketplacePlanIfPresent(image, templateOptions);
 
       VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).createOrUpdate(name, locationName,
             virtualMachineProperties, metadataAndTags, plan);
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
index 028ad9c..e335c76 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension;
+import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
 import org.jclouds.azurecompute.arm.domain.Plan;
 import org.jclouds.azurecompute.arm.domain.VMImage;
 import org.jclouds.collect.Memoized;
@@ -39,6 +40,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
+import com.google.common.base.Strings;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
@@ -101,12 +103,45 @@ public class VMImageToImage implements Function<VMImage, Image> {
                plan.product()));
       }
    }
-   
+
+   /**
+    * In case that image is offered from Azure Marketplace then it requires to provide "Plan Information" (publisher/name/product)
+    * when creating VM from such an image. This method first tries to get this information from image but also allows to
+    * override those values by information passed in Azure template options (@see AzureTemplateOptions).
+    *
+    * In case there is used custom image which was created from Marketplace image then plan information is missing as this image
+    * cannot be referenced in format "location/publisher/offer/sku" from which Plan Information is normally parsed.
+    * In this case user can provide plan information (planPublisher/planName/planProduct) in template otherwise VM creation fails with error.
+    * It's allowed to override any of the original "image" plan information but only if those were present.
+    *
+    * @param image image
+    * @param templateOptions Azure template options
+    * @return Plan Information (publisher, plan name, product) or null if any of publisher/name/product not defined
+    */
    @Nullable
-   public static Plan getMarketplacePlanFromImageMetadata(Image image) {
+   public static Plan createMarketplacePlanIfPresent(Image image, AzureTemplateOptions templateOptions) {
       Map<String, String> imageMetadata = image.getUserMetadata();
-      return imageMetadata.containsKey("product") ? Plan.create(imageMetadata.get("publisher"),
-            imageMetadata.get("name"), imageMetadata.get("product")) : null;
+
+      String planPublisher = getFirstNonEmptyOrReturnNull(templateOptions.getPlanPublisher(), imageMetadata.get("publisher"));
+      String planName = getFirstNonEmptyOrReturnNull(templateOptions.getPlanName(), imageMetadata.get("name"));
+      String planProduct = getFirstNonEmptyOrReturnNull(templateOptions.getPlanProduct(), imageMetadata.get("product"));
+
+      if (Strings.isNullOrEmpty(planPublisher) || Strings.isNullOrEmpty(planName) || Strings.isNullOrEmpty(planProduct)) {
+         return null;
+      } else {
+         return Plan.create(planPublisher, planName, planProduct);
+      }
+   }
+
+   @Nullable
+   private static String getFirstNonEmptyOrReturnNull(String first, String second)   {
+      if (!Strings.isNullOrEmpty(first))   {
+         return first;
+      } else if (!Strings.isNullOrEmpty(second))   {
+         return second;
+      } else {
+         return null;
+      }
    }
 
    public static Function<VMImage, OperatingSystem.Builder> osFamily() {
diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
index e6c3a03..ece527c 100644
--- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
+++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java
@@ -45,6 +45,9 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
    private List<Secrets> secrets = ImmutableList.of();
    private String customData;
    private StorageAccountType osDiskStorageType = StorageAccountType.STANDARD_LRS;
+   private String planPublisher;
+   private String planName;
+   private String planProduct;
 
    /**
     * Sets the availability set where the nodes will be configured. If it does
@@ -145,6 +148,21 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       return this;
    }
 
+   public AzureTemplateOptions planPublisher(String planPublisher) {
+      this.planPublisher = planPublisher;
+      return this;
+   }
+
+   public AzureTemplateOptions planName(String planName) {
+      this.planName = planName;
+      return this;
+   }
+
+   public AzureTemplateOptions planProduct(String planProduct) {
+      this.planProduct = planProduct;
+      return this;
+   }
+
    public AvailabilitySet getAvailabilitySet() {
       return availabilitySet;
    }
@@ -181,6 +199,18 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
       return osDiskStorageType;
    }
 
+   public String getPlanPublisher() {
+      return planPublisher;
+   }
+
+   public String getPlanName() {
+      return planName;
+   }
+
+   public String getPlanProduct() {
+      return planProduct;
+   }
+
    @Override
    public AzureTemplateOptions clone() {
       AzureTemplateOptions options = new AzureTemplateOptions();
@@ -202,6 +232,9 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          eTo.secrets(secrets);
          eTo.customData(customData);
          eTo.osDiskStorageType(osDiskStorageType);
+         eTo.planPublisher(planPublisher);
+         eTo.planName(planName);
+         eTo.planProduct(planProduct);
       }
    }
 
@@ -220,13 +253,16 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
             && Objects.equal(resourceGroup, that.resourceGroup) && Objects.equal(availabilitySet, that.availabilitySet)
             && Objects.equal(dataDisks, that.dataDisks) && Objects.equal(ipOptions, that.ipOptions)
             && Objects.equal(windowsConfiguration, that.windowsConfiguration) && Objects.equal(secrets, that.secrets)
-            && Objects.equal(this.customData, that.customData);
+            && Objects.equal(this.customData, that.customData)
+            && Objects.equal(this.planPublisher, that.planPublisher)
+            && Objects.equal(this.planName, that.planName)
+            && Objects.equal(this.planProduct, that.planProduct);
    }
 
    @Override
    public int hashCode() {
       return Objects.hashCode(super.hashCode(), availabilitySet, availabilitySetName, dataDisks, resourceGroup,
-            ipOptions, customData);
+            ipOptions, customData, planPublisher, planName, planProduct);
    }
 
    @Override
@@ -248,6 +284,12 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          toString.add("secrets", secrets);
       if (customData != null)
          toString.add("customData", customData);
+      if (planPublisher != null)
+         toString.add("publisher", planPublisher);
+      if (planName != null)
+         toString.add("planName", planName);
+      if (planProduct != null)
+         toString.add("planProduct", planProduct);
       return toString;
    }
 
@@ -340,5 +382,29 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable {
          AzureTemplateOptions options = new AzureTemplateOptions();
          return options.osDiskStorageType(osDiskStorageType);
       }
+
+      /**
+       * @see AzureTemplateOptions#planPublisher(String)
+       */
+      public static AzureTemplateOptions planPublisher(String planPublisher) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.planPublisher(planPublisher);
+      }
+
+      /**
+       * @see AzureTemplateOptions#planName(String)
+       */
+      public static AzureTemplateOptions planName(String planName) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.planName(planName);
+      }
+
+      /**
+       * @see AzureTemplateOptions#planProduct(String)
+       */
+      public static AzureTemplateOptions planProduct(String planProduct) {
+         AzureTemplateOptions options = new AzureTemplateOptions();
+         return options.planProduct(planProduct);
+      }
    }
 }