diff --git a/.eslintrc b/.eslintrc index 0de7f9bd00b..1b3658bc274 100644 --- a/.eslintrc +++ b/.eslintrc @@ -182,6 +182,7 @@ "vnc", "vnic", "webpack", + "wget", "wss", "x86_64", "xml", diff --git a/app/controllers/api/v2/registration_commands_controller.rb b/app/controllers/api/v2/registration_commands_controller.rb index 3fa023dca4d..be782d7e14a 100644 --- a/app/controllers/api/v2/registration_commands_controller.rb +++ b/app/controllers/api/v2/registration_commands_controller.rb @@ -15,7 +15,7 @@ class RegistrationCommandsController < V2::BaseController param :setup_insights, :bool, desc: N_("Set 'host_registration_insights' parameter for the host. If it is set to true, insights client will be installed and registered on Red Hat family operating systems") param :setup_remote_execution, :bool, desc: N_("Set 'host_registration_remote_execution' parameter for the host. If it is set to true, SSH keys will be installed on the host") param :jwt_expiration, :number, desc: N_("Expiration of the authorization token (in hours), 0 means 'unlimited'.") - param :insecure, :bool, desc: N_("Enable insecure argument for the initial curl") + param :insecure, :bool, desc: N_("Enable insecure argument for the initial curl/wget") param :packages, String, desc: N_("Packages to install on the host when registered. Can be set by `host_packages` parameter, example: `pkg1 pkg2`") param :update_packages, :bool, desc: N_("Update all packages on the host") param :repo, String, desc: N_("DEPRECATED, use the `repo_data` param instead."), deprecated: true @@ -25,6 +25,7 @@ class RegistrationCommandsController < V2::BaseController param :repo, String, desc: N_("Repository URL / details, for example, for Debian OS family: 'deb http://deb.example.com/ buster 1.0', for Red Hat and SUSE OS family: 'http://yum.theforeman.org/client/latest/el8/x86_64/'") param :repo_gpg_key_url, String, desc: N_("URL of the GPG key for the repository") end + param :download_utility, ["curl", "wget"], desc: N_("The download utility to use during host registration") end def create unless os_with_template? diff --git a/app/controllers/api/v2/registration_controller.rb b/app/controllers/api/v2/registration_controller.rb index 2c8bd987242..9a5c750759d 100644 --- a/app/controllers/api/v2/registration_controller.rb +++ b/app/controllers/api/v2/registration_controller.rb @@ -30,6 +30,7 @@ class RegistrationController < V2::BaseController param :repo, String, desc: N_("Repository URL / details, for example, for Debian OS family: 'deb http://deb.example.com/ buster 1.0', for Red Hat OS family: 'http://yum.theforeman.org/client/latest/el8/x86_64/'") param :repo_gpg_key_url, String, desc: N_("URL of the GPG key for the repository") end + param :download_utility, ["curl", "wget"], desc: N_("The download utility to use during host registration") def global find_global_registration diff --git a/app/controllers/concerns/foreman/controller/registration.rb b/app/controllers/concerns/foreman/controller/registration.rb index 9412473a9c0..03d7b2dbff0 100644 --- a/app/controllers/concerns/foreman/controller/registration.rb +++ b/app/controllers/concerns/foreman/controller/registration.rb @@ -41,6 +41,7 @@ def global_registration_vars packages: params['packages'], update_packages: params['update_packages'], repo_data: repo_data, + download_utility: params['download_utility'], } params.permit(permitted) diff --git a/app/controllers/concerns/foreman/controller/registration_commands.rb b/app/controllers/concerns/foreman/controller/registration_commands.rb index 6c002096a3c..a2fcccc9796 100644 --- a/app/controllers/concerns/foreman/controller/registration_commands.rb +++ b/app/controllers/concerns/foreman/controller/registration_commands.rb @@ -9,7 +9,7 @@ module Foreman::Controller::RegistrationCommands def command args_query = "?#{registration_args.to_query}" - "set -o pipefail && curl -sS #{insecure} '#{registration_url(@smart_proxy)}#{args_query if args_query != '?'}' #{command_headers} | bash" + "set -o pipefail && #{utility[:download_command]} #{utility[:output_pipe]} #{insecure} '#{registration_url(@smart_proxy)}#{args_query if args_query != '?'}' #{command_headers} | bash" end def registration_args @@ -19,8 +19,12 @@ def registration_args .permit! end + def utility + Foreman.download_utilities.fetch(registration_params['download_utility'] || 'curl') + end + def insecure - registration_params['insecure'] ? '--insecure' : '' + registration_params['insecure'] ? utility[:insecure] : '' end def registration_url(proxy = nil) @@ -65,7 +69,7 @@ def command_headers else invalid_expiration_error end - "-H 'Authorization: Bearer #{User.current.jwt_token!(**jwt_args)}'" + "--header 'Authorization: Bearer #{User.current.jwt_token!(**jwt_args)}'" end def host_config_params diff --git a/app/services/foreman/renderer/configuration.rb b/app/services/foreman/renderer/configuration.rb index b86b0213ebf..42f08623a9a 100644 --- a/app/services/foreman/renderer/configuration.rb +++ b/app/services/foreman/renderer/configuration.rb @@ -80,7 +80,8 @@ class Configuration :host_puppet_environment, :host_enc, :install_packages, - :update_packages + :update_packages, + :generate_web_request ] DEFAULT_ALLOWED_VARIABLES = [ diff --git a/app/services/foreman/renderer/scope/macros/helpers.rb b/app/services/foreman/renderer/scope/macros/helpers.rb index 1d4cf589bfc..837541b9295 100644 --- a/app/services/foreman/renderer/scope/macros/helpers.rb +++ b/app/services/foreman/renderer/scope/macros/helpers.rb @@ -155,6 +155,32 @@ def truthy?(value = nil) def falsy?(value = nil) Foreman::Cast.to_bool(value) == false end + + apipie :method, 'Generate a web request' do + keyword :utility, String, desc: 'The utility to use for the web request ("curl" or "wget").' + keyword :url, String, desc: 'The URL for the web request.' + keyword :ssl_ca_cert, String, desc: 'The path to the SSL certificate.', default: nil + keyword :headers, Array, of: String, desc: 'Array containing the headers for the web request starting with "--header".', default: nil + keyword :params, Array, of: String, desc: 'Array containing the POST parameters for the web request.', default: nil + keyword :output_file, String, desc: 'The path were the result of the web request will be stored.', default: nil + returns String, desc: 'The web request.' + example 'generate_web_request(utility: "curl", url: "https://www.example.com/register", ssl_ca_cert: "/etc/ssl/custom_certs/ca_cert.crt", headers: ["--header \'Authorization: Bearer \'"], params: ["host[build]=false", "host[organization_id]=1"])' + example 'generate_web_request(utility: "curl", url: "https://www.example.com/keys/client.asc", output_file: "/etc/apt/trusted.gpg.d/client1.asc")' + end + def generate_web_request(utility:, url:, ssl_ca_cert: nil, headers: nil, params: nil, output_file: nil) + utility = Foreman.download_utilities.fetch(utility || 'curl') + command = ["#{utility[:download_command]} #{url}"] + command << "#{utility[:ca_cert]} #{ssl_ca_cert}" if ssl_ca_cert + command << utility[:request_type_post] if params && utility[:request_type_post] + if output_file + command << "#{utility[:output_file]} #{output_file}" + elsif utility[:output_pipe] + command << utility[:output_pipe] + end + headers&.each { |header| command << header } + utility[:format_params].call(params).each { |param| command << param } if params + command.join(" \\\n ") + end end end end diff --git a/app/services/foreman/template_snapshot_service.rb b/app/services/foreman/template_snapshot_service.rb index 01ac0e9b3a5..2edff12c8e9 100644 --- a/app/services/foreman/template_snapshot_service.rb +++ b/app/services/foreman/template_snapshot_service.rb @@ -54,6 +54,10 @@ def self.windows10_dhcp new.windows10_dhcp end + def self.registration_template + new.registration_template + end + def self.render_template(template, host_name = :host4dhcp) host_stub = send(host_name.to_sym) source = Foreman::Renderer::Source::Snapshot.new(template) @@ -217,6 +221,17 @@ def windows10_dhcp define_host_params(host) end + def registration_template + Setting[:server_ca_file] = Rails.root.join('test/static_fixtures/certificates/example.com.crt') + Setting[:ssl_ca_file] = Rails.root.join('test/static_fixtures/certificates/example2.com.crt') + + host = FactoryBot.build(:host_for_snapshots_ipv4_dhcp_rocky9, + name: 'snapshot-ipv4-dhcp-rocky9', + subnet: FactoryBot.build(:subnet_ipv4_dhcp_for_snapshots), + interfaces: [ipv4_interface]) + define_host_params(host) + end + private def files diff --git a/app/views/unattended/provisioning_templates/registration/global_registration.erb b/app/views/unattended/provisioning_templates/registration/global_registration.erb index 973f1156c88..a13cc9d31bc 100644 --- a/app/views/unattended/provisioning_templates/registration/global_registration.erb +++ b/app/views/unattended/provisioning_templates/registration/global_registration.erb @@ -2,6 +2,8 @@ kind: registration name: Global Registration model: ProvisioningTemplate +test_on: +- registration_template description: | The registration template used to render OS agnostic script that any host can use to register to this Foreman instance. It is rendered as a response in the registration API endpoint. The resulting @@ -14,7 +16,7 @@ description: | # Make sure, all command output can be parsed (e.g. from subscription-manager) export LC_ALL=C LANG=C <% - headers = ["-H 'Authorization: Bearer #{@auth_token}'"] + headers = ["--header 'Authorization: Bearer #{@auth_token}'"] activation_keys = [(@hostgroup.params['kt_activation_keys'] if @hostgroup), @activation_keys].compact.join(',') -%> @@ -35,6 +37,7 @@ export LC_ALL=C LANG=C <%= "\n# Ignore subman errors: [#{@ignore_subman_errors}]" unless @ignore_subman_errors.nil? -%> <%= "\n# Lifecycle environment id: [#{@lifecycle_environment_id}]" if @lifecycle_environment_id.present? -%> <%= "\n# Activation keys: [#{activation_keys}]" if activation_keys.present? -%> +<%= "\n# Download utility: [#{@download_utility}]" unless @download_utility.nil? -%> if ! [ $(id -u) = 0 ]; then @@ -91,11 +94,11 @@ elif [ -f /etc/debian_version ]; then <% if repo_gpg_key_url.present? -%> <%# "apt 1.2.35" on Ubuntu 16.04 does not support storing GPG public keys in "/etc/apt/trusted.gpg.d/" in ASCII format -%> if [ "$(. /etc/os-release ; echo "$VERSION_ID")" = "16.04" ]; then - $PKG_MANAGER_INSTALL ca-certificates curl gnupg - curl --silent --show-error <%= shell_escape repo_gpg_key_url %> | gpg --dearmor > /etc/apt/trusted.gpg.d/client<%= index %>.gpg + $PKG_MANAGER_INSTALL ca-certificates gnupg + <%= indent(4, skip1: true) { generate_web_request(utility: @download_utility, url: shell_escape(repo_gpg_key_url)) } %> | gpg --dearmor > /etc/apt/trusted.gpg.d/client<%= index %>.gpg else - $PKG_MANAGER_INSTALL ca-certificates curl - curl --silent --show-error --output /etc/apt/trusted.gpg.d/client<%= index %>.asc <%= shell_escape repo_gpg_key_url %> + $PKG_MANAGER_INSTALL ca-certificates + <%= indent(4, skip1: true) { generate_web_request(utility: @download_utility, url: shell_escape(repo_gpg_key_url), output_file: "/etc/apt/trusted.gpg.d/client#{index}.asc") } %> fi <% end -%> apt-get update @@ -108,22 +111,22 @@ fi <% end -%> register_host() { - curl --silent --show-error --cacert $SSL_CA_CERT --request POST <%= @registration_url %> \ - <%= headers.join(' ') %> \ - --data "host[name]=$(hostname --fqdn)" \ - --data "host[build]=false" \ - --data "host[managed]=false" \ -<%= " --data 'host[organization_id]=#{@organization.id}' \\\n" if @organization -%> -<%= " --data 'host[location_id]=#{@location.id}' \\\n" if @location -%> -<%= " --data 'host[hostgroup_id]=#{@hostgroup.id}' \\\n" if @hostgroup -%> -<%= " --data 'host[operatingsystem_id]=#{@operatingsystem.id}' \\\n" if @operatingsystem -%> -<%= " --data host[interfaces_attributes][0][identifier]=#{shell_escape(@remote_execution_interface)} \\\n" if @remote_execution_interface.present? -%> -<%= " --data 'setup_insights=#{@setup_insights}' \\\n" unless @setup_insights.nil? -%> -<%= " --data 'setup_remote_execution=#{@setup_remote_execution}' \\\n" unless @setup_remote_execution.nil? -%> -<%= " --data remote_execution_interface=#{shell_escape(@remote_execution_interface)} \\\n" if @remote_execution_interface.present? -%> -<%= " --data packages=#{shell_escape(@packages)} \\\n" if @packages.present? -%> -<%= " --data 'update_packages=#{@update_packages}' \\\n" unless @update_packages.nil? -%> - +<% + params = ["host[name]=$(hostname --fqdn)"] + params << "host[build]=false" + params << "host[managed]=false" + params << "host[organization_id]=#{@organization.id}" if @organization + params << "host[location_id]=#{@location.id}" if @location + params << "host[hostgroup_id]=#{@hostgroup.id}" if @hostgroup + params << "host[operatingsystem_id]=#{@operatingsystem.id}" if @operatingsystem + params << "host[interfaces_attributes][0][identifier]=#{shell_escape(@remote_execution_interface)}" if @remote_execution_interface.present? + params << "setup_insights=#{@setup_insights}" unless @setup_insights.nil? + params << "setup_remote_execution=#{@setup_remote_execution}" unless @setup_remote_execution.nil? + params << "remote_execution_interface=#{shell_escape(@remote_execution_interface)}" if @remote_execution_interface.present? + params << "packages=#{shell_escape(@packages)}" if @packages.present? + params << "update_packages=#{@update_packages}" unless @update_packages.nil? +-%> + <%= indent(2, skip1: true) { generate_web_request(utility: @download_utility, url: @registration_url, ssl_ca_cert: "$SSL_CA_CERT", headers: headers, params: params) } %> } echo "#" @@ -132,22 +135,22 @@ echo "#" <% if plugin_present?('katello') && activation_keys.present? -%> register_katello_host(){ - UUID=$(subscription-manager identity | grep --max-count 1 --only-matching '\([[:xdigit:]]\{8\}-[[:xdigit:]]\{4\}-[[:xdigit:]]\{4\}-[[:xdigit:]]\{4\}-[[:xdigit:]]\{12\}\)') - curl --silent --show-error --cacert $KATELLO_SERVER_CA_CERT --request POST "<%= @registration_url %>" \ - <%= headers.join(' ') %> \ - --data "uuid=$UUID" \ - --data "host[build]=false" \ -<%= " --data 'host[organization_id]=#{@organization.id}' \\\n" if @organization -%> -<%= " --data 'host[location_id]=#{@location.id}' \\\n" if @location -%> -<%= " --data 'host[hostgroup_id]=#{@hostgroup.id}' \\\n" if @hostgroup -%> -<%= " --data 'host[lifecycle_environment_id]=#{@lifecycle_environment_id}' \\\n" if @lifecycle_environment_id.present? -%> -<%= " --data 'setup_insights=#{@setup_insights}' \\\n" unless @setup_insights.nil? -%> -<%= " --data 'setup_remote_execution=#{@setup_remote_execution}' \\\n" unless @setup_remote_execution.nil? -%> -<%= " --data remote_execution_interface=#{shell_escape(@remote_execution_interface)} \\\n" if @remote_execution_interface.present? -%> -<%= " --data 'setup_remote_execution_pull=#{@setup_remote_execution_pull}' \\\n" unless @setup_remote_execution_pull.nil? -%> -<%= " --data packages=#{shell_escape(@packages)} \\\n" if @packages.present? -%> -<%= " --data 'update_packages=#{@update_packages}' \\\n" unless @update_packages.nil? -%> - +<% + params = ["uuid=$UUID"] + params << "host[build]=false" + params << "host[organization_id]=#{@organization.id}" if @organization + params << "host[location_id]=#{@location.id}" if @location + params << "host[hostgroup_id]=#{@hostgroup.id}" if @hostgroup + params << "host[lifecycle_environment_id]=#{@lifecycle_environment_id}" if @lifecycle_environment_id.present? + params << "setup_insights=#{@setup_insights}" unless @setup_insights.nil? + params << "setup_remote_execution=#{@setup_remote_execution}" unless @setup_remote_execution.nil? + params << "remote_execution_interface=#{shell_escape(@remote_execution_interface)}" if @remote_execution_interface.present? + params << "setup_remote_execution_pull=#{@setup_remote_execution_pull}" unless @setup_remote_execution_pull.nil? + params << "packages=#{shell_escape(@packages)}" if @packages.present? + params << "update_packages=#{@update_packages}" unless @update_packages.nil? +-%> + UUID=$(subscription-manager identity | grep --max-count 1 --only-matching '\([[:xdigit:]]\{8\}-[[:xdigit:]]\{4\}-[[:xdigit:]]\{4\}-[[:xdigit:]]\{4\}-[[:xdigit:]]\{12\}\)') + <%= indent(2, skip1: true) { generate_web_request(utility: @download_utility, url: @registration_url, ssl_ca_cert: "$KATELLO_SERVER_CA_CERT", headers: headers, params: params) } %> } # Set up subscription-manager diff --git a/lib/foreman.rb b/lib/foreman.rb index ccb5e65b270..9b198790a6c 100644 --- a/lib/foreman.rb +++ b/lib/foreman.rb @@ -45,4 +45,25 @@ def self.input_types_registry def self.settings SettingRegistry.instance end + + def self.download_utilities + { + 'curl' => { + :ca_cert => '--cacert', + :download_command => 'curl --silent --show-error', + :insecure => '--insecure', + :output_file => '--output', + :request_type_post => '--request POST', + :format_params => proc { |params| params.map { |param| "--data #{param}" } }, + }, + 'wget' => { + :ca_cert => '--ca-certificate', + :download_command => 'wget --no-verbose --no-hsts', + :insecure => '--no-check-certificate', + :output_file => '--output-document', + :output_pipe => '--output-document -', + :format_params => proc { |params| ["--post-data #{params.join('\&')}"] }, + }, + }.freeze + end end diff --git a/test/controllers/api/v2/registration_commands_controller_test.rb b/test/controllers/api/v2/registration_commands_controller_test.rb index 52176a93ec0..94118ec81c7 100644 --- a/test/controllers/api/v2/registration_commands_controller_test.rb +++ b/test/controllers/api/v2/registration_commands_controller_test.rb @@ -7,8 +7,8 @@ class Api::V2::RegistrationCommandsControllerTest < ActionController::TestCase assert_response :success response = ActiveSupport::JSON.decode(@response.body)['registration_command'] - assert_includes response, "curl -sS 'http://test.host/register'" - assert_includes response, "-H 'Authorization: Bearer" + assert_includes response, "curl --silent --show-error 'http://test.host/register'" + assert_includes response, "--header 'Authorization: Bearer" end test 'with params' do @@ -50,7 +50,7 @@ class Api::V2::RegistrationCommandsControllerTest < ActionController::TestCase assert_response :success response = ActiveSupport::JSON.decode(@response.body)['registration_command'] - assert_includes response, "curl -sS --insecure '#{proxy.url}/register'" + assert_includes response, "curl --silent --show-error --insecure '#{proxy.url}/register'" end test 'os without host_init_config template' do @@ -65,5 +65,32 @@ class Api::V2::RegistrationCommandsControllerTest < ActionController::TestCase post :create, params: { smart_proxy_id: smart_proxies(:one).id } assert_response :unprocessable_entity end + + test 'using wget' do + params = { + download_utility: 'wget', + } + + post :create, params: params + assert_response :success + + response = ActiveSupport::JSON.decode(@response.body)['registration_command'] + assert_includes response, "wget --no-verbose --no-hsts --output-document - 'http://test.host/register?download_utility=wget'" + assert_includes response, "--header 'Authorization: Bearer" + end + + test 'using wget with insecure option' do + params = { + download_utility: 'wget', + insecure: true, + } + + post :create, params: params + assert_response :success + + response = ActiveSupport::JSON.decode(@response.body)['registration_command'] + assert_includes response, "wget --no-verbose --no-hsts --output-document - --no-check-certificate 'http://test.host/register?download_utility=wget'" + assert_includes response, "--header 'Authorization: Bearer" + end end end diff --git a/test/controllers/api/v2/registration_controller_test.rb b/test/controllers/api/v2/registration_controller_test.rb index 104d664f5a6..856a15189c9 100644 --- a/test/controllers/api/v2/registration_controller_test.rb +++ b/test/controllers/api/v2/registration_controller_test.rb @@ -26,6 +26,7 @@ class Api::V2::RegistrationControllerTest < ActionController::TestCase location_id: taxonomies(:location1).id, hostgroup_id: hostgroups(:common).id, operatingsystem_id: operatingsystems(:centos5_3).id, + download_utility: 'wget', } get :global, params: params, session: set_session_user @@ -38,6 +39,7 @@ class Api::V2::RegistrationControllerTest < ActionController::TestCase assert_equal operatingsystems(:centos5_3), vars[:operatingsystem] assert_equal users(:admin), vars[:user] assert_equal register_url, vars[:registration_url].to_s + assert_equal 'wget', vars[:download_utility].to_s end test "should not pass unpermitted params to template" do diff --git a/test/controllers/registration_commands_controller_test.rb b/test/controllers/registration_commands_controller_test.rb index cf8361d62b4..6cee1a94a46 100644 --- a/test/controllers/registration_commands_controller_test.rb +++ b/test/controllers/registration_commands_controller_test.rb @@ -37,6 +37,7 @@ class RegistrationCommandsControllerTest < ActionController::TestCase hostgroupId: hostgroups(:common).id, operatingsystemId: operatingsystems(:redhat).id, update_packages: true, + download_utility: 'wget', } post :create, params: params, session: set_session_user command = JSON.parse(@response.body)['command'] @@ -46,6 +47,7 @@ class RegistrationCommandsControllerTest < ActionController::TestCase assert_includes command, 'hostgroupId=' assert_includes command, 'operatingsystemId=' assert_includes command, 'update_packages=true' + assert_includes command, 'download_utility=wget' end test 'with params ignored in URL' do @@ -61,7 +63,7 @@ class RegistrationCommandsControllerTest < ActionController::TestCase post :create, params: params, session: set_session_user command = JSON.parse(@response.body)['command'] - assert_includes command, "curl -sS --insecure '#{proxy.url}/register" + assert_includes command, "curl --silent --show-error --insecure '#{proxy.url}/register" refute command.include?('smart_proxy_id') refute command.include?('insecure=true') refute command.include?('jwt_expiration') diff --git a/test/unit/foreman/renderer/scope/macros/helpers_test.rb b/test/unit/foreman/renderer/scope/macros/helpers_test.rb index a6c0899959f..0d1f3d049cb 100644 --- a/test/unit/foreman/renderer/scope/macros/helpers_test.rb +++ b/test/unit/foreman/renderer/scope/macros/helpers_test.rb @@ -109,4 +109,54 @@ def preview? it { assert scope.falsy?('false') } it { refute scope.falsy?('true') } end + + describe '#generate_web_request' do + it "generate curl get request" do + utility = "curl" + url = "https://www.example.com/keys/client.asc" + output_file = "/etc/apt/trusted.gpg.d/client1.asc" + expected_request = "curl --silent --show-error https://www.example.com/keys/client.asc \\\n" \ + " --output /etc/apt/trusted.gpg.d/client1.asc" + assert_equal expected_request, scope.generate_web_request(utility: utility, url: url, output_file: output_file) + end + + it "generate curl post request" do + utility = "curl" + url = "https://www.example.com/register" + ssl_ca_cert = "/etc/ssl/custom_certs/ca_cert.crt" + headers = ["--header \'Authorization: Bearer my_token\'"] + params = ["host[build]=false", "host[organization_id]=1"] + expected_request = "curl --silent --show-error https://www.example.com/register \\\n" \ + " --cacert /etc/ssl/custom_certs/ca_cert.crt \\\n" \ + " --request POST \\\n" \ + " --header 'Authorization: Bearer my_token' \\\n" \ + " --data host[build]=false \\\n" \ + " --data host[organization_id]=1" + assert_equal expected_request, scope.generate_web_request(utility: utility, url: url, ssl_ca_cert: ssl_ca_cert, headers: headers, params: params) + end + + it "generate wget get request" do + utility = "wget" + url = "https://www.example.com/keys/client.asc" + output_file = "/etc/apt/trusted.gpg.d/client1.asc" + expected_request = "wget --no-verbose --no-hsts https://www.example.com/keys/client.asc \\\n" \ + " --output-document /etc/apt/trusted.gpg.d/client1.asc" + assert_equal expected_request, scope.generate_web_request(utility: utility, url: url, output_file: output_file) + end + + it "generate wget post request" do + utility = "wget" + url = "https://www.example.com/register" + ssl_ca_cert = "/etc/ssl/custom_certs/ca_cert.crt" + headers = ["--header \'Authorization: Bearer my_token\'"] + params = ["host[build]=false", "host[organization_id]=1"] + expected_request = "wget --no-verbose --no-hsts https://www.example.com/register \\\n" \ + " --ca-certificate /etc/ssl/custom_certs/ca_cert.crt \\\n" \ + " --output-document - \\\n" \ + " --header 'Authorization: Bearer my_token' \\\n" \ + " --post-data host[build]=false\\&host[organization_id]=1" + + assert_equal expected_request, scope.generate_web_request(utility: utility, url: url, ssl_ca_cert: ssl_ca_cert, headers: headers, params: params) + end + end end diff --git a/test/unit/foreman/renderer/snapshots.yaml b/test/unit/foreman/renderer/snapshots.yaml index 438efa7552d..a263dd2f8ea 100644 --- a/test/unit/foreman/renderer/snapshots.yaml +++ b/test/unit/foreman/renderer/snapshots.yaml @@ -83,3 +83,4 @@ files: - finish/windows_default_finish.erb - script/windows_default_script.erb - snippet/windows_network.erb + - registration/global_registration.erb diff --git a/test/unit/foreman/renderer/snapshots/ProvisioningTemplate/registration/Global_Registration.registration_template.snap.txt b/test/unit/foreman/renderer/snapshots/ProvisioningTemplate/registration/Global_Registration.registration_template.snap.txt new file mode 100644 index 00000000000..ba1431768a8 --- /dev/null +++ b/test/unit/foreman/renderer/snapshots/ProvisioningTemplate/registration/Global_Registration.registration_template.snap.txt @@ -0,0 +1,148 @@ +#!/bin/sh + +# Make sure, all command output can be parsed (e.g. from subscription-manager) +export LC_ALL=C LANG=C + +# Rendered with following template parameters: + + +if ! [ $(id -u) = 0 ]; then + echo "Please run as root" + exit 1 +fi + +# Select package manager for the OS (sets the $PKG_MANAGER* variables) +if [ -f /etc/os-release ] ; then + . /etc/os-release +fi + +if [ "${NAME%.*}" = 'FreeBSD' ]; then + PKG_MANAGER='pkg' + PKG_MANAGER_INSTALL="${PKG_MANAGER} install -y" + PKG_MANAGER_REMOVE="${PKG_MANAGER} delete -y" + PKG_MANAGER_UPGRADE="${PKG_MANAGER} install -y" +elif [ -f /etc/fedora-release -o -f /etc/redhat-release -o -f /etc/amazon-linux-release -o -f /etc/system-release ]; then + PKG_MANAGER='dnf' + if [ -f /etc/redhat-release -a "${VERSION_ID%.*}" -le 7 ]; then + PKG_MANAGER='yum' + elif [ -f /etc/system-release ]; then + PKG_MANAGER='yum' + fi + PKG_MANAGER_INSTALL="${PKG_MANAGER} install -y" + PKG_MANAGER_REMOVE="${PKG_MANAGER} remove -y" + PKG_MANAGER_UPGRADE="${PKG_MANAGER} upgrade -y" +elif [ -f /etc/debian_version ]; then + PKG_MANAGER='apt-get' + PKG_MANAGER_INSTALL="${PKG_MANAGER} install -y" + PKG_MANAGER_REMOVE="${PKG_MANAGER} remove -y" + PKG_MANAGER_UPGRADE="${PKG_MANAGER} -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' -o APT::Get::Upgrade-Allow-New='true' upgrade -y" +elif [ -f /etc/arch-release ]; then + PKG_MANAGER='pacman' + PKG_MANAGER_INSTALL="${PKG_MANAGER} --noconfirm -S" + PKG_MANAGER_REMOVE="${PKG_MANAGER} --noconfirm -R" + PKG_MANAGER_UPGRADE="${PKG_MANAGER} --noconfirm -S" +elif [ x$ID = xopensuse-tumbleweed -o x$ID = xsles ]; then + PKG_MANAGER='zypper' + PKG_MANAGER_INSTALL="${PKG_MANAGER} --non-interactive install --auto-agree-with-licenses" + PKG_MANAGER_REMOVE="${PKG_MANAGER} --non-interactive remove" + PKG_MANAGER_UPGRADE="${PKG_MANAGER} --non-interactive update" +fi + + +SSL_CA_CERT=$(mktemp) +cat << EOF > $SSL_CA_CERT +-----BEGIN CERTIFICATE----- +MIIFrTCCA5WgAwIBAgIJAOzdk0zTsuBPMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV +BAYTAlhYMRAwDgYDVQQIEwdFeGFtcGxlMRAwDgYDVQQHEwdFeGFtcGxlMRQwEgYD +VQQKEwtFeGFtcGUgSW5jLjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcxMDA2 +MTMxMzMyWhcNMTgxMDA2MTMxMzMyWjBdMQswCQYDVQQGEwJYWDEQMA4GA1UECBMH +RXhhbXBsZTEQMA4GA1UEBxMHRXhhbXBsZTEUMBIGA1UEChMLRXhhbXBlIEluYy4x +FDASBgNVBAMTC2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAslMkcsSL4hhnTLBJ/ZD3qldyD+7qTE9cB5dk9MH0Vj2GEezPnnUYZ0Cu +v0029+ZbwzOb7If8XzGxGU5tnqItZLfihrM3SKqshgJFaCjWEuLXfwRzHF2+jSk8 +mkG69Z0JtewIeQ7SqUReeZb4cV47Hag6gO5LVTnFXlHjGPrz98SH+Ho80XtIdmk0 +6fCzVXUZY+0EtXIul00LwnqsNc8UupuRpNC3VIG6ZCq5snwQ9Va1u+RP77nJlGQz +bKh5/yYaMd9WU3LDREkY0kSzJzcqzzQzEJr1JAY1zmtm5+NLdU2LPZjMAU6UiuJ4 +ABNdHwlvUWQ0SyPDqH2pnaytFlHgAH3G6brOj51Jpp86hOa/3iJ+M6gGtbNcYshd +LYTpr+kl34qri0677VQtpM3uVwM5om4rGrCGbhuse8DtMdOAv4jAvF79SrLGK5k+ +sCWxtPXGIJgt+AXS3HJev3lRGWjNm5yYL6fTwgjbWceh05hBGOro/fDFPyAOpCek +KPqOhu/MpJz7x+48rBny0GIl/CsMqojQ8spFH1Xp9dKoV886ZdzDKMlvDYfSHrj4 +9A9aIOT3+W5VCsPMgSIrr0MFhv3bkIEGleo3IioHeLxIylW4FLl0D7AdXQeiqe99 +Y+Jf+w0FNoVlmykpcQ7qXmQTzHiG7VB+o3wOWaP3K7Sj0jpIjoUCAwEAAaNwMG4w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwVAYDVR0RBE0wS4IPd3d3LmV4YW1wbGUu +Y29tgg93d3cuZXhhbXBsZS5uZXSCD3d3dy5leGFtcGxlLm9yZ4cEwKgBAYcQIAEN +uAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAgEAiirO6rvirqxB5nfziEdd +Tn9BltiBDKg38MspsWSfSGJNHdmbZkBKhoJ89p9oewa8yOMqM3jrUjg2hn0J0nZG +t4dXix3Y7jHswaqr15mJEoLFGflkiOIOVJc1efxlSweXmyC+x6O5gAarmWHb+T6B +qxL/Z72N/Tua3foFQzlzR6lQ/++QglBHeBADtmZg6uPMPmWJ6iUA1OLpzW8cg4/0 +Q2UxKsD3WaN+37JbEJnNuuamCpCXoyHIpzxDccUKzmjAWOxUHuYuiOvSc55w4Ww3 +GXMmRgu6ElVxL938LgJfTnHTBZoN3TjAlWXTRMtLV+cUlUJhBA7wnDkZK9mfXvk8 +d7XCFq9WsRQ0B7+4raMt8fn7M20ckz5J9mnt3d1I8FQRluyTKOfzs7L++OP/AagD +ZCUrI5IrxroWqrf6f65t0HyqNDJy3ZKK2drsaf+emR3X3GVeeWVV0RzhUaIu6NJS +br7erBLX9J5s6ZrAf6LbbeKtF2x9AGF8SUYCCUNVAHQxf/fTBKQAtrB7BxOmZiY1 +fplNEWaMnDChPWlzdzmH+MsCAA5025+Sr7Eb/CS9wKZDV5z6FtqkQKPeZ/eHjtJV +SylVI2XfadJwxM4gj6Jcq1L8LxURS/NpTinoXDd3xfkZYy3WrMNAsP6Cz6GvcU/n +SBq3Hxpl4HptdDg+JyI1RIg= +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIFrTCCA5WgAwIBAgIJAOzdk0zTsuBPMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV +BAYTAlhYMRAwDgYDVQQIEwdFeGFtcGxlMRAwDgYDVQQHEwdFeGFtcGxlMRQwEgYD +VQQKEwtFeGFtcGUgSW5jLjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcxMDA2 +MTMxMzMyWhcNMTgxMDA2MTMxMzMyWjBdMQswCQYDVQQGEwJYWDEQMA4GA1UECBMH +RXhhbXBsZTEQMA4GA1UEBxMHRXhhbXBsZTEUMBIGA1UEChMLRXhhbXBlIEluYy4x +FDASBgNVBAMTC2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAslMkcsSL4hhnTLBJ/ZD3qldyD+7qTE9cB5dk9MH0Vj2GEezPnnUYZ0Cu +v0029+ZbwzOb7If8XzGxGU5tnqItZLfihrM3SKqshgJFaCjWEuLXfwRzHF2+jSk8 +mkG69Z0JtewIeQ7SqUReeZb4cV47Hag6gO5LVTnFXlHjGPrz98SH+Ho80XtIdmk0 +6fCzVXUZY+0EtXIul00LwnqsNc8UupuRpNC3VIG6ZCq5snwQ9Va1u+RP77nJlGQz +bKh5/yYaMd9WU3LDREkY0kSzJzcqzzQzEJr1JAY1zmtm5+NLdU2LPZjMAU6UiuJ4 +ABNdHwlvUWQ0SyPDqH2pnaytFlHgAH3G6brOj51Jpp86hOa/3iJ+M6gGtbNcYshd +LYTpr+kl34qri0677VQtpM3uVwM5om4rGrCGbhuse8DtMdOAv4jAvF79SrLGK5k+ +sCWxtPXGIJgt+AXS3HJev3lRGWjNm5yYL6fTwgjbWceh05hBGOro/fDFPyAOpCek +KPqOhu/MpJz7x+48rBny0GIl/CsMqojQ8spFH1Xp9dKoV886ZdzDKMlvDYfSHrj4 +9A9aIOT3+W5VCsPMgSIrr0MFhv3bkIEGleo3IioHeLxIylW4FLl0D7AdXQeiqe99 +Y+Jf+w0FNoVlmykpcQ7qXmQTzHiG7VB+o3wOWaP3K7Sj0jpIjoUCAwEAAaNwMG4w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwVAYDVR0RBE0wS4IPd3d3LmV4YW1wbGUu +Y29tgg93d3cuZXhhbXBsZS5uZXSCD3d3dy5leGFtcGxlLm9yZ4cEwKgBAYcQIAEN +uAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAgEAiirO6rvirqxB5nfziEdd +Tn9BltiBDKg38MspsWSfSGJNHdmbZkBKhoJ89p9oewa8yOMqM3jrUjg2hn0J0nZG +t4dXix3Y7jHswaqr15mJEoLFGflkiOIOVJc1efxlSweXmyC+x6O5gAarmWHb+T6B +qxL/Z72N/Tua3foFQzlzR6lQ/++QglBHeBADtmZg6uPMPmWJ6iUA1OLpzW8cg4/0 +Q2UxKsD3WaN+37JbEJnNuuamCpCXoyHIpzxDccUKzmjAWOxUHuYuiOvSc55w4Ww3 +GXMmRgu6ElVxL938LgJfTnHTBZoN3TjAlWXTRMtLV+cUlUJhBA7wnDkZK9mfXvk8 +d7XCFq9WsRQ0B7+4raMt8fn7M20ckz5J9mnt3d1I8FQRluyTKOfzs7L++OP/AagD +ZCUrI5IrxroWqrf6f65t0HyqNDJy3ZKK2drsaf+emR3X3GVeeWVV0RzhUaIu6NJS +br7erBLX9J5s6ZrAf6LbbeKtF2x9AGF8SUYCCUNVAHQxf/fTBKQAtrB7BxOmZiY1 +fplNEWaMnDChPWlzdzmH+MsCAA5025+Sr7Eb/CS9wKZDV5z6FtqkQKPeZ/eHjtJV +SylVI2XfadJwxM4gj6Jcq1L8LxURS/NpTinoXDd3xfkZYy3WrMNAsP6Cz6GvcU/n +SBq3Hxpl4HptdDg+JyI1RIg= +-----END CERTIFICATE----- + +EOF + +cleanup_and_exit() { + rm -f $SSL_CA_CERT + exit $1 +} + + + +register_host() { + curl --silent --show-error \ + --cacert $SSL_CA_CERT \ + --request POST \ + --header 'Authorization: Bearer ' \ + --data host[name]=$(hostname --fqdn) \ + --data host[build]=false \ + --data host[managed]=false +} + +echo "#" +echo "# Running registration" +echo "#" + +register_host | bash + + +cleanup_and_exit diff --git a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/__snapshots__/integration.test.js.snap b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/__snapshots__/integration.test.js.snap index f5db2067cd8..3a6ef230803 100644 --- a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/__snapshots__/integration.test.js.snap +++ b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/__snapshots__/integration.test.js.snap @@ -8,6 +8,7 @@ Object { "payload": Object { "key": "REGISTRATION_COMMANDS", "params": Object { + "downloadUtility": "curl", "hostgroupId": undefined, "insecure": false, "jwtExpiration": 4, diff --git a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/components/__snapshots__/General.test.js.snap b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/components/__snapshots__/General.test.js.snap index 6017a5ef5e0..84190a792ea 100644 --- a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/components/__snapshots__/General.test.js.snap +++ b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/__tests__/components/__snapshots__/General.test.js.snap @@ -33,6 +33,11 @@ exports[`RegistrationCommandsPage - General renders 1`] = ` smartProxies={Array []} smartProxyId={0} /> + {}, handleInvalidField: () => {}, isLoading: false, + downloadUtility: DownloadUtilities.curl, + handleDownloadUtility: () => {}, }; export const advancedComponentProps = { configParams: {}, @@ -98,6 +101,12 @@ export const updatePackagesProps = { isLoading: false, }; +export const downloadUtilityProps = { + downloadUtility: DownloadUtilities.curl, + handleDownloadUtility: () => {}, + isLoading: false, +}; + export const repositoryProps = { repoData: [], handleRepoData: () => {}, diff --git a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/components/General.js b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/components/General.js index 146ba504e32..73d4d0e5229 100644 --- a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/components/General.js +++ b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/components/General.js @@ -6,6 +6,7 @@ import HostGroup from './fields/HostGroup'; import OperatingSystem from './fields/OperatingSystem'; import SmartProxy from './fields/SmartProxy'; import Insecure from './fields/Insecure'; +import DownloadUtility, { DownloadUtilities } from './fields/DownloadUtility'; const General = ({ organizationId, @@ -28,6 +29,8 @@ const General = ({ handleInsecure, handleInvalidField, isLoading, + downloadUtility, + handleDownloadUtility, }) => ( <> + + ( + + handleDownloadUtility(v)} + className="without_select2" + id="reg_download_utility" + isDisabled={isLoading} + > + {DownloadUtilities.map(item => ( + + ))} + + +); + +DownloadUtility.propTypes = { + downloadUtility: PropTypes.oneOf(DownloadUtilities), + handleDownloadUtility: PropTypes.func.isRequired, + isLoading: PropTypes.bool.isRequired, +}; + +DownloadUtility.defaultProps = { + downloadUtility: DownloadUtilities[0], +}; + +export default DownloadUtility; diff --git a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/index.js b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/index.js index 24cfbaaae64..e653e3b342f 100644 --- a/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/index.js +++ b/webpack/assets/javascripts/react_app/routes/RegistrationCommands/RegistrationCommandsPage/index.js @@ -44,6 +44,7 @@ import Advanced from './components/Advanced'; import Actions from './components/Actions'; import Command from './components/Command'; import './RegistrationCommandsPage.scss'; +import { DownloadUtilities } from './components/fields/DownloadUtility'; const RegistrationCommandsPage = () => { const dispatch = useDispatch(); @@ -94,6 +95,7 @@ const RegistrationCommandsPage = () => { const [repoData, setRepoData] = useState([]); const [repoDataInternal, setRepoDataInternal] = useState([]); const [invalidFields, setInvalidFields] = useState([]); + const [downloadUtility, setDownloadUtility] = useState(DownloadUtilities[0]); // Command const command = useSelector(selectCommand); @@ -134,6 +136,7 @@ const RegistrationCommandsPage = () => { packages, repoData, updatePackages, + downloadUtility, ...pluginValues, }; @@ -280,6 +283,8 @@ const RegistrationCommandsPage = () => { handleInvalidField={handleInvalidField} invalidFields={invalidFields} isLoading={isLoading} + downloadUtility={downloadUtility} + handleDownloadUtility={setDownloadUtility} />