Skip to content
Permalink
Browse files
JCLOUDS-1577 - Allow to provide Azure Plan Information when starting …
…custom image based on Azure Marketplace image.
  • Loading branch information
mnovak1 authored and gaul committed Jun 29, 2021
1 parent d1bd51f commit 261f9d1fd5c190e9c11a9d65968693cee3df4008
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 8 deletions.
@@ -25,7 +25,7 @@
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 NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoN
// 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);
@@ -25,6 +25,7 @@
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.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 @@ private static void addMarketplacePlanToMetadataIfPresent(ImageBuilder builder,
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() {
@@ -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 AzureTemplateOptions osDiskStorageType(StorageAccountType osDiskStorageTy
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 StorageAccountType getOsDiskStorageType() {
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 void copyTo(TemplateOptions to) {
eTo.secrets(secrets);
eTo.customData(customData);
eTo.osDiskStorageType(osDiskStorageType);
eTo.planPublisher(planPublisher);
eTo.planName(planName);
eTo.planProduct(planProduct);
}
}

@@ -220,13 +253,16 @@ public boolean equals(Object o) {
&& 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 MoreObjects.ToStringHelper string() {
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 static AzureTemplateOptions osDiskStorageType(StorageAccountType osDiskSt
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);
}
}
}

0 comments on commit 261f9d1

Please sign in to comment.