From c4724d7d9f62828f3947f6a9f0ffb318a84baf4f Mon Sep 17 00:00:00 2001 From: Andrew Becker Date: Tue, 2 Jul 2019 10:29:32 -0400 Subject: [PATCH] Allow location-dependent values to be set from custom_provision_task_options (#154) * Adding methods to core.rb + Adding support for service template provisioning tasks in get_vm_and_options + Adding method skip_to_state + Adding method for managing tags * Allow location details to be set in custom provision options + Set networks, domain, etc in set_custom_provision_task_options + Classify this method + Use RHC StdLib * Setting debug to false --- .../__methods__/create_provision_requests.rb | 467 +++++++++--------- .../create_provision_requests.yaml | 2 + .../StdLib/Core.class/__methods__/core.rb | 183 +++++-- 3 files changed, 376 insertions(+), 276 deletions(-) diff --git a/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.rb b/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.rb index 4894439..69e081c 100644 --- a/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.rb +++ b/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.rb @@ -4,244 +4,249 @@ # @param parsed_dialog_tags String (YAML) Parsed dialog tags # @param custom_vm_fields Hash Additional custom VM fields. See $evm.execute('create_provision_request') # @param custom_additional_values Hash Additional custom additional (ws) fields. See $evm.execute('create_provision_request') -@DEBUG = false -def dump_object(object_string, object) - $evm.log("info", "Listing #{object_string} Attributes:") - object.attributes.sort.each { |k, v| $evm.log("info", "\t#{k}: #{v}") } - $evm.log("info", "===========================================") -end +module RedHatConsulting_Utilities + module Service + module Provisioning + module StateMachines + module Methods + class CreateProvisionRequests -def dump_current - $evm.log("info", "Listing Current Object Attributes:") - $evm.current.attributes.sort.each { |k, v| $evm.log("info", "\t#{k}: #{v}") } - $evm.log("info", "===========================================") -end + include RedHatConsulting_Utilities::StdLib::Core -def dump_root - $evm.log("info", "Listing Root Object Attributes:") - $evm.root.attributes.sort.each { |k, v| $evm.log("info", "\t#{k}: #{v}") } - $evm.log("info", "===========================================") -end + def initialize(handle = $evm) + @handle = handle + @DEBUG = false + end -def error(msg) - $evm.root['ae_result'] = 'error' - $evm.root['ae_reason'] = msg - $evm.log(:error, msg) - exit MIQ_OK -end + def main + begin + dump_root() if @DEBUG -def yaml_data(task, option) - task.get_option(option).nil? ? nil : YAML.load(task.get_option(option)) -end + # get options and tags + @handle.log(:info, "$evm.root['vmdb_object_type'] => '#{@handle.root['vmdb_object_type']}'.") if @DEBUG + case @handle.root['vmdb_object_type'] + when 'service_template_provision_task' + task = @handle.root['service_template_provision_task'] -# Creates provision requests based on the givin parameters. -# -# @param task ServiceTemplateProvisionTask Task used to create the service that will own the VMs created by these provision request(s) -# @param requester User User requesting the new VMs -# @param number_of_vms Integer Number of VMs to provision -# @param provisioning_network_name_pattern String Provisioning network name pattern -# @param template_fields Hash Hash describing the template to use. -# Must contain :name and :guid fields. -# @param dialog_options Hash User set options via dialog -# @param tags Hash Tags to set on the created VMs. -# Default {} -# @param custom_vm_fields Hash Custom vm_fields to use when creating the provsion request(s) -# Default {} -# @param custom_additional_values Hash Custom additional_values (ws_values) to use when creating the provsion request(s) -# Default {} -# @param create_seperate_requests Hash True to create seperate requests for each VM. -# False to create one request that will create all of the requested VM(s) -# Default true -# -# @return Array all of the created requests -def create_provision_requests(task, requester, number_of_vms, - provisioning_network_name_pattern, - template_fields, dialog_options, - tags = {}, custom_vm_fields = {}, custom_additional_values = {}, create_seperate_requests = true) - $evm.log(:info, "START: create_provision_requests") if @DEBUG - $evm.log(:info, "number_of_vms => #{number_of_vms}") if @DEBUG - $evm.log(:info, "provisioning_network_name_pattern => #{provisioning_network_name_pattern}") if @DEBUG - $evm.log(:info, "template_fields => #{template_fields}") if @DEBUG - $evm.log(:info, "dialog_options => #{dialog_options}") if @DEBUG - $evm.log(:info, "tags => #{tags}") if @DEBUG - $evm.log(:info, "custom_additional_values => #{custom_additional_values}") if @DEBUG - $evm.log(:info, "custom_vm_fields => #{custom_vm_fields}") if @DEBUG - $evm.log(:info, "create_seperate_requests => #{create_seperate_requests}") if @DEBUG - - # determine number of vms to create and - # how many provisioning requests to create and - # how many VMs per provisioning request - if create_seperate_requests - number_of_requests = number_of_vms - number_of_vms_per_request = 1 - else - number_of_requests = 1 - number_of_vms_per_request = number_of_vms - end - - # === START: template_fields - template_fields[:request_type] = 'template' - # === END: template_fields - - # === START: vm_fields - vm_fields = {} - - # determine if auto placement or not - # NOTE: this used to be determined based on if the network was a cloud network or not, - # but now network is determined after placement, so need to cirlce back here and - # figure out new way to do cloud stuff. - # This current setting will likely break using this code with cloud right now - vm_fields[:placement_auto] = true - - # TODO: used to set placement_availability_zone based on the selected network if cloud, but now network doesnt get set to later, so need way to figure out AZ, or do that automatically in determine placement - - vm_fields.merge!(custom_vm_fields) - vm_fields.merge!(dialog_options) - - # override number of vms - vm_fields[:number_of_vms] = number_of_vms_per_request - - # ensure option values are of correct type - vm_fields[:vm_memory] = vm_fields[:vm_memory].to_s if !vm_fields[:vm_memory].nil? - # === END: vm_fields - - # === START: requester - requester = { - :user_name => requester.userid, # need this otherwise requestor will always be 'admin' - :owner_email => requester.email, - :owner_first_name => requester.first_name, - :owner_last_name => requester.last_name - } - # === END: requester - - # === START: additional_values (AKA: ws_values) - additional_values = { - :service_id => task.destination.id, - :provisioning_network_name_pattern => provisioning_network_name_pattern - } - additional_values.merge!(custom_additional_values) - additional_values.merge!(dialog_options) - - # override number of vms - additional_values[:number_of_vms] = number_of_vms_per_request - # === END: additional_values (AKA: ws_values) - - # Setup the parameters needed for request - build_request = { - :version => '1.1', - :template_fields => template_fields, - :vm_fields => vm_fields, - :requester => requester, - :tags => tags, - :additional_values => additional_values, - :ems_custom_attrs => {}, - :miq_custom_attrs => {} - } - - # Create the actual provision request(s) - $evm.log(:info, "Execute '#{number_of_requests}' create_provision_requests for '#{number_of_vms_per_request}' VMs each: #{build_request}") - requests = [] - number_of_requests.times do |count| - requests << $evm.execute( - 'create_provision_request', - build_request[:version], - build_request[:template_fields].stringify_keys, - build_request[:vm_fields].stringify_keys, - build_request[:requester].stringify_keys, - build_request[:tags].stringify_keys, - build_request[:additional_values].stringify_keys, - build_request[:ems_custom_attrs].stringify_keys, - build_request[:miq_custom_attrs].stringify_keys) + dialog_options = get_task_option_yaml_data(task, :parsed_dialog_options) + dialog_options = dialog_options[0] if !dialog_options[0].nil? + dialog_tags = get_task_option_yaml_data(task, :parsed_dialog_tags) + custom_vm_fields = task.get_option(:custom_vm_fields) + custom_additional_values = task.get_option(:custom_additional_values) + else + error("Can not handle vmdb_object_type: #{@handle.root['vmdb_object_type']}") + end + @handle.log(:info, "dialog_options => #{dialog_options}") if @DEBUG + @handle.log(:info, "dialog_tags => #{dialog_tags}") if @DEBUG + @handle.log(:info, "custom_vm_fields => #{custom_vm_fields}") if @DEBUG + @handle.log(:info, "custom_additional_values => #{custom_additional_values}") if @DEBUG + + # determine requestor + user = @handle.root['user'] + dump_root_attribute('user') if @DEBUG + + # get the templates + templates = YAML.load(dialog_options[:templates]) if dialog_options[:templates] + templates ||= YAML.load(custom_additional_values[:templates]) if custom_additional_values[:templates] + error("Selected templates must be specified") if templates.blank? + @handle.log(:info, "templates => #{templates}") if @DEBUG + + # get the number of VMs + number_of_vms = dialog_options[:number_of_vms] || custom_vm_fields[:number_of_vms] || custom_additional_values[:number_of_vms] || 1 + @handle.log(:info, "number_of_vms => #{number_of_vms}") if @DEBUG + + # Create new provision request(s) based on the number of requested VM(s) and the number of template(s) + new_provision_requests = [] + base_vms_per_template = number_of_vms / templates.length + templates.each_with_index do |template_fields, index| + number_of_vms_for_this_template = base_vms_per_template + number_of_vms_for_this_template += 1 if index < number_of_vms % templates.length + + # set custom additional values + destination_network_name = dialog_options["location_#{index}_destination_network".to_sym] + destination_network_name ||= custom_additional_values["location_#{index}_destination_network".to_sym] + destination_network_gateway = dialog_options["location_#{index}_destination_network_gateway".to_sym] + destination_network_gateway ||= custom_additional_values["location_#{index}_destination_network_gateway".to_sym] + domain_name = dialog_options["location_#{index}_domain_name".to_sym] + domain_name ||= custom_additional_values["location_#{index}_domain_name".to_sym] + custom_additional_values[:destination_network] = destination_network_name + custom_additional_values[:destination_network_gateway] = destination_network_gateway + custom_additional_values[:domain_name] = domain_name + + # handle cloud provider specific options + cloud_flavor_id = dialog_options["location_#{index}_cloud_flavor".to_sym] + cloud_flavor_id ||= custom_additional_values["location_#{index}_cloud_flavor".to_sym] + cloud_ssh_key_id = dialog_options["location_#{index}_cloud_ssh_key".to_sym] + cloud_ssh_key_id ||= custom_additional_values["location_#{index}_cloud_ssh_key".to_sym] + custom_vm_fields[:instance_type] = cloud_flavor_id if !cloud_flavor_id.blank? + custom_vm_fields[:guest_access_key_pair] = cloud_ssh_key_id if !cloud_ssh_key_id.blank? + # TODO: figure out these parameters + #custom_vm_fields[:security_groups] = ??? + + # create provision requests + provisioning_network_name_pattern = dialog_options["location_#{index}_provisioning_network".to_sym] + provisioning_network_name_pattern ||= custom_additional_values["location_#{index}_provisioning_network".to_sym] + @handle.log(:info, "dialog_options => #{dialog_options}") if @DEBUG + @handle.log(:info, "dialog_tags => #{dialog_tags}") if @DEBUG + @handle.log(:info, "custom_vm_fields => #{custom_vm_fields}") if @DEBUG + @handle.log(:info, "custom_additional_values => #{custom_additional_values}") if @DEBUG + new_provision_requests |= create_provision_requests( + task, + user, + number_of_vms_for_this_template, + provisioning_network_name_pattern, + template_fields, + dialog_options, + dialog_tags, + custom_vm_fields, + custom_additional_values) + end + + # set requests on task so service task can wait for them to finish later in state machine + provision_request_ids = task.get_option(:provision_request_ids) || {} + provision_request_ids = provision_request_ids.values + new_provision_requests.each do |provision_request| + provision_request_ids << provision_request.id + end + provision_request_ids_hash = {} + provision_request_ids.each_with_index { |id, index| provision_request_ids_hash[index] = id } + task.set_option(:provision_request_ids, provision_request_ids_hash) + @handle.log(:info, "task.get_option(:provision_request_ids) => #{task.get_option(:provision_request_ids)}") if @DEBUG + end + end + + # Creates provision requests based on the givin parameters. + # + # @param task ServiceTemplateProvisionTask Task used to create the service that will own the VMs created by these provision request(s) + # @param requester User User requesting the new VMs + # @param number_of_vms Integer Number of VMs to provision + # @param provisioning_network_name_pattern String Provisioning network name pattern + # @param template_fields Hash Hash describing the template to use. + # Must contain :name and :guid fields. + # @param dialog_options Hash User set options via dialog + # @param tags Hash Tags to set on the created VMs. + # Default {} + # @param custom_vm_fields Hash Custom vm_fields to use when creating the provsion request(s) + # Default {} + # @param custom_additional_values Hash Custom additional_values (ws_values) to use when creating the provsion request(s) + # Default {} + # @param create_seperate_requests Hash True to create seperate requests for each VM. + # False to create one request that will create all of the requested VM(s) + # Default true + # + # @return Array all of the created requests + def create_provision_requests(task, requester, number_of_vms, + provisioning_network_name_pattern, + template_fields, dialog_options, + tags = {}, custom_vm_fields = {}, custom_additional_values = {}, create_seperate_requests = true) + @handle.log(:info, "START: create_provision_requests") if @DEBUG + @handle.log(:info, "number_of_vms => #{number_of_vms}") if @DEBUG + @handle.log(:info, "provisioning_network_name_pattern => #{provisioning_network_name_pattern}") if @DEBUG + @handle.log(:info, "template_fields => #{template_fields}") if @DEBUG + @handle.log(:info, "dialog_options => #{dialog_options}") if @DEBUG + @handle.log(:info, "tags => #{tags}") if @DEBUG + @handle.log(:info, "custom_additional_values => #{custom_additional_values}") if @DEBUG + @handle.log(:info, "custom_vm_fields => #{custom_vm_fields}") if @DEBUG + @handle.log(:info, "create_seperate_requests => #{create_seperate_requests}") if @DEBUG + + # determine number of vms to create and + # how many provisioning requests to create and + # how many VMs per provisioning request + if create_seperate_requests + number_of_requests = number_of_vms + number_of_vms_per_request = 1 + else + number_of_requests = 1 + number_of_vms_per_request = number_of_vms + end + + # === START: template_fields + template_fields[:request_type] = 'template' + # === END: template_fields + + # === START: vm_fields + vm_fields = {} + + # determine if auto placement or not + # NOTE: this used to be determined based on if the network was a cloud network or not, + # but now network is determined after placement, so need to cirlce back here and + # figure out new way to do cloud stuff. + # This current setting will likely break using this code with cloud right now + vm_fields[:placement_auto] = true + + # TODO: used to set placement_availability_zone based on the selected network if cloud, but now network doesnt get set to later, so need way to figure out AZ, or do that automatically in determine placement + + vm_fields.merge!(custom_vm_fields) + vm_fields.merge!(dialog_options) + + # override number of vms + vm_fields[:number_of_vms] = number_of_vms_per_request + + # ensure option values are of correct type + vm_fields[:vm_memory] = vm_fields[:vm_memory].to_s if !vm_fields[:vm_memory].nil? + # === END: vm_fields + + # === START: requester + requester = { + :user_name => requester.userid, # need this otherwise requestor will always be 'admin' + :owner_email => requester.email, + :owner_first_name => requester.first_name, + :owner_last_name => requester.last_name + } + # === END: requester + + # === START: additional_values (AKA: ws_values) + additional_values = { + :service_id => task.destination.id, + :provisioning_network_name_pattern => provisioning_network_name_pattern + } + additional_values.merge!(custom_additional_values) + additional_values.merge!(dialog_options) + + # override number of vms + additional_values[:number_of_vms] = number_of_vms_per_request + # === END: additional_values (AKA: ws_values) + + # Setup the parameters needed for request + build_request = { + :version => '1.1', + :template_fields => template_fields, + :vm_fields => vm_fields, + :requester => requester, + :tags => tags, + :additional_values => additional_values, + :ems_custom_attrs => {}, + :miq_custom_attrs => {} + } + + # Create the actual provision request(s) + @handle.log(:info, "Execute '#{number_of_requests}' create_provision_requests for '#{number_of_vms_per_request}' VMs each: #{build_request}") + requests = [] + number_of_requests.times do |count| + requests << @handle.execute( + 'create_provision_request', + build_request[:version], + build_request[:template_fields].stringify_keys, + build_request[:vm_fields].stringify_keys, + build_request[:requester].stringify_keys, + build_request[:tags].stringify_keys, + build_request[:additional_values].stringify_keys, + build_request[:ems_custom_attrs].stringify_keys, + build_request[:miq_custom_attrs].stringify_keys) + end + @handle.log(:info, "requests => #{requests}") if @DEBUG + @handle.log(:info, "END: create_provision_requests") if @DEBUG + return requests + end + + end + end + end + end end - $evm.log(:info, "requests => #{requests}") if @DEBUG - - $evm.log(:info, "END: create_provision_requests") if @DEBUG - return requests end -begin - dump_current() if @DEBUG - dump_root() if @DEBUG - - # get options and tags - $evm.log(:info, "$evm.root['vmdb_object_type'] => '#{$evm.root['vmdb_object_type']}'.") if @DEBUG - case $evm.root['vmdb_object_type'] - when 'service_template_provision_task' - task = $evm.root['service_template_provision_task'] - dump_object("service_template_provision_task", task) if @DEBUG - - dialog_options = yaml_data(task, :parsed_dialog_options) - dialog_options = dialog_options[0] if !dialog_options[0].nil? - dialog_tags = yaml_data(task, :parsed_dialog_tags) - custom_vm_fields = task.get_option(:custom_vm_fields) - custom_additional_values = task.get_option(:custom_additional_values) - else - error("Can not handle vmdb_object_type: #{$evm.root['vmdb_object_type']}") - end - $evm.log(:info, "dialog_options => #{dialog_options}") if @DEBUG - $evm.log(:info, "dialog_tags => #{dialog_tags}") if @DEBUG - $evm.log(:info, "custom_vm_fields => #{custom_vm_fields}") if @DEBUG - $evm.log(:info, "custom_additional_values => #{custom_additional_values}") if @DEBUG - - # determine requestor - user = $evm.root['user'] - dump_object("Current User", user) if @DEBUG - - # get the templates - templates = YAML.load(dialog_options[:templates]) if dialog_options[:templates] - error("Selected templates must be specified") if templates.blank? - $evm.log(:info, "templates => #{templates}") if @DEBUG - - # get the number of VMs - number_of_vms = dialog_options[:number_of_vms] || custom_vm_fields[:number_of_vms] || custom_additional_values[:number_of_vms] || 1 - $evm.log(:info, "umber_of_vms => #{number_of_vms}") if @DEBUG - - # Create new provision request(s) based on the number of requested VM(s) and the number of template(s) - new_provision_requests = [] - base_vms_per_template = number_of_vms / templates.length - templates.each_with_index do |template_fields, index| - number_of_vms_for_this_template = base_vms_per_template - number_of_vms_for_this_template += 1 if index < number_of_vms % templates.length - - # set custom additional values - destination_network_name = dialog_options["location_#{index}_destination_network".to_sym] - destination_network_gateway = dialog_options["location_#{index}_destination_network_gateway".to_sym] - domain_name = dialog_options["location_#{index}_domain_name".to_sym] - custom_additional_values[:destination_network] = destination_network_name - custom_additional_values[:destination_network_gateway] = destination_network_gateway - custom_additional_values[:domain_name] = domain_name - - # handle cloud provider specific options - cloud_flavor_id = dialog_options["location_#{index}_cloud_flavor".to_sym] - cloud_ssh_key_id = dialog_options["location_#{index}_cloud_ssh_key".to_sym] - custom_vm_fields[:instance_type] = cloud_flavor_id if !cloud_flavor_id.blank? - custom_vm_fields[:guest_access_key_pair] = cloud_ssh_key_id if !cloud_ssh_key_id.blank? - # TODO: figure out these parameters - #custom_vm_fields[:security_groups] = ??? - - # create provision requests - provisioning_network_name_pattern = dialog_options["location_#{index}_provisioning_network".to_sym] - new_provision_requests |= create_provision_requests( - task, - user, - number_of_vms_for_this_template, - provisioning_network_name_pattern, - template_fields, - dialog_options, - dialog_tags, - custom_vm_fields, - custom_additional_values) - end - - # set requests on task so service task can wait for them to finish later in state machine - provision_request_ids = task.get_option(:provision_request_ids) || {} - provision_request_ids = provision_request_ids.values - new_provision_requests.each do |provision_request| - provision_request_ids << provision_request.id - end - provision_request_ids_hash = {} - provision_request_ids.each_with_index { |id, index| provision_request_ids_hash[index] = id } - task.set_option(:provision_request_ids, provision_request_ids_hash) - $evm.log(:info, "task.get_option(:provision_request_ids) => #{task.get_option(:provision_request_ids)}") if @DEBUG +if __FILE__ == $PROGRAM_NAME + RedHatConsulting_Utilities::Service::Provisioning::StateMachines::Methods::CreateProvisionRequests.new.main() end diff --git a/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.yaml b/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.yaml index c1a206a..93eea53 100644 --- a/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.yaml +++ b/Automate/RedHatConsulting_Utilities/Service/Provisioning/StateMachines/Methods.class/__methods__/create_provision_requests.yaml @@ -9,5 +9,7 @@ object: scope: instance language: ruby location: inline + embedded_methods: + - "/StdLib/Core/Core" options: {} inputs: [] diff --git a/Automate/RedHatConsulting_Utilities/StdLib/Core.class/__methods__/core.rb b/Automate/RedHatConsulting_Utilities/StdLib/Core.class/__methods__/core.rb index e58c688..00c5394 100644 --- a/Automate/RedHatConsulting_Utilities/StdLib/Core.class/__methods__/core.rb +++ b/Automate/RedHatConsulting_Utilities/StdLib/Core.class/__methods__/core.rb @@ -87,6 +87,10 @@ def set_complex_state_var(name, value) def get_complex_state_var(name) JSON.parse(@handle.get_state_var(name.to_sym)) end + + def get_task_option_yaml_data(task, option) + task.get_option(option).nil? ? nil : YAML.load(task.get_option(option)) + end # Useful in the rescue of service provisioning methods. # rescue => err @@ -211,14 +215,25 @@ def object_eligible?(obj) # @param seconds Number of seconds to wait before next retry # @param reason Reason for the retry def automate_retry(seconds, reason) - $evm.root['ae_result'] = 'retry' - $evm.root['ae_retry_interval'] = "#{seconds.to_i}.seconds" - $evm.root['ae_reason'] = reason + @handle.root['ae_result'] = 'retry' + @handle.root['ae_retry_interval'] = "#{seconds.to_i}.seconds" + @handle.root['ae_reason'] = reason - $evm.log(:info, "Retrying #{@method} after #{seconds} seconds, because '#{reason}'") if @DEBUG + @handle.log(:info, "Retrying #{@method} after #{seconds} seconds, because '#{reason}'") if @DEBUG exit MIQ_OK end + # Set attributes to skip to specified next state + # + # @param message Reason for the skip + # @param next_state State to skip to + def skip_to_state(message, next_state) + log(:info, "#{message}. Skip to State <#{next_state}>") + @handle.root['ae_result'] = 'skip' + @handle.root['ae_next_state'] = next_state + exit MIQ_OK + end + # Function for getting the current VM and associated options based on the vmdb_object_type. # # Supported vmdb_object_types @@ -230,51 +245,129 @@ def automate_retry(seconds, reason) def get_vm_and_options() @handle.log(:info, "@handle.root['vmdb_object_type'] => '#{@handle.root['vmdb_object_type']}'.") case @handle.root['vmdb_object_type'] - when 'miq_provision' - # get root object - miq_provision = @handle.root['miq_provision'] - - # get VM - vm = miq_provision.vm - - # get options - options = miq_provision.options - #merge the ws_values, dialog, top level options into one list to make it easier to search - options = options.merge(options[:ws_values]) if options[:ws_values] - options = options.merge(options[:dialog]) if options[:dialog] - when 'vm' - # get root objet & VM - vm = get_param(:vm) - - # get options - options = @handle.root.attributes - #merge the ws_values, dialog, top level options into one list to make it easier to search - options = options.merge(options[:ws_values]) if options[:ws_values] - options = options.merge(options[:dialog]) if options[:dialog] - when 'automation_task' - # get root objet - automation_task = @handle.root['automation_task'] - - # get VM - vm = get_param(:vm) - - # get options - options = get_param(:options) - options = JSON.load(options) if options && options.class == String - options = options.symbolize_keys if options - #merge the ws_values, dialog, top level options into one list to make it easier to search - options = options.merge(options[:ws_values]) if options[:ws_values] - options = options.merge(options[:dialog]) if options[:dialog] - else - error("Can not handle vmdb_object_type: #{@handle.root['vmdb_object_type']}") - end + when 'miq_provision' + # get root object + miq_provision = @handle.root['miq_provision'] + + # get VM + vm = miq_provision.vm + + # get options + options = miq_provision.options + #merge the ws_values, dialog, top level options into one list to make it easier to search + options = options.merge(options[:ws_values]) if options[:ws_values] + options = options.merge(options[:dialog]) if options[:dialog] + when 'vm' + # get root objet & VM + vm = get_param(:vm) + + # get options + options = @handle.root.attributes + #merge the ws_values, dialog, top level options into one list to make it easier to search + options = options.merge(options[:ws_values]) if options[:ws_values] + options = options.merge(options[:dialog]) if options[:dialog] + when 'automation_task' + # get root objet + automation_task = @handle.root['automation_task'] + + # get VM + vm = get_param(:vm) + + # get options + options = get_param(:options) + options = JSON.load(options) if options && options.class == String + options = options.symbolize_keys if options + #merge the ws_values, dialog, top level options into one list to make it easier to search + options = options.merge(options[:ws_values]) if options[:ws_values] + options = options.merge(options[:dialog]) if options[:dialog] + when 'service_template_provision_task' + task = @handle.root['service_template_provision_task'] + + # if service task then no VM yet + vm = nil + + # get options + options = get_task_option_yaml_data(task, :parsed_dialog_options) + options = options[0] if !options[0].nil? + else + error("Can not handle vmdb_object_type: #{@handle.root['vmdb_object_type']}") + end + + # standerdize the option keys + options = options.symbolize_keys() + + return vm,options + end + + # Create a Tag Category if it does not already exist + # + # @param category Tag Category to create + # @param description Tag Category description. + # Optional + # Defaults to the `category` + # @param single_value True if a resource can only have one tag from this category, + # False if a resource can have multiple tags from this category. + # Optional. + # Defaults to `false` + # + # @source https://pemcg.gitbooks.io/mastering-automation-in-cloudforms-4-2-and-manage/content/using_tags_from_automate/chapter.html + def create_tag_category(category, description = nil, single_value = false) + category_name = to_tag_name(category) + unless @handle.execute('category_exists?', category_name) + @handle.execute('category_create', + :name => category_name, + :single_value => single_value, + :perf_by_tag => false, + :description => description || category) + end + end + + # Gets all of the Tags in a given Tag Category + # + # @param category Tag Category to get all of the Tags for + # + # @return Hash of Tag names mapped to Tag descriptions + # + # @source https://pemcg.gitbooks.io/mastering-automation-in-cloudforms-4-2-and-manage/content/using_tags_from_automate/chapter.html#_getting_the_list_of_tags_in_a_category + def get_category_tags(category) + classification = @handle.vmdb(:classification).find_by_name(category) + tags = {} + @handle.vmdb(:classification).where(:parent_id => classification.id).each do |tag| + tags[tag.name] = tag.description + end + + return tags + end - # standerdize the option keys - options = options.symbolize_keys() - return vm,options + # Create a Tag in a given Category if it does not already exist + # + # @param category Tag Category to create the Tag in + # @param tag Tag to create in the given Tag Category + # + # @source https://pemcg.gitbooks.io/mastering-automation-in-cloudforms-4-2-and-manage/content/using_tags_from_automate/chapter.html + def create_tag(category, tag) + create_tag_category(category) + tag_name = to_tag_name(tag) + unless @handle.execute('tag_exists?', category, tag_name) + @handle.execute('tag_create', + category, + :name => tag_name, + :description => tag) end + return "#{category}/#{tag_name}" + end + + # Takes a string and makes it a valid tag name + # + # @param str String to turn into a valid Tag name + # + # @return Given string transformed into a valid Tag name + def to_tag_name(str) + return str.downcase.gsub(/[^a-z0-9_]+/,'_') + end + end end end