From 4b6a0eb28f5f9cea9c4d085ca3c0b295d0870f0c Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Fri, 20 Sep 2024 19:11:07 +0530 Subject: [PATCH 01/27] add support for creating new diaglogs with extra-vars for terraform template --- .../terraform_template_service_dialog.rb | 50 +++++++++++++++++++ .../service_template_terraform_template.rb | 22 ++++++++ 2 files changed, 72 insertions(+) create mode 100644 app/models/dialog/terraform_template_service_dialog.rb diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb new file mode 100644 index 00000000..1858a8cd --- /dev/null +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -0,0 +1,50 @@ +class Dialog + class TerraformTemplateServiceDialog + def self.create_dialog(label, extra_vars) + new.create_dialog(label, extra_vars) + end + + # This dialog is to be used by a terraform template service item + def create_dialog(label, extra_vars) + Dialog.new(:label => label, :buttons => "submit,cancel").tap do |dialog| + tab = dialog.dialog_tabs.build(:display => "edit", :label => "Basic Information", :position => 0) + if extra_vars.present? + add_variables_group(tab, 1, extra_vars) + end + dialog.save! + end + end + + private + + def add_variables_group(tab, position, extra_vars) + tab.dialog_groups.build( + :display => "edit", + :label => "Variables", + :position => position + ).tap do |dialog_group| + extra_vars.transform_values { |val| val[:default] }.each_with_index do |(key, value), index| + value = value.to_json if [Hash, Array].include?(value.class) + add_variable_field(key, value, dialog_group, index) + end + end + end + + def add_variable_field(key, value, group, position) + group.dialog_fields.build( + :type => "DialogFieldTextBox", + :name => "param_#{key}", + :data_type => "string", + :display => "edit", + :required => false, + :default_value => value, + :label => key, + :description => key, + :reconfigurable => true, + :position => position, + :dialog_group => group, + :read_only => false + ) + end + end +end diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index a23e4569..d8064cd9 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -17,6 +17,9 @@ def self.create_catalog_item(options, _auth_user) transaction do create_from_options(options).tap do |service_template| + dialog_ids = service_template.send(:create_dialogs, config_info) + config_info.deep_merge!(dialog_ids) + service_template.options[:config_info].deep_merge!(dialog_ids) service_template.create_resource_actions(config_info) end end @@ -41,4 +44,23 @@ def terraform_template(action) ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Template.find(template_id) end + + def create_dialogs(config_info) + # [:provision, :retirement, :reconfigure].each_with_object({}) do |action, hash| + [:provision,].each_with_object({}) do |action, hash| + info = config_info[action] + # next unless new_dialog_required?(info) + + template_name = SecureRandom.alphanumeric # TODO: get template_name instead + + new_dialog_name = info.key?(:new_dialog_name) ? info[:new_dialog_name] : "Dialog-#{template_name}" + + hash[action] = {:dialog_id => create_new_dialog(info[:new_dialog_name], info[:extra_vars]).id} + end + end + + def create_new_dialog(dialog_name, extra_vars) + Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, extra_vars) + end + private :create_new_dialog end From 067f4f408564e3a68e5a502e45ebb1dea07bf08f Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Sat, 21 Sep 2024 00:34:22 +0530 Subject: [PATCH 02/27] add parse_template_variables method in Terraform::Runner to parse template input/output variables --- lib/terraform/runner.rb | 27 ++++++++++++++++++++ lib/terraform/runner/variables_response.rb | 29 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 lib/terraform/runner/variables_response.rb diff --git a/lib/terraform/runner.rb b/lib/terraform/runner.rb index 0d90223d..415fe704 100644 --- a/lib/terraform/runner.rb +++ b/lib/terraform/runner.rb @@ -59,6 +59,13 @@ def fetch_result_by_stack_id(stack_id) retrieve_stack_job(stack_id) end + # Parse Terraform Template input/output variables + # @param template_path [String] Path to the template we will want to parse for input/output variables + # @return [Terraform::Runner::VariablesResponse] Response object of terraform-runner api/template/variables + def parse_template_variables(template_path) + template_variables(template_path) + end + # ================================================= # TerraformRunner Stack-API interaction methods # ================================================= @@ -180,6 +187,26 @@ def encoded_zip_from_directory(template_path) end end + # Parse Variables in Terraform Template + def template_variables( + template_path + ) + _log.info("prase template: #{template_path}") + encoded_zip_file = encoded_zip_from_directory(template_path) + + # TODO: use tags,env_vars + payload = { + :templateZipFile => encoded_zip_file, + } + + http_response = terraform_runner_client.post( + "api/template/variables", + *json_post_arguments(payload) + ) + _log.debug("==== http_response.body: \n #{http_response.body}") + Terraform::Runner::VariablesResponse.parsed_response(http_response) + end + def jwt_token require "jwt" diff --git a/lib/terraform/runner/variables_response.rb b/lib/terraform/runner/variables_response.rb new file mode 100644 index 00000000..b36525ad --- /dev/null +++ b/lib/terraform/runner/variables_response.rb @@ -0,0 +1,29 @@ +require 'json' + +module Terraform + class Runner + # Response object designed for holding full response from terraform-runner api/template/variables + class VariablesResponse + include Vmdb::Logging + + attr_reader :template_input_params, :template_output_params, :terraform_version + + # @return [String] Extracted attributes from the JSON response body object + def self.parsed_response(http_response) + data = JSON.parse(http_response.body) + _log.debug("data : #{data}") + Terraform::Runner::VariablesResponse.new( + :template_input_params => data['template_input_params'], + :template_output_params => data['template_output_params'], + :terraform_version => data['terraform_version'] + ) + end + + def initialize(template_input_params: nil, template_output_params: nil, terraform_version: nil) + @template_input_params = template_input_params + @template_output_params = template_output_params + @terraform_version = terraform_version + end + end + end +end From 53909c9f8ca1f53200be91966a6ae642355d86e1 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Mon, 23 Sep 2024 00:59:54 +0530 Subject: [PATCH 03/27] add test for parse_template_variables --- .../hello-world-variables-success.json | 25 +++++++++++ spec/lib/terraform/runner_spec.rb | 44 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 spec/lib/terraform/runner/data/responses/hello-world-variables-success.json diff --git a/spec/lib/terraform/runner/data/responses/hello-world-variables-success.json b/spec/lib/terraform/runner/data/responses/hello-world-variables-success.json new file mode 100644 index 00000000..3ea73cd3 --- /dev/null +++ b/spec/lib/terraform/runner/data/responses/hello-world-variables-success.json @@ -0,0 +1,25 @@ +{ + "template_input_params": [ + { + "name": "name", + "label": "name", + "type": "string", + "description": "", + "required": true, + "secured": false, + "hidden": false, + "immutable": false, + "default": "World" + } + ], + "template_output_params": [ + { + "name": "greeting", + "label": "greeting", + "description": "", + "secured": false, + "hidden": false + } + ], + "terraform_version": ">= 1.1.0" + } \ No newline at end of file diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index dad4515f..d83fd69b 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -352,4 +352,48 @@ def verify_req(req) end end end + + context '.parse_template_variables hello-world' do + describe '.parse_template_variables input/output vars' do + template_variables_stub = nil + + def verify_req(req) + body = JSON.parse(req.body) + expect(body).to(have_key('templateZipFile')) + end + + before do + ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" + + @hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-variables-success.json"))) + + template_variables_stub = stub_request(:post, "https://1.2.3.4:7000/api/template/variables") + .with { |req| verify_req(req) } + .to_return( + :status => 200, + :body => @hello_world_variables_response.to_json + ) + end + + it "parse input/output params from hello-world terraform template" do + response = Terraform::Runner.parse_template_variables(File.join(__dir__, "runner/data/hello-world")) + expect(template_variables_stub).to(have_been_requested.times(1)) + + expect(response.template_input_params.length).to(eq(1)) + input_var = response.template_input_params[0] + expect(input_var["name"]).to(eq("name")) + expect(input_var["label"]).to(eq("name")) + expect(input_var["type"]).to(eq("string")) + expect(input_var["default"]).to(eq("World")) + expect(input_var["required"]).to(eq(true)) + expect(input_var["secured"]).to(eq(false)) + + expect(response.template_output_params.length).to(eq(1)) + output_var = response.template_output_params[0] + expect(output_var["name"]).to(eq("greeting")) + expect(output_var["label"]).to(eq("greeting")) + expect(output_var["secured"]).to(eq(false)) + end + end + end end From e377dbeeb621a991520d0537a28f60366f8c07a1 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Mon, 23 Sep 2024 13:21:16 +0530 Subject: [PATCH 04/27] parse terraform template and store input/output vars info --- .../configuration_script_source.rb | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb index 3eba437a..02595f4b 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb @@ -75,8 +75,11 @@ def self.template_name_from_git_repo_url(git_repo_url, relative_path) def find_templates_in_git_repo template_dirs = {} + # checkout repo, for sending files to terraform-runner to parse for input/ouput vars. + git_checkout_tempdir = checkout_git_repo + # traverse through files in git-worktree - git_repository.update_repo + # git_repository.update_repo - already done through checkout_git_repo git_repository.with_worktree do |worktree| worktree.ref = scm_branch @@ -85,22 +88,51 @@ def find_templates_in_git_repo .group_by { |file| File.dirname(file) } .select { |_dir, files| files.any? { |f| f.end_with?(".tf", ".tf.json") } } .transform_values! { |files| files.map { |f| File.basename(f) } } - .each do |parent_dir, files| - name = self.class.template_name_from_git_repo_url(git_repository.url, parent_dir) + .each do |relative_path, files| + name = self.class.template_name_from_git_repo_url(git_repository.url, relative_path) + + template_full_path = File.join(git_checkout_tempdir, relative_path) - # TODO: add parsing for input/output vars - input_vars = nil - output_vars = nil + input_vars, output_vars, terraform_version = parse_vars_in_template(template_full_path) template_dirs[name] = { - :relative_path => parent_dir, - :files => files, - :input_vars => input_vars, - :output_vars => output_vars + :relative_path => relative_path, + :files => files, + :input_vars => input_vars, + :output_vars => output_vars, + :terraform_version => terraform_version, } end end template_dirs + rescue => error + _log.error("Failing scaning for terraform templates in the git repo: ", error) + raise error + ensure + cleanup_git_repo(git_checkout_tempdir) + end + + # Parse template and return input-vars, output-vars & terraform-version + def parse_vars_in_template(template_path) + response = Terraform::Runner.parse_template_variables(template_path) + return response.template_input_params, response.template_output_params, response.terraform_version + end + + # checkout git repo to temp dir + def checkout_git_repo + git_checkout_tempdir = Dir.mktmpdir("embedded-terraform-runner-git") + + _log.info("Checking out git repository to #{git_checkout_tempdir}...") + checkout_git_repository(git_checkout_tempdir) + git_checkout_tempdir + end + + # clean temp dir + def cleanup_git_repo(git_checkout_tempdir) + _log.info("Cleaning up git repository checked out at #{git_checkout_tempdir}...") + FileUtils.rm_rf(git_checkout_tempdir) + rescue Errno::ENOENT + nil end end From 1573aacc717702af7f340258ef678dca7b538f9a Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Mon, 23 Sep 2024 15:08:29 +0530 Subject: [PATCH 05/27] add terraform template input variables into new dialog --- .../terraform_template_service_dialog.rb | 62 ++++++++++++++++--- .../service_template_terraform_template.rb | 6 +- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb index 1858a8cd..66ae3a78 100644 --- a/app/models/dialog/terraform_template_service_dialog.rb +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -1,13 +1,18 @@ +require "JSON" + class Dialog class TerraformTemplateServiceDialog - def self.create_dialog(label, extra_vars) - new.create_dialog(label, extra_vars) + def self.create_dialog(label, terraform_template, extra_vars) + new.create_dialog(label, terraform_template, extra_vars) end # This dialog is to be used by a terraform template service item - def create_dialog(label, extra_vars) + def create_dialog(label, terraform_template, extra_vars) Dialog.new(:label => label, :buttons => "submit,cancel").tap do |dialog| tab = dialog.dialog_tabs.build(:display => "edit", :label => "Basic Information", :position => 0) + if terraform_template.present? + add_template_variables_group(tab, 0, terraform_template) + end if extra_vars.present? add_variables_group(tab, 1, extra_vars) end @@ -17,33 +22,70 @@ def create_dialog(label, extra_vars) private + def add_template_variables_group(tab, position, terraform_template) + template_info = JSON.parse(terraform_template.payload) + input_vars = template_info["input_vars"] + + return if input_vars.nil? + + tab.dialog_groups.build( + :display => "edit", + :label => "Terraform Template Variables", + :position => position + ).tap do |dialog_group| + input_vars.each_with_index do |(var_info), index| + key = var_info["name"] + value = var_info["default"] + value = value.to_json if [Hash, Array].include?(value.class) + required = var_info["required"] + readonly = var_info["immutable"] + hidden = var_info["hidden"] + label = var_info["label"] + description = var_info["description"] + if description.blank? + description = key + end + + # TODO: use these when adding variable field + # type = var_info["type"] + # secured = var_info["secured"] + + if hidden == true + _log.info("Not adding text-box for hidden variable: #{key}") + else + add_variable_field(key, value, dialog_group, index, label, description, required, readonly) + end + end + end + end + def add_variables_group(tab, position, extra_vars) tab.dialog_groups.build( :display => "edit", - :label => "Variables", + :label => "Extra Variables", :position => position ).tap do |dialog_group| extra_vars.transform_values { |val| val[:default] }.each_with_index do |(key, value), index| value = value.to_json if [Hash, Array].include?(value.class) - add_variable_field(key, value, dialog_group, index) + add_variable_field(key, value, dialog_group, index, key, key, false, false) end end end - def add_variable_field(key, value, group, position) + def add_variable_field(key, value, group, position, label, description, required, read_only) group.dialog_fields.build( :type => "DialogFieldTextBox", :name => "param_#{key}", :data_type => "string", :display => "edit", - :required => false, + :required => required, :default_value => value, - :label => key, - :description => key, + :label => label, + :description => description, :reconfigurable => true, :position => position, :dialog_group => group, - :read_only => false + :read_only => read_only ) end end diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index d8064cd9..77079ae0 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -55,12 +55,12 @@ def create_dialogs(config_info) new_dialog_name = info.key?(:new_dialog_name) ? info[:new_dialog_name] : "Dialog-#{template_name}" - hash[action] = {:dialog_id => create_new_dialog(info[:new_dialog_name], info[:extra_vars]).id} + hash[action] = {:dialog_id => create_new_dialog(new_dialog_name, terraform_template(action), info[:extra_vars]).id} end end - def create_new_dialog(dialog_name, extra_vars) - Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, extra_vars) + def create_new_dialog(dialog_name, terraform_template, extra_vars) + Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, terraform_template, extra_vars) end private :create_new_dialog end From 30a006bc869afeb66b84cebd0cf7db69d7dc2ce6 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 24 Sep 2024 09:59:31 +0530 Subject: [PATCH 06/27] update spec - match hash with include, instead match to each key value --- spec/lib/terraform/runner_spec.rb | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index d83fd69b..2fbc36cf 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -380,19 +380,26 @@ def verify_req(req) expect(template_variables_stub).to(have_been_requested.times(1)) expect(response.template_input_params.length).to(eq(1)) - input_var = response.template_input_params[0] - expect(input_var["name"]).to(eq("name")) - expect(input_var["label"]).to(eq("name")) - expect(input_var["type"]).to(eq("string")) - expect(input_var["default"]).to(eq("World")) - expect(input_var["required"]).to(eq(true)) - expect(input_var["secured"]).to(eq(false)) + expect(response.template_input_params.first).to include( + "name" => "name", + "label" => "name", + "type" => "string", + "description" => "", + "required" => true, + "secured" => false, + "hidden" => false, + "immutable" => false, + "default" => "World" + ) expect(response.template_output_params.length).to(eq(1)) - output_var = response.template_output_params[0] - expect(output_var["name"]).to(eq("greeting")) - expect(output_var["label"]).to(eq("greeting")) - expect(output_var["secured"]).to(eq(false)) + expect(response.template_output_params.first).to include( + "name" => "greeting", + "label" => "greeting", + "description" => "", + "secured" => false, + "hidden" => false + ) end end end From 398081afd4482162e646deedd74a80ed14638539 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 24 Sep 2024 10:09:16 +0530 Subject: [PATCH 07/27] update spec - match with be_kind_of(Hash) --- spec/lib/terraform/runner_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index 2fbc36cf..cf8ccce5 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -380,7 +380,7 @@ def verify_req(req) expect(template_variables_stub).to(have_been_requested.times(1)) expect(response.template_input_params.length).to(eq(1)) - expect(response.template_input_params.first).to include( + expect(response.template_input_params.first).to be_kind_of(Hash).and include( "name" => "name", "label" => "name", "type" => "string", @@ -393,7 +393,7 @@ def verify_req(req) ) expect(response.template_output_params.length).to(eq(1)) - expect(response.template_output_params.first).to include( + expect(response.template_output_params.first).to be_kind_of(Hash).and include( "name" => "greeting", "label" => "greeting", "description" => "", From d13a115ca38594dbbd269e252469cd30e9c30699 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 24 Sep 2024 11:33:52 +0530 Subject: [PATCH 08/27] review comments - move require into method & other changes --- app/models/dialog/terraform_template_service_dialog.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb index 66ae3a78..4a000f91 100644 --- a/app/models/dialog/terraform_template_service_dialog.rb +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -1,5 +1,3 @@ -require "JSON" - class Dialog class TerraformTemplateServiceDialog def self.create_dialog(label, terraform_template, extra_vars) @@ -23,6 +21,7 @@ def create_dialog(label, terraform_template, extra_vars) private def add_template_variables_group(tab, position, terraform_template) + require "json" template_info = JSON.parse(terraform_template.payload) input_vars = template_info["input_vars"] @@ -36,7 +35,6 @@ def add_template_variables_group(tab, position, terraform_template) input_vars.each_with_index do |(var_info), index| key = var_info["name"] value = var_info["default"] - value = value.to_json if [Hash, Array].include?(value.class) required = var_info["required"] readonly = var_info["immutable"] hidden = var_info["hidden"] @@ -66,13 +64,13 @@ def add_variables_group(tab, position, extra_vars) :position => position ).tap do |dialog_group| extra_vars.transform_values { |val| val[:default] }.each_with_index do |(key, value), index| - value = value.to_json if [Hash, Array].include?(value.class) add_variable_field(key, value, dialog_group, index, key, key, false, false) end end end def add_variable_field(key, value, group, position, label, description, required, read_only) + value = value.to_json if [Hash, Array].include?(value.class) group.dialog_fields.build( :type => "DialogFieldTextBox", :name => "param_#{key}", From f9347495fb4b13965a68b41585c04b42e8005dae Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 24 Sep 2024 11:53:02 +0530 Subject: [PATCH 09/27] improve position value for dialog groups --- app/models/dialog/terraform_template_service_dialog.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb index 4a000f91..c5fda421 100644 --- a/app/models/dialog/terraform_template_service_dialog.rb +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -8,11 +8,13 @@ def self.create_dialog(label, terraform_template, extra_vars) def create_dialog(label, terraform_template, extra_vars) Dialog.new(:label => label, :buttons => "submit,cancel").tap do |dialog| tab = dialog.dialog_tabs.build(:display => "edit", :label => "Basic Information", :position => 0) + position = 0 if terraform_template.present? - add_template_variables_group(tab, 0, terraform_template) + add_template_variables_group(tab, position, terraform_template) + position += 1 end if extra_vars.present? - add_variables_group(tab, 1, extra_vars) + add_variables_group(tab, position, extra_vars) end dialog.save! end From 2a983a1130f8c07b919d6bebfaf4bc4d5a30472b Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 24 Sep 2024 13:46:31 +0530 Subject: [PATCH 10/27] review comment - code improvements --- .../terraform_template_service_dialog.rb | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb index c5fda421..f8c89a31 100644 --- a/app/models/dialog/terraform_template_service_dialog.rb +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -35,26 +35,17 @@ def add_template_variables_group(tab, position, terraform_template) :position => position ).tap do |dialog_group| input_vars.each_with_index do |(var_info), index| - key = var_info["name"] - value = var_info["default"] - required = var_info["required"] - readonly = var_info["immutable"] - hidden = var_info["hidden"] - label = var_info["label"] - description = var_info["description"] - if description.blank? - description = key - end - + key, value, required, readonly, hidden, label, description = var_info.values_at( + "name", "default", "required", "immutable", "hidden", "label", "description" + ) # TODO: use these when adding variable field - # type = var_info["type"] - # secured = var_info["secured"] + # type, secured = var_info.values_at("type", "secured") + + next if hidden - if hidden == true - _log.info("Not adding text-box for hidden variable: #{key}") - else - add_variable_field(key, value, dialog_group, index, label, description, required, readonly) - end + add_variable_field( + key, value, dialog_group, index, label, description, required, readonly + ) end end end @@ -73,6 +64,8 @@ def add_variables_group(tab, position, extra_vars) def add_variable_field(key, value, group, position, label, description, required, read_only) value = value.to_json if [Hash, Array].include?(value.class) + description = key if description.blank? + group.dialog_fields.build( :type => "DialogFieldTextBox", :name => "param_#{key}", From 60200470850dc02f09a7fdb2d18923557bf21755 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 24 Sep 2024 14:00:54 +0530 Subject: [PATCH 11/27] minor - remove commented code & _log.info to _log.debug --- .../automation_manager/configuration_script_source.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb index 02595f4b..b65b47cc 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb @@ -79,7 +79,6 @@ def find_templates_in_git_repo git_checkout_tempdir = checkout_git_repo # traverse through files in git-worktree - # git_repository.update_repo - already done through checkout_git_repo git_repository.with_worktree do |worktree| worktree.ref = scm_branch @@ -123,14 +122,14 @@ def parse_vars_in_template(template_path) def checkout_git_repo git_checkout_tempdir = Dir.mktmpdir("embedded-terraform-runner-git") - _log.info("Checking out git repository to #{git_checkout_tempdir}...") + _log.debug("Checking out git repository to #{git_checkout_tempdir}...") checkout_git_repository(git_checkout_tempdir) git_checkout_tempdir end # clean temp dir def cleanup_git_repo(git_checkout_tempdir) - _log.info("Cleaning up git repository checked out at #{git_checkout_tempdir}...") + _log.debug("Cleaning up git repository checked out at #{git_checkout_tempdir}...") FileUtils.rm_rf(git_checkout_tempdir) rescue Errno::ENOENT nil From 32c8387d373054ca5af5f0d9eea1bdb2033e05ba Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Wed, 25 Sep 2024 14:11:54 +0530 Subject: [PATCH 12/27] fix error log message --- .../automation_manager/configuration_script_source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb index b65b47cc..fff38159 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb @@ -106,7 +106,7 @@ def find_templates_in_git_repo template_dirs rescue => error - _log.error("Failing scaning for terraform templates in the git repo: ", error) + _log.error("Failing scaning for terraform templates in the git repo: #{error}") raise error ensure cleanup_git_repo(git_checkout_tempdir) From e4441229ab9898108788d70b4cd8ca582ac412cc Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Wed, 25 Sep 2024 11:22:49 +0530 Subject: [PATCH 13/27] minor - private method defination --- app/models/service_template_terraform_template.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index 77079ae0..52798559 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -59,8 +59,9 @@ def create_dialogs(config_info) end end + private + def create_new_dialog(dialog_name, terraform_template, extra_vars) Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, terraform_template, extra_vars) end - private :create_new_dialog end From 72d7c7e78b8ffab7d682b1aba482b74bd5425d30 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Wed, 25 Sep 2024 17:59:31 +0530 Subject: [PATCH 14/27] use same dialog from :provision action with retirement & reconfigure action --- .../service_template_terraform_template.rb | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index 52798559..bc76c101 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -46,17 +46,25 @@ def terraform_template(action) end def create_dialogs(config_info) - # [:provision, :retirement, :reconfigure].each_with_object({}) do |action, hash| - [:provision,].each_with_object({}) do |action, hash| - info = config_info[action] - # next unless new_dialog_required?(info) - - template_name = SecureRandom.alphanumeric # TODO: get template_name instead - - new_dialog_name = info.key?(:new_dialog_name) ? info[:new_dialog_name] : "Dialog-#{template_name}" + dialog_hash = {} + + info = config_info[:provision] + if info + # create new dialog, if required for :provision action + if info.key?(:new_dialog_name) && !info.key?(:dialog_id) + provision_dialog_id = create_new_dialog(info[:new_dialog_name], template = terraform_template(:provision), info[:extra_vars]).id + dialog_hash[:provision] = {:dialog_id => provision_dialog_id} + else + provision_dialog_id = info[:dialog_id] + end - hash[action] = {:dialog_id => create_new_dialog(new_dialog_name, terraform_template(action), info[:extra_vars]).id} + # For :retirement & :reconfigure, we use the same dialog as in :provision action + dialog_hash = [:retirement, :reconfigure].each_with_object(dialog_hash) do |action, hash| + hash[action] = {:dialog_id => :provision_dialog_id} + end end + + dialog_hash end private @@ -64,4 +72,8 @@ def create_dialogs(config_info) def create_new_dialog(dialog_name, terraform_template, extra_vars) Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, terraform_template, extra_vars) end + + def new_dialog_required?(info) + info && info.key?(:new_dialog_name) && !info.key?(:dialog_id) + end end From fca9d3d1633883b58b8eede20bd590e6777976ff Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Wed, 25 Sep 2024 18:24:54 +0530 Subject: [PATCH 15/27] remove 'param_' prefix for dialog var names --- app/models/dialog/terraform_template_service_dialog.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb index f8c89a31..5e087590 100644 --- a/app/models/dialog/terraform_template_service_dialog.rb +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -68,7 +68,7 @@ def add_variable_field(key, value, group, position, label, description, required group.dialog_fields.build( :type => "DialogFieldTextBox", - :name => "param_#{key}", + :name => "#{key}", :data_type => "string", :display => "edit", :required => required, From ea7945dd0b2d962581f18af8ffe7e2de95243e3c Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Wed, 25 Sep 2024 21:36:43 +0530 Subject: [PATCH 16/27] code-review-fix: no need new VariablesResponse class, no translation done --- .../configuration_script_source.rb | 2 +- lib/terraform/runner.rb | 9 +++--- lib/terraform/runner/variables_response.rb | 29 ------------------- spec/lib/terraform/runner_spec.rb | 13 ++++++--- 4 files changed, 15 insertions(+), 38 deletions(-) delete mode 100644 lib/terraform/runner/variables_response.rb diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb index fff38159..505459ed 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb @@ -115,7 +115,7 @@ def find_templates_in_git_repo # Parse template and return input-vars, output-vars & terraform-version def parse_vars_in_template(template_path) response = Terraform::Runner.parse_template_variables(template_path) - return response.template_input_params, response.template_output_params, response.terraform_version + return response['template_input_params'], response['template_output_params'], response['terraform_version'] end # checkout git repo to temp dir diff --git a/lib/terraform/runner.rb b/lib/terraform/runner.rb index 415fe704..f99eb91c 100644 --- a/lib/terraform/runner.rb +++ b/lib/terraform/runner.rb @@ -61,7 +61,8 @@ def fetch_result_by_stack_id(stack_id) # Parse Terraform Template input/output variables # @param template_path [String] Path to the template we will want to parse for input/output variables - # @return [Terraform::Runner::VariablesResponse] Response object of terraform-runner api/template/variables + # @return Response(body) object of terraform-runner api/template/variables, + # - the response object had template_input_params, template_output_params and terraform_version def parse_template_variables(template_path) template_variables(template_path) end @@ -191,10 +192,9 @@ def encoded_zip_from_directory(template_path) def template_variables( template_path ) - _log.info("prase template: #{template_path}") + _log.debug("prase template: #{template_path}") encoded_zip_file = encoded_zip_from_directory(template_path) - # TODO: use tags,env_vars payload = { :templateZipFile => encoded_zip_file, } @@ -203,8 +203,9 @@ def template_variables( "api/template/variables", *json_post_arguments(payload) ) + _log.debug("==== http_response.body: \n #{http_response.body}") - Terraform::Runner::VariablesResponse.parsed_response(http_response) + JSON.parse(http_response.body) end def jwt_token diff --git a/lib/terraform/runner/variables_response.rb b/lib/terraform/runner/variables_response.rb deleted file mode 100644 index b36525ad..00000000 --- a/lib/terraform/runner/variables_response.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'json' - -module Terraform - class Runner - # Response object designed for holding full response from terraform-runner api/template/variables - class VariablesResponse - include Vmdb::Logging - - attr_reader :template_input_params, :template_output_params, :terraform_version - - # @return [String] Extracted attributes from the JSON response body object - def self.parsed_response(http_response) - data = JSON.parse(http_response.body) - _log.debug("data : #{data}") - Terraform::Runner::VariablesResponse.new( - :template_input_params => data['template_input_params'], - :template_output_params => data['template_output_params'], - :terraform_version => data['terraform_version'] - ) - end - - def initialize(template_input_params: nil, template_output_params: nil, terraform_version: nil) - @template_input_params = template_input_params - @template_output_params = template_output_params - @terraform_version = terraform_version - end - end - end -end diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index cf8ccce5..62e2e9e2 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -379,8 +379,9 @@ def verify_req(req) response = Terraform::Runner.parse_template_variables(File.join(__dir__, "runner/data/hello-world")) expect(template_variables_stub).to(have_been_requested.times(1)) - expect(response.template_input_params.length).to(eq(1)) - expect(response.template_input_params.first).to be_kind_of(Hash).and include( + template_input_params = response['template_input_params'] + expect(template_input_params.length).to(eq(1)) + expect(template_input_params.first).to be_kind_of(Hash).and include( "name" => "name", "label" => "name", "type" => "string", @@ -392,14 +393,18 @@ def verify_req(req) "default" => "World" ) - expect(response.template_output_params.length).to(eq(1)) - expect(response.template_output_params.first).to be_kind_of(Hash).and include( + template_output_params = response['template_output_params'] + expect(template_output_params.length).to(eq(1)) + expect(template_output_params.first).to be_kind_of(Hash).and include( "name" => "greeting", "label" => "greeting", "description" => "", "secured" => false, "hidden" => false ) + + terraform_version = response['terraform_version'] + expect(terraform_version).to eq('>= 1.1.0') end end end From 6431953f650837e207b1c2c9f897bd13805c5186 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Thu, 26 Sep 2024 14:25:01 +0530 Subject: [PATCH 17/27] minor - code formating & remove unused method --- .../dialog/terraform_template_service_dialog.rb | 2 +- .../automation_manager/template.rb | 2 +- app/models/service_template_terraform_template.rb | 12 ++++-------- lib/terraform/runner.rb | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/app/models/dialog/terraform_template_service_dialog.rb b/app/models/dialog/terraform_template_service_dialog.rb index 5e087590..e5daf79e 100644 --- a/app/models/dialog/terraform_template_service_dialog.rb +++ b/app/models/dialog/terraform_template_service_dialog.rb @@ -68,7 +68,7 @@ def add_variable_field(key, value, group, position, label, description, required group.dialog_fields.build( :type => "DialogFieldTextBox", - :name => "#{key}", + :name => key.to_s, :data_type => "string", :display => "edit", :required => required, diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/template.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/template.rb index 51ebaeac..b7df59f0 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/template.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/template.rb @@ -2,7 +2,7 @@ class ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Template < Mana has_many :stacks, :class_name => "ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Stack", :foreign_key => :configuration_script_base_id, :inverse_of => :configuration_script_payload, :dependent => :nullify def run(vars = {}, _userid = nil) - env_vars = vars.delete(:env) || {} + env_vars = vars.delete(:env) || {} credentials = vars.delete(:credentials) self.class.module_parent::Job.create_job(self, env_vars, vars, credentials).tap(&:signal_start) diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index bc76c101..04f6c875 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -47,18 +47,18 @@ def terraform_template(action) def create_dialogs(config_info) dialog_hash = {} - + info = config_info[:provision] - if info + if info # create new dialog, if required for :provision action if info.key?(:new_dialog_name) && !info.key?(:dialog_id) - provision_dialog_id = create_new_dialog(info[:new_dialog_name], template = terraform_template(:provision), info[:extra_vars]).id + provision_dialog_id = create_new_dialog(info[:new_dialog_name], terraform_template(:provision), info[:extra_vars]).id dialog_hash[:provision] = {:dialog_id => provision_dialog_id} else provision_dialog_id = info[:dialog_id] end - # For :retirement & :reconfigure, we use the same dialog as in :provision action + # For :retirement & :reconfigure, we use the same dialog as in :provision action dialog_hash = [:retirement, :reconfigure].each_with_object(dialog_hash) do |action, hash| hash[action] = {:dialog_id => :provision_dialog_id} end @@ -72,8 +72,4 @@ def create_dialogs(config_info) def create_new_dialog(dialog_name, terraform_template, extra_vars) Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, terraform_template, extra_vars) end - - def new_dialog_required?(info) - info && info.key?(:new_dialog_name) && !info.key?(:dialog_id) - end end diff --git a/lib/terraform/runner.rb b/lib/terraform/runner.rb index f99eb91c..e0d957da 100644 --- a/lib/terraform/runner.rb +++ b/lib/terraform/runner.rb @@ -59,7 +59,7 @@ def fetch_result_by_stack_id(stack_id) retrieve_stack_job(stack_id) end - # Parse Terraform Template input/output variables + # Parse Terraform Template input/output variables # @param template_path [String] Path to the template we will want to parse for input/output variables # @return Response(body) object of terraform-runner api/template/variables, # - the response object had template_input_params, template_output_params and terraform_version From a24a5f66d5f9b576999fdeb9bde531f9032be74f Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Thu, 26 Sep 2024 14:59:27 +0530 Subject: [PATCH 18/27] fix typo --- app/models/service_template_terraform_template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index 04f6c875..43e1a6b2 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -60,7 +60,7 @@ def create_dialogs(config_info) # For :retirement & :reconfigure, we use the same dialog as in :provision action dialog_hash = [:retirement, :reconfigure].each_with_object(dialog_hash) do |action, hash| - hash[action] = {:dialog_id => :provision_dialog_id} + hash[action] = {:dialog_id => provision_dialog_id} end end From 54446105e052fffaa3e9177fe737ee38ca10aefa Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Thu, 26 Sep 2024 15:36:18 +0530 Subject: [PATCH 19/27] code review : code improvement --- app/models/service_template_terraform_template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index 43e1a6b2..5030e6f6 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -19,7 +19,7 @@ def self.create_catalog_item(options, _auth_user) create_from_options(options).tap do |service_template| dialog_ids = service_template.send(:create_dialogs, config_info) config_info.deep_merge!(dialog_ids) - service_template.options[:config_info].deep_merge!(dialog_ids) + service_template.options[:config_info] = config_info service_template.create_resource_actions(config_info) end end From 4fe3adf60527209486f0a172c6f36345fb0a83c7 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Thu, 26 Sep 2024 19:03:28 +0530 Subject: [PATCH 20/27] add stub_request for terraform_runner:api/template/variables --- .../configuration_script_source_spec.rb | 59 ++++++++++++------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb index 18af050a..d124a42b 100644 --- a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb +++ b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb @@ -15,7 +15,21 @@ let(:repos) { Dir.glob(File.join(repo_dir, "*")) } let(:repo_dir_structure) { %w[hello_world.tf] } + def verify_req(req) + body = JSON.parse(req.body) + expect(body).to(have_key('templateZipFile')) + end + before do + ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" + @hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "../../../../../lib/terraform/runner/data/responses/hello-world-variables-success.json"))) + @template_variables_stub = stub_request(:post, "https://1.2.3.4:7000/api/template/variables") + .with { |req| verify_req(req) } + .to_return( + :status => 200, + :body => @hello_world_variables_response.to_json + ) + FileUtils.mkdir_p(local_repo) repo = Spec::Support::FakeTerraformRepo.new(local_repo, repo_dir_structure) @@ -85,10 +99,11 @@ def files_in_repository(git_repo_dir) expect(names.first).to(eq("/hello_world_local")) expected_hash = { - "relative_path" => File.dirname(*repo_dir_structure), - "files" => [File.basename(*repo_dir_structure)], - "input_vars" => nil, - "output_vars" => nil + "relative_path" => File.dirname(*repo_dir_structure), + "files" => [File.basename(*repo_dir_structure)], + "input_vars" => @hello_world_variables_response['template_input_params'], + "output_vars" => @hello_world_variables_response['template_output_params'], + "terraform_version" => @hello_world_variables_response['terraform_version'] } expect(payloads.first).to(eq(expected_hash.to_json)) @@ -117,10 +132,11 @@ def files_in_repository(git_repo_dir) expect(names.first).to(eq("templates/hello-world")) expected_hash = { - "relative_path" => File.dirname(*nested_repo_structure), - "files" => [File.basename(*nested_repo_structure)], - "input_vars" => nil, - "output_vars" => nil + "relative_path" => File.dirname(*nested_repo_structure), + "files" => [File.basename(*nested_repo_structure)], + "input_vars" => @hello_world_variables_response['template_input_params'], + "output_vars" => @hello_world_variables_response['template_output_params'], + "terraform_version" => @hello_world_variables_response['terraform_version'] } expect(payloads.first).to(eq(expected_hash.to_json)) @@ -174,17 +190,19 @@ def files_in_repository(git_repo_dir) ) expected_hash1 = { - "relative_path" => File.dirname(multiple_templates_repo_structure.first), - "files" => [File.basename(multiple_templates_repo_structure.first)], - "input_vars" => nil, - "output_vars" => nil + "relative_path" => File.dirname(multiple_templates_repo_structure.first), + "files" => [File.basename(multiple_templates_repo_structure.first)], + "input_vars" => @hello_world_variables_response['template_input_params'], + "output_vars" => @hello_world_variables_response['template_output_params'], + "terraform_version" => @hello_world_variables_response['terraform_version'] } expected_hash2 = { - "relative_path" => File.dirname(multiple_templates_repo_structure.second), - "files" => [File.basename(multiple_templates_repo_structure.second)], - "input_vars" => nil, - "output_vars" => nil + "relative_path" => File.dirname(multiple_templates_repo_structure.second), + "files" => [File.basename(multiple_templates_repo_structure.second)], + "input_vars" => @hello_world_variables_response['template_input_params'], + "output_vars" => @hello_world_variables_response['template_output_params'], + "terraform_version" => @hello_world_variables_response['terraform_version'] } expect(payloads).to(match_array([expected_hash1.to_json, expected_hash2.to_json])) @@ -282,10 +300,11 @@ def files_in_repository(git_repo_dir) expect(names.first).to(eq("/hello_world_local")) expected_hash = { - "relative_path" => File.dirname(*repo_dir_structure), - "files" => [File.basename(*repo_dir_structure)], - "input_vars" => nil, - "output_vars" => nil + "relative_path" => File.dirname(*repo_dir_structure), + "files" => [File.basename(*repo_dir_structure)], + "input_vars" => @hello_world_variables_response['template_input_params'], + "output_vars" => @hello_world_variables_response['template_output_params'], + "terraform_version" => @hello_world_variables_response['terraform_version'] } expect(payloads.first).to(eq(expected_hash.to_json)) From f965829aced449559acf87233b100ac179f36d8a Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Thu, 26 Sep 2024 19:37:12 +0530 Subject: [PATCH 21/27] code review fix: don't need instance variables --- spec/lib/terraform/runner_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index 62e2e9e2..efb44fbe 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -365,13 +365,13 @@ def verify_req(req) before do ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - @hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-variables-success.json"))) + hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-variables-success.json"))) template_variables_stub = stub_request(:post, "https://1.2.3.4:7000/api/template/variables") .with { |req| verify_req(req) } .to_return( :status => 200, - :body => @hello_world_variables_response.to_json + :body => hello_world_variables_response.to_json ) end From 180af2ce7a1a644a08e3e8284becc1634a0ee4dc Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Fri, 27 Sep 2024 12:22:45 +0530 Subject: [PATCH 22/27] no rm dir requried, if git_checkout_tempdir is nil --- .../automation_manager/configuration_script_source.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb index 505459ed..862a84b1 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb @@ -129,6 +129,8 @@ def checkout_git_repo # clean temp dir def cleanup_git_repo(git_checkout_tempdir) + return if git_checkout_tempdir.nil? + _log.debug("Cleaning up git repository checked out at #{git_checkout_tempdir}...") FileUtils.rm_rf(git_checkout_tempdir) rescue Errno::ENOENT From 82b609588b3c680067be734d365fc293eb8a6047 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Fri, 27 Sep 2024 12:26:54 +0530 Subject: [PATCH 23/27] minor - just raise is enough --- .../automation_manager/configuration_script_source.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb index 862a84b1..77f452ca 100644 --- a/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb +++ b/app/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source.rb @@ -37,7 +37,7 @@ def sync update!(:status => "successful", :last_updated_on => Time.zone.now, :last_update_error => nil) rescue => error update!(:status => "error", :last_updated_on => Time.zone.now, :last_update_error => error) - raise error + raise end # Return Template name, using relative_path's basename prefix, @@ -107,7 +107,7 @@ def find_templates_in_git_repo template_dirs rescue => error _log.error("Failing scaning for terraform templates in the git repo: #{error}") - raise error + raise ensure cleanup_git_repo(git_checkout_tempdir) end From 9d0748cd721fa61044b129b8b73d6440ede55c11 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Fri, 27 Sep 2024 14:27:06 +0530 Subject: [PATCH 24/27] stub ENV var TERRAFORM_RUNNER_URL in spec --- spec/lib/terraform/runner_spec.rb | 41 +++++++------------ .../configuration_script_source_spec.rb | 18 ++++---- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index efb44fbe..b03bdd46 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -1,12 +1,15 @@ require 'webmock/rspec' require 'json' +TERRAFORM_RUNNER_URL = "https://1.2.3.4:7000".freeze + RSpec.describe(Terraform::Runner) do let(:embedded_terraform) { ManageIQ::Providers::EmbeddedTerraform::AutomationManager } let(:manager) { FactoryBot.create(:embedded_automation_manager_terraform) } - before(:all) do - ENV["TERRAFORM_RUNNER_TOKEN"] = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNodWJoYW5naSBTaW5naCIsImlhdCI6MTcwNjAwMDk0M30.46mL8RRxfHI4yveZ2wTsHyF7s2BAiU84aruHBoz2JRQ' + before do + stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => TERRAFORM_RUNNER_URL)) + @hello_world_create_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-create-success.json"))) @hello_world_retrieve_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-retrieve-success.json"))) end @@ -17,9 +20,7 @@ describe "is .available" do before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - - stub_request(:get, "https://1.2.3.4:7000/ping") + stub_request(:get, "#{TERRAFORM_RUNNER_URL}/ping") .to_return(:status => 200, :body => {'count' => 0}.to_json) end @@ -42,16 +43,14 @@ def verify_req(req) end before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - - create_stub = stub_request(:post, "https://1.2.3.4:7000/api/stack/create") + create_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") .with { |req| verify_req(req) } .to_return( :status => 200, :body => @hello_world_create_response.to_json ) - retrieve_stub = stub_request(:post, "https://1.2.3.4:7000/api/stack/retrieve") + retrieve_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/retrieve") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -100,9 +99,7 @@ def verify_req(req) retrieve_stub = nil before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - - retrieve_stub = stub_request(:post, "https://1.2.3.4:7000/api/stack/retrieve") + retrieve_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/retrieve") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -131,9 +128,7 @@ def verify_req(req) cancel_stub = nil before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - - create_stub = stub_request(:post, "https://1.2.3.4:7000/api/stack/create") + create_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") .with(:body => hash_including({:parameters => [], :cloud_providers => []})) .to_return( :status => 200, @@ -143,7 +138,7 @@ def verify_req(req) cancel_response = @hello_world_create_response.clone cancel_response[:status] = 'CANCELLED' - retrieve_stub = stub_request(:post, "https://1.2.3.4:7000/api/stack/retrieve") + retrieve_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/retrieve") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -155,7 +150,7 @@ def verify_req(req) :status => 200, :body => cancel_response.to_json ) - cancel_stub = stub_request(:post, "https://1.2.3.4:7000/api/stack/cancel") + cancel_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/cancel") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -245,10 +240,8 @@ def verify_req(req) create_stub = nil before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - create_stub = - stub_request(:post, "https://1.2.3.4:7000/api/stack/create") + stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") .with { |req| verify_req(req) } .to_return( :status => 200, @@ -329,10 +322,8 @@ def verify_req(req) create_stub = nil before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - create_stub = - stub_request(:post, "https://1.2.3.4:7000/api/stack/create") + stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") .with { |req| verify_req(req) } .to_return( :status => 200, @@ -363,11 +354,9 @@ def verify_req(req) end before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" - hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-variables-success.json"))) - template_variables_stub = stub_request(:post, "https://1.2.3.4:7000/api/template/variables") + template_variables_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/template/variables") .with { |req| verify_req(req) } .to_return( :status => 200, diff --git a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb index d124a42b..8fec7c21 100644 --- a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb +++ b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb @@ -1,3 +1,5 @@ +TERRAFORM_RUNNER_URL = 'https://1.2.3.4:7000'.freeze + RSpec.describe(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptSource) do context "with a local repo" do let(:manager) { FactoryBot.create(:embedded_automation_manager_terraform) } @@ -21,14 +23,16 @@ def verify_req(req) end before do - ENV["TERRAFORM_RUNNER_URL"] = "https://1.2.3.4:7000" @hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "../../../../../lib/terraform/runner/data/responses/hello-world-variables-success.json"))) - @template_variables_stub = stub_request(:post, "https://1.2.3.4:7000/api/template/variables") - .with { |req| verify_req(req) } - .to_return( - :status => 200, - :body => @hello_world_variables_response.to_json - ) + + stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => TERRAFORM_RUNNER_URL)) + + stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/template/variables") + .with { |req| verify_req(req) } + .to_return( + :status => 200, + :body => @hello_world_variables_response.to_json + ) FileUtils.mkdir_p(local_repo) From 8945d559eb11a87ab0aabc44ab5692f2543f4868 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Fri, 27 Sep 2024 15:00:03 +0530 Subject: [PATCH 25/27] fix for review comments --- .../configuration_script_source_spec.rb | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb index 8fec7c21..cb8d48f2 100644 --- a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb +++ b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb @@ -17,21 +17,23 @@ let(:repos) { Dir.glob(File.join(repo_dir, "*")) } let(:repo_dir_structure) { %w[hello_world.tf] } + let(:hello_world_vars_response) do + JSON.parse(File.read(File.join(__dir__, "../../../../../lib/terraform/runner/data/responses/hello-world-variables-success.json"))) + end + def verify_req(req) body = JSON.parse(req.body) expect(body).to(have_key('templateZipFile')) end before do - @hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "../../../../../lib/terraform/runner/data/responses/hello-world-variables-success.json"))) - stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => TERRAFORM_RUNNER_URL)) stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/template/variables") .with { |req| verify_req(req) } .to_return( :status => 200, - :body => @hello_world_variables_response.to_json + :body => hello_world_vars_response.to_json ) FileUtils.mkdir_p(local_repo) @@ -105,9 +107,9 @@ def files_in_repository(git_repo_dir) expected_hash = { "relative_path" => File.dirname(*repo_dir_structure), "files" => [File.basename(*repo_dir_structure)], - "input_vars" => @hello_world_variables_response['template_input_params'], - "output_vars" => @hello_world_variables_response['template_output_params'], - "terraform_version" => @hello_world_variables_response['terraform_version'] + "input_vars" => hello_world_vars_response['template_input_params'], + "output_vars" => hello_world_vars_response['template_output_params'], + "terraform_version" => hello_world_vars_response['terraform_version'] } expect(payloads.first).to(eq(expected_hash.to_json)) @@ -138,9 +140,9 @@ def files_in_repository(git_repo_dir) expected_hash = { "relative_path" => File.dirname(*nested_repo_structure), "files" => [File.basename(*nested_repo_structure)], - "input_vars" => @hello_world_variables_response['template_input_params'], - "output_vars" => @hello_world_variables_response['template_output_params'], - "terraform_version" => @hello_world_variables_response['terraform_version'] + "input_vars" => hello_world_vars_response['template_input_params'], + "output_vars" => hello_world_vars_response['template_output_params'], + "terraform_version" => hello_world_vars_response['terraform_version'] } expect(payloads.first).to(eq(expected_hash.to_json)) @@ -196,17 +198,17 @@ def files_in_repository(git_repo_dir) expected_hash1 = { "relative_path" => File.dirname(multiple_templates_repo_structure.first), "files" => [File.basename(multiple_templates_repo_structure.first)], - "input_vars" => @hello_world_variables_response['template_input_params'], - "output_vars" => @hello_world_variables_response['template_output_params'], - "terraform_version" => @hello_world_variables_response['terraform_version'] + "input_vars" => hello_world_vars_response['template_input_params'], + "output_vars" => hello_world_vars_response['template_output_params'], + "terraform_version" => hello_world_vars_response['terraform_version'] } expected_hash2 = { "relative_path" => File.dirname(multiple_templates_repo_structure.second), "files" => [File.basename(multiple_templates_repo_structure.second)], - "input_vars" => @hello_world_variables_response['template_input_params'], - "output_vars" => @hello_world_variables_response['template_output_params'], - "terraform_version" => @hello_world_variables_response['terraform_version'] + "input_vars" => hello_world_vars_response['template_input_params'], + "output_vars" => hello_world_vars_response['template_output_params'], + "terraform_version" => hello_world_vars_response['terraform_version'] } expect(payloads).to(match_array([expected_hash1.to_json, expected_hash2.to_json])) @@ -306,9 +308,9 @@ def files_in_repository(git_repo_dir) expected_hash = { "relative_path" => File.dirname(*repo_dir_structure), "files" => [File.basename(*repo_dir_structure)], - "input_vars" => @hello_world_variables_response['template_input_params'], - "output_vars" => @hello_world_variables_response['template_output_params'], - "terraform_version" => @hello_world_variables_response['terraform_version'] + "input_vars" => hello_world_vars_response['template_input_params'], + "output_vars" => hello_world_vars_response['template_output_params'], + "terraform_version" => hello_world_vars_response['terraform_version'] } expect(payloads.first).to(eq(expected_hash.to_json)) From aacd630ce451e8fbc2e15a8c3126b87f9f152bbb Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Mon, 30 Sep 2024 20:32:42 +0530 Subject: [PATCH 26/27] add support to update catalog item --- .../service_template_terraform_template.rb | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/models/service_template_terraform_template.rb b/app/models/service_template_terraform_template.rb index 5030e6f6..8bd25e44 100644 --- a/app/models/service_template_terraform_template.rb +++ b/app/models/service_template_terraform_template.rb @@ -25,6 +25,20 @@ def self.create_catalog_item(options, _auth_user) end end + def update_catalog_item(options, auth_user = nil) + config_info = validate_update_config_info(options) + unless config_info + update!(options) + return reload + end + + config_info.deep_merge!(create_dialogs(config_info)) + + options[:config_info] = config_info + + super + end + def self.validate_config_info(info) info[:provision][:fqname] ||= default_provisioning_entry_point(SERVICE_TYPE_ATOMIC) if info.key?(:provision) info[:reconfigure][:fqname] ||= default_reconfiguration_entry_point if info.key?(:reconfigure) @@ -72,4 +86,11 @@ def create_dialogs(config_info) def create_new_dialog(dialog_name, terraform_template, extra_vars) Dialog::TerraformTemplateServiceDialog.create_dialog(dialog_name, terraform_template, extra_vars) end + + def validate_update_config_info(options) + opts = super + return unless options.key?(:config_info) + + self.class.send(:validate_config_info, opts) + end end From 9719425764f48b50cde889b5a901b0d2cb6e1fa7 Mon Sep 17 00:00:00 2001 From: MANOJ PUTHRAN Date: Tue, 1 Oct 2024 11:26:51 +0530 Subject: [PATCH 27/27] instead of global constant use let defination within test --- spec/lib/terraform/runner_spec.rb | 26 +++++++++---------- .../configuration_script_source_spec.rb | 8 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/spec/lib/terraform/runner_spec.rb b/spec/lib/terraform/runner_spec.rb index b03bdd46..3a693420 100644 --- a/spec/lib/terraform/runner_spec.rb +++ b/spec/lib/terraform/runner_spec.rb @@ -1,14 +1,14 @@ require 'webmock/rspec' require 'json' -TERRAFORM_RUNNER_URL = "https://1.2.3.4:7000".freeze - RSpec.describe(Terraform::Runner) do + let(:terraform_runner_url) { "https://1.2.3.4:7000" } + let(:embedded_terraform) { ManageIQ::Providers::EmbeddedTerraform::AutomationManager } let(:manager) { FactoryBot.create(:embedded_automation_manager_terraform) } before do - stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => TERRAFORM_RUNNER_URL)) + stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => terraform_runner_url)) @hello_world_create_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-create-success.json"))) @hello_world_retrieve_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-retrieve-success.json"))) @@ -20,7 +20,7 @@ describe "is .available" do before do - stub_request(:get, "#{TERRAFORM_RUNNER_URL}/ping") + stub_request(:get, "#{terraform_runner_url}/ping") .to_return(:status => 200, :body => {'count' => 0}.to_json) end @@ -43,14 +43,14 @@ def verify_req(req) end before do - create_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") + create_stub = stub_request(:post, "#{terraform_runner_url}/api/stack/create") .with { |req| verify_req(req) } .to_return( :status => 200, :body => @hello_world_create_response.to_json ) - retrieve_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/retrieve") + retrieve_stub = stub_request(:post, "#{terraform_runner_url}/api/stack/retrieve") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -99,7 +99,7 @@ def verify_req(req) retrieve_stub = nil before do - retrieve_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/retrieve") + retrieve_stub = stub_request(:post, "#{terraform_runner_url}/api/stack/retrieve") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -128,7 +128,7 @@ def verify_req(req) cancel_stub = nil before do - create_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") + create_stub = stub_request(:post, "#{terraform_runner_url}/api/stack/create") .with(:body => hash_including({:parameters => [], :cloud_providers => []})) .to_return( :status => 200, @@ -138,7 +138,7 @@ def verify_req(req) cancel_response = @hello_world_create_response.clone cancel_response[:status] = 'CANCELLED' - retrieve_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/retrieve") + retrieve_stub = stub_request(:post, "#{terraform_runner_url}/api/stack/retrieve") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -150,7 +150,7 @@ def verify_req(req) :status => 200, :body => cancel_response.to_json ) - cancel_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/cancel") + cancel_stub = stub_request(:post, "#{terraform_runner_url}/api/stack/cancel") .with(:body => hash_including({:stack_id => @hello_world_retrieve_response['stack_id']})) .to_return( :status => 200, @@ -241,7 +241,7 @@ def verify_req(req) before do create_stub = - stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") + stub_request(:post, "#{terraform_runner_url}/api/stack/create") .with { |req| verify_req(req) } .to_return( :status => 200, @@ -323,7 +323,7 @@ def verify_req(req) before do create_stub = - stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/stack/create") + stub_request(:post, "#{terraform_runner_url}/api/stack/create") .with { |req| verify_req(req) } .to_return( :status => 200, @@ -356,7 +356,7 @@ def verify_req(req) before do hello_world_variables_response = JSON.parse(File.read(File.join(__dir__, "runner/data/responses/hello-world-variables-success.json"))) - template_variables_stub = stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/template/variables") + template_variables_stub = stub_request(:post, "#{terraform_runner_url}/api/template/variables") .with { |req| verify_req(req) } .to_return( :status => 200, diff --git a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb index cb8d48f2..046e1639 100644 --- a/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb +++ b/spec/models/manageiq/providers/embedded_terraform/automation_manager/configuration_script_source_spec.rb @@ -1,6 +1,6 @@ -TERRAFORM_RUNNER_URL = 'https://1.2.3.4:7000'.freeze - RSpec.describe(ManageIQ::Providers::EmbeddedTerraform::AutomationManager::ConfigurationScriptSource) do + let(:terraform_runner_url) { "https://1.2.3.4:7000" } + context "with a local repo" do let(:manager) { FactoryBot.create(:embedded_automation_manager_terraform) } @@ -27,9 +27,9 @@ def verify_req(req) end before do - stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => TERRAFORM_RUNNER_URL)) + stub_const("ENV", ENV.to_h.merge("TERRAFORM_RUNNER_URL" => terraform_runner_url)) - stub_request(:post, "#{TERRAFORM_RUNNER_URL}/api/template/variables") + stub_request(:post, "#{terraform_runner_url}/api/template/variables") .with { |req| verify_req(req) } .to_return( :status => 200,