Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for marketplace plan information #132

Merged
merged 2 commits into from
Apr 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@ info: vm image list command OK

* The optional ```vm_tags``` parameter allows you to define key:value pairs to tag VMs with on creation.

* The optional ```plan``` parameter allows you to define plan information when creating VMs from Marketplace images. Please refer to [Deploy an image with Marketplace terms](https://aka.ms/azuremarketplaceapideployment) for more details. Not all Marketplace images support programmatic deployment, and support is controlled by the image publisher.

* Managed disks are now enabled by default, to use the Storage account set ```use_managed_disks``` (default: true).

* The ```image_url``` (unmanaged disks only) parameter can be used to specify a custom vhd (This VHD must be in the same storage account as the disks of the VM, therefore ```existing_storage_account_blob_url``` must also be set and ```use_managed_disks``` must be set to false)
Expand Down
4 changes: 4 additions & 0 deletions kitchen-azurerm.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ Gem::Specification.new do |spec|
spec.add_dependency "azure_mgmt_resources", "~> 0.17", ">= 0.17.2"
spec.add_dependency "inifile", "~> 3.0", ">= 3.0.0"
spec.add_dependency "sshkey", ">= 1.0.0", "< 3"
spec.add_dependency "test-kitchen", ">= 1.20", "< 3.0"

spec.add_development_dependency "bundler"
spec.add_development_dependency "rake", ">= 11.0"
spec.add_development_dependency "chefstyle"
spec.add_development_dependency "rspec", "~> 3.5"
spec.add_development_dependency "rspec-mocks", "~> 3.5"
spec.add_development_dependency "rspec-expectations", "~> 3.5"
end
22 changes: 20 additions & 2 deletions lib/kitchen/driver/azurerm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Azurerm < Kitchen::Driver::Base
attr_accessor :resource_management_client
attr_accessor :network_management_client

kitchen_driver_api_version 2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mainly added this cause I saw across the board the primary drivers have this set. Willing to pull if this is a big deal.


default_config(:azure_resource_group_prefix) do |_config|
"kitchen-"
end
Expand Down Expand Up @@ -132,6 +134,10 @@ class Azurerm < Kitchen::Driver::Base
{}
end

default_config(:plan) do |_config|
{}
end

default_config(:vm_tags) do |_config|
{}
end
Expand Down Expand Up @@ -643,13 +649,25 @@ def windows_unattend_content

def virtual_machine_deployment_template
if config[:vnet_id] == ""
virtual_machine_deployment_template_file("public.erb", vm_tags: vm_tag_string(config[:vm_tags]), use_managed_disks: config[:use_managed_disks], image_url: config[:image_url], existing_storage_account_blob_url: config[:existing_storage_account_blob_url], image_id: config[:image_id], existing_storage_account_container: config[:existing_storage_account_container], custom_data: config[:custom_data], os_disk_size_gb: config[:os_disk_size_gb], data_disks_for_vm_json: data_disks_for_vm_json, use_ephemeral_osdisk: config[:use_ephemeral_osdisk], ssh_key: instance.transport[:ssh_key])
virtual_machine_deployment_template_file("public.erb", vm_tags: vm_tag_string(config[:vm_tags]), use_managed_disks: config[:use_managed_disks], image_url: config[:image_url], existing_storage_account_blob_url: config[:existing_storage_account_blob_url], image_id: config[:image_id], existing_storage_account_container: config[:existing_storage_account_container], custom_data: config[:custom_data], os_disk_size_gb: config[:os_disk_size_gb], data_disks_for_vm_json: data_disks_for_vm_json, use_ephemeral_osdisk: config[:use_ephemeral_osdisk], ssh_key: instance.transport[:ssh_key], plan_json: plan_json)
else
info "Using custom vnet: #{config[:vnet_id]}"
virtual_machine_deployment_template_file("internal.erb", vnet_id: config[:vnet_id], subnet_id: config[:subnet_id], public_ip: config[:public_ip], vm_tags: vm_tag_string(config[:vm_tags]), use_managed_disks: config[:use_managed_disks], image_url: config[:image_url], existing_storage_account_blob_url: config[:existing_storage_account_blob_url], image_id: config[:image_id], existing_storage_account_container: config[:existing_storage_account_container], custom_data: config[:custom_data], os_disk_size_gb: config[:os_disk_size_gb], data_disks_for_vm_json: data_disks_for_vm_json, use_ephemeral_osdisk: config[:use_ephemeral_osdisk], ssh_key: instance.transport[:ssh_key])
virtual_machine_deployment_template_file("internal.erb", vnet_id: config[:vnet_id], subnet_id: config[:subnet_id], public_ip: config[:public_ip], vm_tags: vm_tag_string(config[:vm_tags]), use_managed_disks: config[:use_managed_disks], image_url: config[:image_url], existing_storage_account_blob_url: config[:existing_storage_account_blob_url], image_id: config[:image_id], existing_storage_account_container: config[:existing_storage_account_container], custom_data: config[:custom_data], os_disk_size_gb: config[:os_disk_size_gb], data_disks_for_vm_json: data_disks_for_vm_json, use_ephemeral_osdisk: config[:use_ephemeral_osdisk], ssh_key: instance.transport[:ssh_key], plan_json: plan_json)
end
end

def plan_json
return nil if config[:plan].empty?

plan = {}
plan["name"] = config[:plan][:name] if config[:plan][:name]
plan["product"] = config[:plan][:product] if config[:plan][:product]
plan["promotionCode"] = config[:plan][:promotion_code] if config[:plan][:promotion_code]
plan["publisher"] = config[:plan][:publisher] if config[:plan][:publisher]

plan.to_json
end

def virtual_machine_deployment_template_file(template_file, data = {})
template = File.read(File.expand_path(File.join(__dir__, "../../../templates", template_file)))
render_binding = OpenStruct.new(data)
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative "../lib/kitchen/driver/azurerm"
119 changes: 119 additions & 0 deletions spec/unit/kitchen/driver/azurerm_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
require "spec_helper"
require "kitchen/transport/dummy"

describe Kitchen::Driver::Azurerm do
let(:logged_output) { StringIO.new }
let(:logger) { Logger.new(logged_output) }
let(:platform) { Kitchen::Platform.new(name: "fake_platform") }
let(:transport) { Kitchen::Transport::Dummy.new }
let(:driver) { described_class.new(config) }

let(:subscription_id) { "115b12cb-b0d3-4ed9-94db-f73733be6f3c" }
let(:location) { "eastus2" }
let(:machine_size) { "Standard_D4_v3" }
let(:vm_tags) do
{
os_type: "linux",
distro: "redhat",
}
end

let(:image_urn) { "RedHat:rhel-byos:rhel-raw76:7.6.20190620" }
let(:vm_name) { "my-awesome-vm" }

let(:config) do
{
subscription_id: subscription_id,
location: location,
machine_size: machine_size,
vm_tags: vm_tags,
image_urn: image_urn,
vm_name: vm_name,
}
end

let(:instance) do
instance_double(Kitchen::Instance,
logger: logger,
transport: transport,
platform: platform,
to_str: "instance_str")
end

before do
allow(driver).to receive(:instance).and_return(instance)
end

it "driver API version is 2" do
expect(driver.diagnose_plugin[:api_version]).to eq(2)
end

describe "#name" do
it "has an overridden name" do
expect(driver.name).to eq("Azurerm")
end
end

describe "#create" do
end

describe "#virtual_machine_deployment_template" do
subject { driver.send(:virtual_machine_deployment_template) }

let(:parsed_json) { JSON.parse(subject) }
let(:vm_resource) { parsed_json["resources"].find { |x| x["type"] == "Microsoft.Compute/virtualMachines" } }

context "when plan config is provided" do
let(:plan_name) { "plan-abc" }
let(:plan_product) { "my-product" }
let(:plan_publisher) { "captain-america" }
let(:plan_promotion_code) { "50-percent-off" }

let(:plan) do
{
name: plan_name,
product: plan_product,
publisher: plan_publisher,
promotion_code: plan_promotion_code,
}
end

let(:config) do
{
subscription_id: subscription_id,
location: location,
machine_size: machine_size,
vm_tags: vm_tags,
plan: plan,
image_urn: image_urn,
vm_name: vm_name,
}
end

it "includes plan information in deployment template" do
expect(vm_resource).to have_key("plan")
expect(vm_resource["plan"]["name"]).to eq(plan_name)
expect(vm_resource["plan"]["product"]).to eq(plan_product)
expect(vm_resource["plan"]["publisher"]).to eq(plan_publisher)
expect(vm_resource["plan"]["promotionCode"]).to eq(plan_promotion_code)
end
end

context "when plan config is not provided" do
let(:config) do
{
subscription_id: subscription_id,
location: location,
machine_size: machine_size,
vm_tags: vm_tags,
image_urn: image_urn,
vm_name: vm_name,
}
end

it "does not include plan information in deployment template" do
expect(vm_resource).not_to have_key("plan")
end
end
end
end
3 changes: 3 additions & 0 deletions templates/internal.erb
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@
<%- end -%>
}
},
<%- unless plan_json.nil? -%>
"plan": <%= plan_json %>,
<%- end -%>
"identity": {
"type": "[variables('vmIdentityType')]",
"identityIds": "[if(empty(parameters('userAssignedIdentities')), json('null'), parameters('userAssignedIdentities'))]"
Expand Down
3 changes: 3 additions & 0 deletions templates/public.erb
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@
<%- end -%>
}
},
<%- unless plan_json.nil? -%>
"plan": <%= plan_json %>,
<%- end -%>
"identity": {
"type": "[variables('vmIdentityType')]",
"identityIds": "[if(empty(parameters('userAssignedIdentities')), json('null'), parameters('userAssignedIdentities'))]"
Expand Down