diff --git a/app/models/manageiq/providers/automation_manager/provision.rb b/app/models/manageiq/providers/automation_manager/provision.rb new file mode 100644 index 00000000000..e0e32175869 --- /dev/null +++ b/app/models/manageiq/providers/automation_manager/provision.rb @@ -0,0 +1,13 @@ +class ManageIQ::Providers::AutomationManager::Provision < MiqProvisionTask + def self.request_class + MiqProvisionConfigurationScriptRequest + end + + def my_role(*) + "ems_operations" + end + + def my_queue_name + source.manager&.queue_name_for_ems_operations + end +end diff --git a/app/models/manageiq/providers/automation_manager/provision_workflow.rb b/app/models/manageiq/providers/automation_manager/provision_workflow.rb new file mode 100644 index 00000000000..ac9d7815e82 --- /dev/null +++ b/app/models/manageiq/providers/automation_manager/provision_workflow.rb @@ -0,0 +1,6 @@ +class ManageIQ::Providers::AutomationManager::ProvisionWorkflow < MiqProvisionConfigurationScriptWorkflow + def dialog_name_from_automate(message = 'get_dialog_name', extra_attrs = {}) + extra_attrs['platform_category'] ||= 'automation_manager' + super(message, %i[request_type], extra_attrs) + end +end diff --git a/app/models/miq_provision_configuration_script_request.rb b/app/models/miq_provision_configuration_script_request.rb new file mode 100644 index 00000000000..511a281709f --- /dev/null +++ b/app/models/miq_provision_configuration_script_request.rb @@ -0,0 +1,38 @@ +class MiqProvisionConfigurationScriptRequest < MiqRequest + delegate :my_zone, :to => :source + + TASK_DESCRIPTION = N_('Automation Manager Provisioning') + SOURCE_CLASS_NAME = 'ConfigurationScript' + + default_value_for(:source_id) { |r| r.get_option(:source_id) } + default_value_for :source_type, "ConfigurationScript" + validates :source, :presence => true + validate :must_have_user + + def self.request_task_class_from(attribs) + source_id = MiqRequestMixin.get_option(:source_id, nil, attribs['options']) + configuration_script = ::ConfigurationScript.find_by(:id => source_id) + return if configuration_script.nil? + + configuration_script.manager.class.provision_class(nil) + end + + def self.new_request_task(attribs) + request_task_class_from(attribs).new(attribs) + end + + def customize_request_task_attributes(_req_task_attrs, _idx) + end + + def requested_task_idx + [-1] # we are only using one task per request + end + + def originating_controller + "configuration_scripts" + end + + def event_name(mode) + "configuration_script_provision_request_#{mode}" + end +end diff --git a/app/models/miq_provision_configuration_script_request_template.rb b/app/models/miq_provision_configuration_script_request_template.rb new file mode 100644 index 00000000000..26f507c51f3 --- /dev/null +++ b/app/models/miq_provision_configuration_script_request_template.rb @@ -0,0 +1,76 @@ +class MiqProvisionConfigurationScriptRequestTemplate < MiqProvisionConfigurationScriptRequest + def create_tasks_for_service(service_task, parent_svc) + template_service_resource = ServiceResource.find_by(:id => service_task.options[:service_resource_id]) + scaling_min = 1 + + _log.info("create_tasks_for_service ID #{service_task.id} SCALING : #{scaling_min}") + scaling_min.times.collect do |idx| + create_request_task(idx) do |req_task| + req_task.miq_request_id = service_task.miq_request.id + req_task.userid = service_task.userid + + task_options = req_task.options.merge(service_options(parent_svc, service_task, template_service_resource)) + task_options = task_options.merge(owner_options(service_task)) + req_task.options = task_options + end + end + end + + def request_task_class + MiqProvisionConfigurationScriptTask + end + + def get_source_name + SecureRandom.uuid # TODO + end + + def post_create(_auto_approve) + update(:description => "Miq Provision ConfigurationScript Request Template for #{source.name}") + self + end + + def service_template_resource_copy + dup.tap(&:save!) + end + + def execute + # Should not be called. + raise _("Provision ConfigurationScript Request Templates do not support the execute method.") + end + + private + + def service_options(parent_svc, service_task, template_service_resource) + { + :miq_force_unique_name => [true, 1], + :service_guid => parent_svc.guid, + :service_resource_id => template_service_resource.id, + :service_template_request => false, + :configuration_script_payload_id => service_task.options&.dig(:parent_configuration_script_payload_id) + } + end + + # NOTE: for services, the requester is the owner + def owner_options(service_task) + user = User.lookup_by_userid(service_task.userid) + return {} if user.nil? + + { + :requester_group => service_task.options[:requester_group], + :owner_email => user.email, + :owner_group => service_task.options[:requester_group], + :owner_first_name => user.first_name, + :owner_last_name => user.last_name + } + end + + def get_root_svc(parent_svc) + return nil unless parent_svc + + parent_svc.parent || parent_svc + end + + def get_parent_task(service_task) + MiqRequestTask.find_by(:id => service_task.options[:parent_task_id]) + end +end diff --git a/app/models/miq_provision_configuration_script_task.rb b/app/models/miq_provision_configuration_script_task.rb new file mode 100644 index 00000000000..b27bf057ce1 --- /dev/null +++ b/app/models/miq_provision_configuration_script_task.rb @@ -0,0 +1,4 @@ +class MiqProvisionConfigurationScriptTask < MiqRequestTask + def self.get_description(*) + end +end diff --git a/app/models/miq_provision_configuration_script_workflow.rb b/app/models/miq_provision_configuration_script_workflow.rb new file mode 100644 index 00000000000..8ed4293c9da --- /dev/null +++ b/app/models/miq_provision_configuration_script_workflow.rb @@ -0,0 +1,17 @@ +class MiqProvisionConfigurationScriptWorkflow < MiqProvisionWorkflow + def self.base_model + MiqProvisionConfigurationScriptWorkflow + end + + def self.default_dialog_file + 'miq_provision_configuration_script_dialogs' + end + + def self.automate_dialog_request + 'UI_CONFIGURATION_SCRIPT_PROVISION_INFO' + end + + def self.request_class + MiqProvisionConfigurationScriptRequest + end +end diff --git a/app/models/miq_request.rb b/app/models/miq_request.rb index 26b84684374..cf956ab9418 100644 --- a/app/models/miq_request.rb +++ b/app/models/miq_request.rb @@ -82,6 +82,9 @@ class MiqRequest < ApplicationRecord :MiqProvisionConfiguredSystemRequest => { :provision_via_foreman => N_("%{config_mgr_type} Provision") % {:config_mgr_type => ui_lookup(:ui_title => 'foreman')} }, + :MiqProvisionConfigurationScriptRequest => { + :provision_via_automation_manager => N_("Automation Manager Provision") + }, :MiqProvisionRequest => { :template => N_("VM Provision"), :clone_to_vm => N_("VM Clone"), @@ -121,7 +124,8 @@ class MiqRequest < ApplicationRecord }.freeze REQUEST_TYPES_BACKEND_ONLY = { - :MiqProvisionRequestTemplate => {:template => "VM Provision Template"}, + :MiqProvisionRequestTemplate => {:template => "VM Provision Template"}, + :MiqProvisionConfigurationScriptRequestTemplate => {:provision_via_automation_manager => "Configuration Script Template"} } REQUEST_TYPES = MODEL_REQUEST_TYPES.values.each_with_object(REQUEST_TYPES_BACKEND_ONLY) { |i, h| i.each { |k, v| h[k] = v } } diff --git a/app/models/service_template.rb b/app/models/service_template.rb index 5d74a21cb51..e721688ce3e 100644 --- a/app/models/service_template.rb +++ b/app/models/service_template.rb @@ -20,7 +20,8 @@ class ServiceTemplate < ApplicationRecord :fqname, :configuration_template, :configuration_template_id, - :configuration_template_type].freeze + :configuration_template_type, + :configuration_script_id].freeze include CustomActionsMixin include ServiceMixin diff --git a/product/dialogs/miq_dialogs/miq_provision_configuration_script_dialogs.yaml b/product/dialogs/miq_dialogs/miq_provision_configuration_script_dialogs.yaml new file mode 100644 index 00000000000..f5c3f1e9a78 --- /dev/null +++ b/product/dialogs/miq_dialogs/miq_provision_configuration_script_dialogs.yaml @@ -0,0 +1,193 @@ +--- +:name: miq_provision_configuration_script_dialogs +:description: Sample Configuration Script Provisioning Dialog +:dialog_type: MiqProvisionConfigurationScriptWorkflow +:content: + :buttons: + - :submit + - :cancel + :dialogs: + :requester: + :description: Request + :fields: + :owner_phone: + :description: Phone + :required: false + :display: :hide + :data_type: :string + :owner_country: + :description: Country/Region + :required: false + :display: :hide + :data_type: :string + :owner_phone_mobile: + :description: Mobile + :required: false + :display: :hide + :data_type: :string + :owner_title: + :description: Title + :required: false + :display: :hide + :data_type: :string + :owner_first_name: + :description: First Name + :required: false + :display: :edit + :data_type: :string + :owner_manager: + :description: Name + :required: false + :display: :edit + :data_type: :string + :owner_address: + :description: Address + :required: false + :display: :hide + :data_type: :string + :owner_company: + :description: Company + :required: false + :display: :hide + :data_type: :string + :owner_last_name: + :description: Last Name + :required: false + :display: :edit + :data_type: :string + :owner_manager_mail: + :description: E-Mail + :required: false + :display: :hide + :data_type: :string + :owner_city: + :description: City + :required: false + :display: :hide + :data_type: :string + :owner_department: + :description: Department + :required: false + :display: :hide + :data_type: :string + :owner_load_ldap: + :pressed: + :method: :retrieve_ldap + :description: Look Up LDAP Email + :required: false + :display: :show + :data_type: :button + :owner_manager_phone: + :description: Phone + :required: false + :display: :hide + :data_type: :string + :owner_state: + :description: State + :required: false + :display: :hide + :data_type: :string + :owner_office: + :description: Office + :required: false + :display: :hide + :data_type: :string + :owner_zip: + :description: Zip code + :required: false + :display: :hide + :data_type: :string + :owner_email: + :description: E-Mail + :required_method: :validate_regex + :required_regex: !ruby/regexp /\A[\w!#$\%&'*+\/=?`\{|\}~^-]+(?:\.[\w!#$\%&'*+\/=?`\{|\}~^-]+)*@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}\Z/i + :required: true + :display: :edit + :data_type: :string + :request_notes: + :description: Notes + :required: false + :display: :edit + :data_type: :string + :display: :show + :field_order: + :purpose: + :description: Purpose + :fields: + :tag_ids: + :required_method: :validate_tags + :description: Tags + :required: false + :options: + :include: [] + :order: [] + :single_select: [] + :exclude: [] + :display: :edit + :required_tags: [] + :data_type: :integer + :display: :show + :field_order: + :customize: + :description: Customize + :fields: + :root_password: + :description: Root Password + :required: false + :display: :edit + :data_type: :string + :notes: Minimum 8 characters or blank + :hostname: + :description: Host Name + :required: false + :display: :edit + :data_type: :string + :ip_addr: + :description: IP Address + :required: false + :notes: (Enter starting IP address) + :display: :edit + :data_type: :string + :notes_display: :hide + :display: :show + :service: + :description: Catalog + :fields: + :source_id: + :values_from: + :method: :allowed_configuration_scripts + :description: Workspaces + :required: true + :notes: + :display: :show + :data_type: :integer + :notes_display: :show + :display: :show + :schedule: + :description: Schedule + :fields: + :schedule_type: + :values: + schedule: Schedule + immediately: Immediately on Approval + :description: When to Provision + :required: false + :display: :edit + :default: immediately + :data_type: :string + :schedule_time: + :values_from: + :options: + :offset: 1.day + :method: :default_schedule_time + :description: Provision on + :required: false + :display: :edit + :data_type: :time + :display: :show + :dialog_order: + - :requester + - :purpose + - :service + - :customize + - :schedule diff --git a/spec/models/miq_provision_configuration_script_request_spec.rb b/spec/models/miq_provision_configuration_script_request_spec.rb new file mode 100644 index 00000000000..bec787389cd --- /dev/null +++ b/spec/models/miq_provision_configuration_script_request_spec.rb @@ -0,0 +1,24 @@ +describe MiqProvisionConfigurationScriptRequest do + let(:admin) { FactoryBot.create(:user) } + let(:ems) { FactoryBot.create(:automation_manager, :url => "https://localhost") } + let(:configuration_script) { FactoryBot.create(:configuration_script, :manager => ems) } + let(:request) { FactoryBot.create(:miq_provision_configuration_script_request, :requester => admin, :options => {:source_id => [configuration_script.id]}) } + + describe ".request_task_class_from" do + it "retrieves the request task class" do + options = {:source_id => configuration_script.id} + + expect(described_class.request_task_class_from("options" => options)).to eq(ems.class::Provision) + end + end + + describe ".new_request_task" do + it "returns the provision task" do + options = {:source_id => configuration_script.id} + + request_task = described_class.new_request_task("options" => options) + expect(request_task).to have_attributes(:options => options, :state => "pending") + expect(request_task).to be_kind_of(ManageIQ::Providers::AutomationManager::Provision) + end + end +end diff --git a/spec/models/miq_request_spec.rb b/spec/models/miq_request_spec.rb index 531db80dad3..2a0e5ee5059 100644 --- a/spec/models/miq_request_spec.rb +++ b/spec/models/miq_request_spec.rb @@ -5,20 +5,22 @@ context "CONSTANTS" do it "REQUEST_TYPES" do expected_request_types = { - :MiqProvisionRequest => {:template => "VM Provision", :clone_to_vm => "VM Clone", :clone_to_template => "VM Publish"}, - :MiqProvisionRequestTemplate => {:template => "VM Provision Template"}, - :MiqProvisionConfiguredSystemRequest => {:provision_via_foreman => "#{ui_lookup(:ui_title => 'foreman')} Provision"}, - :VmReconfigureRequest => {:vm_reconfigure => "VM Reconfigure"}, - :VmCloudReconfigureRequest => {:vm_cloud_reconfigure => "VM Cloud Reconfigure"}, - :VmMigrateRequest => {:vm_migrate => "VM Migrate"}, - :VmRetireRequest => {:vm_retire => "VM Retire"}, - :ServiceRetireRequest => {:service_retire => "Service Retire"}, - :OrchestrationStackRetireRequest => {:orchestration_stack_retire => "Orchestration Stack Retire"}, - :AutomationRequest => {:automation => "Automation"}, - :ServiceTemplateProvisionRequest => {:clone_to_service => "Service Provision"}, - :ServiceReconfigureRequest => {:service_reconfigure => "Service Reconfigure"}, - :PhysicalServerProvisionRequest => {:provision_physical_server => "Physical Server Provision"}, - :PhysicalServerFirmwareUpdateRequest => {:physical_server_firmware_update => "Physical Server Firmware Update"}, + :MiqProvisionRequest => {:template => "VM Provision", :clone_to_vm => "VM Clone", :clone_to_template => "VM Publish"}, + :MiqProvisionRequestTemplate => {:template => "VM Provision Template"}, + :MiqProvisionConfiguredSystemRequest => {:provision_via_foreman => "#{ui_lookup(:ui_title => 'foreman')} Provision"}, + :VmReconfigureRequest => {:vm_reconfigure => "VM Reconfigure"}, + :VmCloudReconfigureRequest => {:vm_cloud_reconfigure => "VM Cloud Reconfigure"}, + :VmMigrateRequest => {:vm_migrate => "VM Migrate"}, + :VmRetireRequest => {:vm_retire => "VM Retire"}, + :ServiceRetireRequest => {:service_retire => "Service Retire"}, + :OrchestrationStackRetireRequest => {:orchestration_stack_retire => "Orchestration Stack Retire"}, + :AutomationRequest => {:automation => "Automation"}, + :MiqProvisionConfigurationScriptRequest => {:provision_via_automation_manager => "Automation Manager Provision"}, + :MiqProvisionConfigurationScriptRequestTemplate => {:provision_via_automation_manager => "Configuration Script Template"}, + :ServiceTemplateProvisionRequest => {:clone_to_service => "Service Provision"}, + :ServiceReconfigureRequest => {:service_reconfigure => "Service Reconfigure"}, + :PhysicalServerProvisionRequest => {:provision_physical_server => "Physical Server Provision"}, + :PhysicalServerFirmwareUpdateRequest => {:physical_server_firmware_update => "Physical Server Firmware Update"}, } expect(described_class::REQUEST_TYPES).to eq(expected_request_types)