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

Refactor vmware_preprovision_clone_to_template method for VM Provisioning. #645

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
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,115 @@
# 2. Target VC Folder
# 3. Tag Inheritance

set_folder = true
set_notes = true
set_tags = true

# Get provisioning object
prov = $evm.root["miq_provision"]

# Get Provision Type
prov_type = prov.provision_type
$evm.log("info", "Provision Type: <#{prov_type}>")

# Get template
template = prov.vm_template

# Get OS Type from the template platform
product = template.operating_system['product_name'] rescue ''
$evm.log("info", "Source Product: <#{product}>")

if set_notes
###################################
# Set the VM Description and VM Annotations as follows:
# The example would allow user input in provisioning dialog "vm_description"
# to be added to the VM notes
###################################
# Stamp VM with custom description
unless prov.get_option(:vm_description).nil?
vmdescription = prov.get_option(:vm_description)
prov.set_option(:vm_description, vmdescription)
$evm.log("info", "Provisioning object <:vmdescription> updated with <#{vmdescription}>")
end

# Setup VM Annotations
vm_notes = "Owner: #{prov.get_option(:owner_first_name)} #{prov.get_option(:owner_last_name)}"
vm_notes += "\nEmail: #{prov.get_option(:owner_email)}"
vm_notes += "\nSource Template: #{prov.vm_template.name}"
vm_notes += "\nCustom Description: #{vmdescription}" unless vmdescription.nil?
prov.set_vm_notes(vm_notes)
$evm.log("info", "Provisioning object <:vm_notes> updated with <#{vm_notes}>")
end
module ManageIQ
module Automate
module Infrastructure
module VM
module Provisioning
module StateMachines
module Methods
class VmwarePreprovisionCloneToTemplate
def initialize(handle = $evm)
@handle = handle
@folder = true
@notes = true
@tags = true
end

if set_folder
###################################
# Drop the VM in the targeted folder if no folder was chosen in the dialog
# The VC folder must exist for the VM to be placed correctly,
# Otherwise the VM will be placed at the Data Center level.
###################################
datacenter = template.v_owning_datacenter

if prov.get_option(:placement_folder_name).nil?
prov.set_folder(datacenter)
$evm.log("info", "Provisioning object <:placement_folder_name> updated with <#{prov.options[:placement_folder_name].inspect}>")
else
$evm.log("info", "Placing VM in folder: <#{prov.get_option(:placement_folder_name)}>")
end
end
def main
@handle.log("info", "Provision Type: <#{prov_type}>")
@handle.log("info", "Source Product: <#{product}>")

set_notes if @notes
set_folder if @folder
set_tags if @tags
end

private

def set_notes
vmdescription = prov.get_option(:vm_description)

# Setup VM Annotations
vm_notes = "Owner: #{prov.get_option(:owner_first_name)} #{prov.get_option(:owner_last_name)}"
vm_notes += "\nEmail: #{prov.get_option(:owner_email)}"
vm_notes += "\nSource Template: #{prov.vm_template.name}"
vm_notes += "\nCustom Description: #{vmdescription}" unless vmdescription.nil?
prov.set_vm_notes(vm_notes)
@handle.log("info", "Provisioning object <:vm_notes> updated with <#{vm_notes}>")
end

def set_folder
###################################
# Drop the VM in the targeted folder if no folder was chosen in the dialog
# The VC folder must exist for the VM to be placed correctly,
# Otherwise the VM will be placed at the Data Center level.
###################################
datacenter = template.v_owning_datacenter

if prov.get_option(:placement_folder_name).nil?
prov.set_folder(datacenter)
@handle.log("info", "Provisioning object <:placement_folder_name> updated with <#{prov.options[:placement_folder_name].inspect}>")
else
@handle.log("info", "Placing VM in folder: <#{prov.get_option(:placement_folder_name)}>")
end
end

if set_tags
###################################
#
# Inherit parent VM's tags and apply
# them to the published template
#
###################################

# List of tag categories to carry over
tag_categories_to_migrate = %w(environment department location function)

# Assign variables
prov_tags = prov.get_tags
$evm.log("info", "Inspecting Provisioning Tags: <#{prov_tags.inspect}>")
template_tags = template.tags
$evm.log("info", "Inspecting Template Tags: <#{template_tags.inspect}>")

# Loop through each source tag for matching categories
template_tags.each do |cat_tagname|
category, tag_value = cat_tagname.split('/')
$evm.log("info", "Processing Tag Category: <#{category}> Value: <#{tag_value}>")
next unless tag_categories_to_migrate.include?(category)
prov.add_tag(category, tag_value)
$evm.log("info", "Updating Provisioning Tags with Category: <#{category}> Value: <#{tag_value}>")
def set_tags
###################################
#
# Inherit parent VM's tags and apply
# them to the published template
#
###################################

# List of tag categories to carry over
tag_categories_to_migrate = %w[environment department location function]

# Assign variables
prov_tags = prov.get_tags
@handle.log("info", "Inspecting Provisioning Tags: <#{prov_tags.inspect}>")
template_tags = template.tags
@handle.log("info", "Inspecting Template Tags: <#{template_tags.inspect}>")

# Loop through each source tag for matching categories
template_tags.each do |cat_tagname|
category, tag_value = cat_tagname.split('/')
@handle.log("info", "Processing Tag Category: <#{category}> Value: <#{tag_value}>")
next unless tag_categories_to_migrate.include?(category)

prov.add_tag(category, tag_value)
@handle.log("info", "Updating Provisioning Tags with Category: <#{category}> Value: <#{tag_value}>")
end
end

def prov
@prov ||= @handle.root["miq_provision"].tap do |req|
raise 'miq_provision not specified' if req.nil?
end
end

def prov_type
@prov_type ||= prov.provision_type
end

def template
@template ||= prov.vm_template.tap do |req|
raise 'vm_template not specified' if req.nil?
end
end

def product
@product ||= template.operating_system&.product_name&.downcase
end
end
end
end
end
end
end
end
end

ManageIQ::Automate::Infrastructure::VM::Provisioning::StateMachines::Methods::VmwarePreprovisionCloneToTemplate.new.main
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require_domain_file

describe ManageIQ::Automate::Infrastructure::VM::Provisioning::StateMachines::Methods::VmwarePreprovisionCloneToTemplate do
let(:prov_type) { :miq_provision_redhat }
let(:ems) { FactoryBot.create(:ems_redhat_with_authentication) }
let(:os) { FactoryBot.create(:operating_system, :product_name => 'Fedora') }
let(:template) { FactoryBot.create(:miq_template, :ext_management_system => ems, :operating_system => os) }
let(:prov_req) { FactoryBot.create(:miq_provision_request, :options => prov_opt) }
let(:prov) { FactoryBot.create(prov_type, :miq_provision_request => prov_req, :options => prov_opt) }
let(:svc_prov) { MiqAeMethodService::MiqAeServiceMiqProvision.find(prov.id) }
let(:root_hash) { {'miq_provision' => svc_prov} }
let(:root_object) { Spec::Support::MiqAeMockObject.new(root_hash) }
let(:category) { FactoryBot.create(:classification_department_with_tags) }
let(:prov_opt) do
{
:src_vm_id => template.id,
:owner_first_name => 'owner_first_name',
:owner_last_name => 'owner_last_name',
:owner_email => 'owner_email@owner_email.com',
:vm_description => 'vm_description'
}
end
let(:ae_service) do
Spec::Support::MiqAeMockService.new(root_object).tap do |service|
current_object = Spec::Support::MiqAeMockObject.new
current_object.parent = root_object
service.object = current_object
end
end

def build_notes
res = "Owner: #{prov_opt[:owner_first_name]} #{prov_opt[:owner_last_name]}\n"\
"Email: #{prov_opt[:owner_email]}\n"\
"Source Template: #{template.name}"

if ae_service.root["miq_provision"].get_option(:vm_description)
res += "\nCustom Description: #{prov_opt[:vm_description]}"
end

res
end

def validate_notes
described_class.new(ae_service).instance_eval do
@set_notes = true
main
end

expect(ae_service.root["miq_provision"].get_option(:vm_notes)).to eq(build_notes)
end

it 'sets the notes with description' do
validate_notes
end

it 'sets the notes without description' do
prov_opt[:vm_description] = nil
validate_notes
end

it 'sets the folder' do
v_owning_datacenter = "v_owning_datacenter"
svc_template = MiqAeMethodService::MiqAeServiceMiqTemplate.find(template.id)
allow(ae_service.root["miq_provision"]).to receive(:vm_template).and_return(svc_template)
allow(svc_template).to receive(:v_owning_datacenter).and_return(v_owning_datacenter)
expect(ae_service.root["miq_provision"]).to receive(:set_folder).with(v_owning_datacenter)
described_class.new(ae_service).main
end

it 'skips folder set' do
prov_opt[:placement_folder_name] = 'placement_folder_name'
expect(ae_service.root["miq_provision"]).not_to receive(:set_folder)
described_class.new(ae_service).main
end

it 'sets the tags' do
tag = category.children.first
svc_template = MiqAeMethodService::MiqAeServiceMiqTemplate.find(template.id)
allow(ae_service.root["miq_provision"]).to receive(:vm_template).and_return(svc_template)
allow(svc_template).to receive(:tags).and_return(["#{category.name}/#{tag.name}"])

expect(ae_service.root["miq_provision"]).to receive(:add_tag).with(category.name, tag.name)
described_class.new(ae_service).main
end

it 'raises error for missing miq_provision' do
ae_service.root["miq_provision"] = nil
expect { described_class.new(ae_service).main }.to raise_error('miq_provision not specified')
end

it 'raises error for missing vm_template' do
allow(ae_service.root["miq_provision"]).to receive(:vm_template).and_return(nil)
expect { described_class.new(ae_service).main }.to raise_error('vm_template not specified')
end
end