hammer_cli_foreman 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/config/foreman.yml +4 -0
  3. data/doc/configuration.md +30 -0
  4. data/doc/release_notes.md +10 -0
  5. data/lib/hammer_cli_foreman/api/authenticator.rb +9 -0
  6. data/lib/hammer_cli_foreman/api/connection.rb +2 -0
  7. data/lib/hammer_cli_foreman/api/negotiate_auth.rb +36 -0
  8. data/lib/hammer_cli_foreman/api/session_authenticator_wrapper.rb +6 -2
  9. data/lib/hammer_cli_foreman/api.rb +2 -1
  10. data/lib/hammer_cli_foreman/auth.rb +13 -0
  11. data/lib/hammer_cli_foreman/commands.rb +5 -1
  12. data/lib/hammer_cli_foreman/exception_handler.rb +26 -0
  13. data/lib/hammer_cli_foreman/partition_table.rb +30 -0
  14. data/lib/hammer_cli_foreman/report_template.rb +15 -0
  15. data/lib/hammer_cli_foreman/smart_proxy.rb +11 -0
  16. data/lib/hammer_cli_foreman/template.rb +30 -0
  17. data/lib/hammer_cli_foreman/version.rb +1 -1
  18. data/locale/ca/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  19. data/locale/de/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  20. data/locale/en/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  21. data/locale/en_GB/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  22. data/locale/es/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  23. data/locale/fr/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  24. data/locale/it/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  25. data/locale/ja/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  26. data/locale/ko/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  27. data/locale/pt_BR/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  28. data/locale/ru/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  29. data/locale/zh_CN/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  30. data/locale/zh_TW/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  31. data/test/functional/partition_table_test.rb +63 -0
  32. data/test/functional/report_template_test.rb +24 -0
  33. data/test/functional/template_test.rb +60 -0
  34. metadata +49 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87407ba2c43be96a076220e9500050007447596f6d14024932fa85a7c9046f20
4
- data.tar.gz: 2987c54ab5fef04cc45629754a55c62d16a252b6cd950e7de461a989712a79ca
3
+ metadata.gz: 70a45953e142e7d3a67ee81e99bb5cc6fccaf179d2a61e44922f3b809196a178
4
+ data.tar.gz: 6c958ff14e311eef47ac379a41ceb45cbabe7f7ed34b3d28c64c40fe963f2ca5
5
5
  SHA512:
6
- metadata.gz: 030d7c3ff4d19fb767e771c123b8cb0de2a6166cec3ec2012b689f7d920d3049a234f7900ee43141c2af97ce0d5aaf403ea9a9f3962072bdffc181126de57e70
7
- data.tar.gz: 6acaf9a9b06c59b4c7db28b73bdc7dfe31170ac3b621adb2b85a5a501090e310a4fcfc703e2b6dc48170a693ff675507b8b9c478a8c344ff7793bfe778a8f3f3
6
+ metadata.gz: 6d436e24f99cc80f70aff4ad2c0436a92d63e8b60b5f1aa1ebb787e0fe202404c686fe78397ae16ae9bb3f2261834f8a02db39417a2511fd562c316344933d7a
7
+ data.tar.gz: 828772047e91923c3b6ac365fa942d381483988ed4c7303a1021d560e73d4f591d1656613ef45916cdc565fa3b7989a6b0f577c655c5624f5a5f8e9bdc82f24b
data/config/foreman.yml CHANGED
@@ -29,6 +29,10 @@
29
29
  #:oidc_client_id: example-client-id
30
30
  #:oidc_redirect_uri: urn:ietf:wg:oauth:2.0:oob
31
31
 
32
+ # Negotiate (Kerberos) Auth:
33
+ # User needs to run kinit before using hammer (or initiate kerberos keyring in another way).
34
+ #:default_auth_type: 'Negotiate_Auth'
35
+
32
36
  # Enable using sessions
33
37
  # When sessions are enabled, hammer ignores credentials stored in the config file
34
38
  # and asks for them interactively at the begining of each session.
data/doc/configuration.md CHANGED
@@ -49,3 +49,33 @@ Please note that when you turn sessions on, the credentials stored in your confi
49
49
 
50
50
  The default session timeout is 1 hour. This can be changed in the Foreman: `Settings > Authentication > Idle timeout`
51
51
  When the session expires hammer will prompt for username and password again.
52
+
53
+ ### Negotiate (Kerberos) auth
54
+
55
+ This implements Kerberos authentication, usually implemented in FreeIPA or Microsoft Active Directory.
56
+ For this to work, the host that we are trying to use hammer on, needs to have realm already configured on this host.
57
+ This can be achieved through `realm join`, please refer to that command for more info.
58
+
59
+ **Sessions needs to be enabled**
60
+
61
+ `~/.hammer/cli.modules.d/foreman.yml`
62
+ ```yaml
63
+ :foreman:
64
+ :default_auth_type: 'Negotiate_Auth'
65
+ :use_sessions: true
66
+ ```
67
+
68
+ ```bash
69
+ # To initiate the kerberos keyring (this might be already done on login)
70
+ $ kinit <kerb_user>
71
+ # Enter your password
72
+ $ klist
73
+ Ticket cache: KEYRING:persistent:1000:1000
74
+ Default principal: kerb_user@REALM.EXAMPLE.COM
75
+
76
+ # use hammer as usuall, it will negotiate your auth on the first request
77
+ hammer ...
78
+
79
+ # or if you do not have negotiate as default auth, initiate the auth manually
80
+ hammer auth login negotiate
81
+ ```
data/doc/release_notes.md CHANGED
@@ -1,5 +1,15 @@
1
1
  Release notes
2
2
  =============
3
+ ### 3.3.0 (2022-05-10)
4
+ * Add kerberos negotiate auth support ([PR #555](https://github.com/theforeman/hammer-cli-foreman/pull/555)), [#8923](http://projects.theforeman.org/issues/8923)
5
+ * Pin mocha gem to < 1.14.0
6
+ * Force api docs checksum check, [#28283](http://projects.theforeman.org/issues/28283)
7
+ * Add template report-remplate and partition-table export command ([PR #595](https://github.com/theforeman/hammer-cli-foreman/pull/595)), [#34503](http://projects.theforeman.org/issues/34503)
8
+ * Add template import and partition-table import commands ([PR #596](https://github.com/theforeman/hammer-cli-foreman/pull/596)), [#22692](http://projects.theforeman.org/issues/22692)
9
+ * Add resource information to download command ([PR #598](https://github.com/theforeman/hammer-cli-foreman/pull/598)), [#34621](http://projects.theforeman.org/issues/34621)
10
+ * Add command to import ipv4 subnet from smart proxy ([PR #593](https://github.com/theforeman/hammer-cli-foreman/pull/593)), [#33255](http://projects.theforeman.org/issues/33255)
11
+ * Bump to 3.3.0-develop
12
+
3
13
  ### 3.2.0 (2022-02-10)
4
14
  * Domain update doesn't reset dns implicitly ([PR #591](https://github.com/theforeman/hammer-cli-foreman/pull/591)), [#34177](http://projects.theforeman.org/issues/34177)
5
15
  * Send filter's tax params only when required ([PR #592](https://github.com/theforeman/hammer-cli-foreman/pull/592)), [#34199](http://projects.theforeman.org/issues/34199)
@@ -13,6 +13,8 @@ module HammerCLIForeman
13
13
  void_auth
14
14
  elsif auth_type == AUTH_TYPES[:basic_auth]
15
15
  basic_auth
16
+ elsif auth_type == AUTH_TYPES[:negotiate]
17
+ negotiate_auth
16
18
  elsif auth_type == AUTH_TYPES[:oauth_password_grant]
17
19
  oauth_password_grant
18
20
  elsif auth_type == AUTH_TYPES[:oauth_authentication_code_grant]
@@ -43,6 +45,13 @@ module HammerCLIForeman
43
45
  end
44
46
  end
45
47
 
48
+ def negotiate_auth
49
+ return unless HammerCLIForeman::Sessions.enabled?
50
+
51
+ authenticator = NegotiateAuth.new(uri)
52
+ SessionAuthenticatorWrapper.new(authenticator, uri, auth_type)
53
+ end
54
+
46
55
  def oauth_password_grant
47
56
  return unless HammerCLIForeman::Sessions.enabled?
48
57
 
@@ -1,6 +1,7 @@
1
1
  require 'hammer_cli_foreman/api/session_authenticator_wrapper'
2
2
  require 'hammer_cli_foreman/api/authenticator'
3
3
  require 'hammer_cli_foreman/api/interactive_basic_auth'
4
+ require 'hammer_cli_foreman/api/negotiate_auth'
4
5
  require 'hammer_cli_foreman/api/oauth/authentication_code_grant'
5
6
  require 'hammer_cli_foreman/api/oauth/password_grant'
6
7
  require 'hammer_cli_foreman/api/void_auth'
@@ -10,6 +11,7 @@ module HammerCLIForeman
10
11
  CONNECTION_NAME = 'foreman'
11
12
  AUTH_TYPES = {
12
13
  basic_auth: 'Basic_Auth',
14
+ negotiate: 'Negotiate_Auth',
13
15
  oauth_authentication_code_grant: 'Oauth_Authentication_Code_Grant',
14
16
  oauth_password_grant: 'Oauth_Password_Grant'
15
17
  }.freeze
@@ -0,0 +1,36 @@
1
+ module HammerCLIForeman
2
+ module Api
3
+ class NegotiateAuth < ApipieBindings::Authenticators::Negotiate
4
+ def initialize(foreman_url, **options)
5
+ super("#{foreman_url}/users/extlogin", HammerCLI::SSLOptions.new.get_options(foreman_url).merge(options))
6
+ end
7
+
8
+ def user
9
+ _('current Kerberos user')
10
+ end
11
+
12
+ def session_id
13
+ auth_cookie&.delete_prefix('_session_id=')
14
+ end
15
+
16
+ def status
17
+ if system('klist')
18
+ _('No session, but there is an active Kerberos session, that will be used for negotiate login.')
19
+ else
20
+ _('There is no active Kerberos session. Have you run %s?') % 'kinit'
21
+ end
22
+ end
23
+
24
+ def error(ex)
25
+ super unless ex.is_a?(RestClient::Unauthorized)
26
+
27
+ message = _('Invalid username or password.')
28
+ begin
29
+ message = JSON.parse(ex.response.body)['error']['message']
30
+ rescue
31
+ end
32
+ UnauthorizedError.new(message)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -24,6 +24,8 @@ module HammerCLIForeman
24
24
  def status
25
25
  if session.valid?
26
26
  _("Session exists, currently logged in as '%s'.") % session.user_name
27
+ elsif @authenticator.respond_to?(:status)
28
+ @authenticator.status
27
29
  else
28
30
  _('Using sessions, you are currently not logged in.')
29
31
  end
@@ -66,8 +68,10 @@ module HammerCLIForeman
66
68
  end
67
69
 
68
70
  def response(r)
69
- if (r.cookies['_session_id'] && r.code != 401)
70
- session.id = r.cookies['_session_id']
71
+ session_id = @authenticator.session_id if @authenticator.respond_to?(:session_id)
72
+ session_id ||= r.cookies['_session_id']
73
+ if session_id && r.code != 401
74
+ session.id = session_id
71
75
  session.user_name = @authenticator.user
72
76
  session.store
73
77
  end
@@ -7,4 +7,5 @@ module HammerCLIForeman
7
7
  end
8
8
  end
9
9
 
10
- HammerCLIForeman.init_api_connection
10
+ api = HammerCLIForeman.init_api_connection.api
11
+ api.update_cache(api.check_cache)
@@ -28,6 +28,19 @@ module HammerCLIForeman
28
28
  end
29
29
  end
30
30
 
31
+ class Negotiate < HammerCLI::AbstractCommand
32
+ extend HammerCLIForeman::Authenticate::Login
33
+
34
+ command_name('negotiate')
35
+ desc('negotiate the login credentials from the auth ticket (Kerberos)')
36
+
37
+ def execute
38
+ Negotiate.execute_with_params(AUTH_TYPES[:negotiate])
39
+ print_message(_("Successfully authenticated using negotiate auth, using the KEYRING principal."))
40
+ HammerCLI::EX_OK
41
+ end
42
+ end
43
+
31
44
  class Oauth < HammerCLI::AbstractCommand
32
45
  extend HammerCLIForeman::Authenticate::Login
33
46
 
@@ -744,13 +744,17 @@ module HammerCLIForeman
744
744
  response = send_request
745
745
  if option_path
746
746
  filepath = store_response(response)
747
- print_message(_('The response has been saved to %{path}s.'), {:path => filepath})
747
+ print_message(saved_response_message(filepath))
748
748
  else
749
749
  puts response.body
750
750
  end
751
751
  return HammerCLI::EX_OK
752
752
  end
753
753
 
754
+ def saved_response_message(filepath)
755
+ _("The response has been saved to %{path}.") % { path: filepath }
756
+ end
757
+
754
758
  def default_filename
755
759
  "Downloaded-#{Time.new.strftime("%Y-%m-%d")}.txt"
756
760
  end
@@ -12,6 +12,7 @@ module HammerCLIForeman
12
12
  [RestClient::UnprocessableEntity, :handle_unprocessable_entity],
13
13
  [RestClient::MovedPermanently, :handle_moved_permanently],
14
14
  [RestClient::BadRequest, :handle_bad_request],
15
+ [ApipieBindings::AuthenticatorError, :handle_authenticator_error],
15
16
  [HammerCLIForeman::Api::UnauthorizedError, :handle_foreman_unauthorized],
16
17
  [HammerCLIForeman::Api::SessionExpired, :handle_sesion_expired],
17
18
  [ArgumentError, :handle_argument_error],
@@ -112,6 +113,12 @@ module HammerCLIForeman
112
113
  HammerCLI::EX_DATAERR
113
114
  end
114
115
 
116
+ def handle_authenticator_error(e)
117
+ print_error authenticator_error_message(e)
118
+ log_full_error e.original_error
119
+ HammerCLI::EX_USAGE
120
+ end
121
+
115
122
  def ssl_cert_instructions
116
123
  host_url = HammerCLI::Settings.get(:_params, :host) || HammerCLI::Settings.get(:foreman, :host)
117
124
  uri = URI.parse(host_url)
@@ -147,6 +154,25 @@ module HammerCLIForeman
147
154
 
148
155
  private
149
156
 
157
+ def authenticator_error_message(e)
158
+ case e.type
159
+ when :negotiate then negotiation_error_message(e)
160
+ end
161
+ end
162
+
163
+ def negotiation_error_message(e)
164
+ case e.cause
165
+ when :configuration
166
+ _('Server misconfiguration detected') + "\n - " +
167
+ _('have you run installer with option %s?') % '--foreman-ipa-authentication=true' + "\n - " +
168
+ _('the user might come from a different authentication source') + "\n"
169
+ else
170
+ _('Could not authenticate using negotiation protocol') + "\n - " +
171
+ _('have you run %s (for Kerberos)?') % 'kinit' + "\n - " +
172
+ _('is the server down?') + "\n"
173
+ end
174
+ end
175
+
150
176
  def response_message(response)
151
177
  message = JSON.parse(response)["error"]["message"]
152
178
  "\n #{message}"
@@ -71,6 +71,36 @@ module HammerCLIForeman
71
71
  build_options
72
72
  end
73
73
 
74
+ class ImportCommand < HammerCLIForeman::Command
75
+ command_name "import"
76
+ action :import
77
+ option '--file', 'PATH', _('Path to a file that contains the template content including metadata'),
78
+ :attribute_name => :option_template, :format => HammerCLI::Options::Normalizers::File.new
79
+
80
+ validate_options do
81
+ all(:option_name, :option_template).required
82
+ end
83
+
84
+ success_message _("Import partition table template succeeded.")
85
+ failure_message _("Could not import partition table template")
86
+
87
+ build_options :without => [:template]
88
+ end
89
+
90
+ class ExportCommand < HammerCLIForeman::DownloadCommand
91
+ command_name "export"
92
+ action :export
93
+
94
+ def default_filename
95
+ "Partition Table Template-#{Time.new.strftime("%Y-%m-%d")}.txt"
96
+ end
97
+
98
+ def saved_response_message(filepath)
99
+ _("The partition table template has been saved to %{path}.") % { path: filepath }
100
+ end
101
+
102
+ build_options
103
+ end
74
104
 
75
105
  HammerCLIForeman::AssociatingCommands::OperatingSystem.extend_command(self)
76
106
 
@@ -148,6 +148,21 @@ module HammerCLIForeman
148
148
  build_options :without => [:template]
149
149
  end
150
150
 
151
+ class ExportCommand < HammerCLIForeman::DownloadCommand
152
+ command_name "export"
153
+ action :export
154
+
155
+ def default_filename
156
+ "Report Template-#{Time.new.strftime("%Y-%m-%d")}.txt"
157
+ end
158
+
159
+ def saved_response_message(filepath)
160
+ _("The report template has been saved to %{path}.") % { path: filepath }
161
+ end
162
+
163
+ build_options
164
+ end
165
+
151
166
  class ReportDataCommand < HammerCLIForeman::DownloadCommand
152
167
  command_name "report-data"
153
168
  action :report_data
@@ -73,6 +73,17 @@ module HammerCLIForeman
73
73
  build_options
74
74
  end
75
75
 
76
+ class ImportSubnetsCommand < HammerCLIForeman::Command
77
+
78
+ action :import_subnets
79
+
80
+ command_name "import-subnets"
81
+ success_message _("Import subnets succeeded.")
82
+ failure_message _("Could not import subnets")
83
+
84
+ build_options
85
+ end
86
+
76
87
  autoload_subcommands
77
88
  end
78
89
 
@@ -142,7 +142,37 @@ module HammerCLIForeman
142
142
  build_options
143
143
  end
144
144
 
145
+ class ImportCommand < HammerCLIForeman::Command
146
+ command_name "import"
147
+ action :import
148
+ option '--file', 'PATH', _('Path to a file that contains the template content including metadata'),
149
+ :attribute_name => :option_template, :format => HammerCLI::Options::Normalizers::File.new
145
150
 
151
+ validate_options do
152
+ all(:option_name, :option_template).required
153
+ end
154
+
155
+ success_message _("Import provisioning template succeeded.")
156
+ failure_message _("Could not import provisioning template")
157
+
158
+ build_options :without => [:template]
159
+ end
160
+
161
+ class ExportCommand < HammerCLIForeman::DownloadCommand
162
+ command_name "export"
163
+ action :export
164
+
165
+ def default_filename
166
+ "Template-#{Time.new.strftime("%Y-%m-%d")}.txt"
167
+ end
168
+
169
+ def saved_response_message(filepath)
170
+ _("The provisioning template has been saved to %{path}.") % { path: filepath }
171
+ end
172
+
173
+ build_options
174
+ end
175
+
146
176
  class BuildPXEDefaultCommand < HammerCLIForeman::Command
147
177
 
148
178
  action :build_pxe_default
@@ -1,5 +1,5 @@
1
1
  module HammerCLIForeman
2
2
  def self.version
3
- @version ||= Gem::Version.new "3.2.0"
3
+ @version ||= Gem::Version.new "3.3.0"
4
4
  end
5
5
  end
@@ -0,0 +1,63 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe 'partition-table' do
4
+ describe 'import' do
5
+ let(:template) do
6
+ {
7
+ 'id' => 1,
8
+ 'template' => 'Template content'
9
+ }
10
+ end
11
+ let(:cmd) { %w(partition-table import) }
12
+ let(:tempfile) { Tempfile.new('template') }
13
+
14
+ it 'requires --name and --file' do
15
+ params = ['--name=test']
16
+ api_expects_no_call
17
+ expected_result = usage_error_result(
18
+ cmd,
19
+ 'Options --name, --file are required.',
20
+ 'Could not import partition table template')
21
+ result = run_cmd(cmd + params)
22
+ assert_cmd(expected_result, result)
23
+ end
24
+
25
+ it 'import template' do
26
+ params = ['--name=test', "--file=#{tempfile.path}"]
27
+ tempfile.write('Template content')
28
+ tempfile.rewind
29
+ api_expects(:ptables, :import, 'Import partition table template').with_params(
30
+ 'ptable' => {
31
+ 'name' => 'test',
32
+ 'template' => 'Template content'
33
+ }).returns(template)
34
+
35
+ result = run_cmd(cmd + params)
36
+ assert_cmd(success_result("Import partition table template succeeded.\n"), result)
37
+ end
38
+ end
39
+
40
+ describe 'export' do
41
+ let(:cmd) { %w(partition-table export) }
42
+ let(:tempfile) { Tempfile.new('template', '/tmp') }
43
+ let(:params) { ['--id=1', '--path=/tmp'] }
44
+ let(:template_response) do
45
+ response = mock('TemplateResponse')
46
+ response.stubs(:code).returns(200)
47
+ response.stubs(:body).returns('Template content')
48
+ response.stubs(:headers).returns({:content_disposition => "filename=\"#{File.basename(tempfile.path)}\""})
49
+ response
50
+ end
51
+
52
+ it 'download template' do
53
+ api_expects(:ptables, :export, 'Export partition table template').with_params(
54
+ 'id' => '1').returns(template_response)
55
+
56
+ output = OutputMatcher.new("The partition table template has been saved to #{tempfile.path}")
57
+ expected_result = success_result(output)
58
+ result = run_cmd(cmd + params)
59
+ assert_cmd(expected_result, result)
60
+ assert_equal('Template content', tempfile.read)
61
+ end
62
+ end
63
+ end
@@ -384,6 +384,30 @@ describe 'report-template' do
384
384
  end
385
385
  end
386
386
 
387
+ describe 'export' do
388
+ let(:cmd) { %w(report-template export) }
389
+ let(:tempfile) { Tempfile.new('template', '/tmp') }
390
+ let(:params) { ['--id=1', '--path=/tmp'] }
391
+ let(:template_response) do
392
+ response = mock('TemplateResponse')
393
+ response.stubs(:code).returns(200)
394
+ response.stubs(:body).returns('Template content')
395
+ response.stubs(:headers).returns({:content_disposition => "filename=\"#{File.basename(tempfile.path)}\""})
396
+ response
397
+ end
398
+
399
+ it 'download template' do
400
+ api_expects(:report_templates, :export, 'Export report template').with_params(
401
+ 'id' => '1').returns(template_response)
402
+
403
+ output = OutputMatcher.new("The report template has been saved to #{tempfile.path}")
404
+ expected_result = success_result(output)
405
+ result = run_cmd(cmd + params)
406
+ assert_cmd(expected_result, result)
407
+ assert_equal('Template content', tempfile.read)
408
+ end
409
+ end
410
+
387
411
  describe 'report-data' do
388
412
  let(:cmd) { %w(report-template report-data) }
389
413
  let(:tempfile) { Tempfile.new('template', '/tmp') }
@@ -77,6 +77,66 @@ describe 'template' do
77
77
  end
78
78
  end
79
79
 
80
+ describe 'import' do
81
+ let(:template) do
82
+ {
83
+ 'id' => 1,
84
+ 'template' => 'Template content'
85
+ }
86
+ end
87
+ let(:cmd) { %w(template import) }
88
+ let(:tempfile) { Tempfile.new('template') }
89
+
90
+ it 'requires --name and --file' do
91
+ params = ['--name=test']
92
+ api_expects_no_call
93
+ expected_result = usage_error_result(
94
+ cmd,
95
+ 'Options --name, --file are required.',
96
+ 'Could not import provisioning template')
97
+ result = run_cmd(cmd + params)
98
+ assert_cmd(expected_result, result)
99
+ end
100
+
101
+ it 'import template' do
102
+ params = ['--name=test', "--file=#{tempfile.path}"]
103
+ tempfile.write('Template content')
104
+ tempfile.rewind
105
+ api_expects(:provisioning_templates, :import, 'Import template').with_params(
106
+ 'provisioning_template' => {
107
+ 'name' => 'test',
108
+ 'template' => 'Template content'
109
+ }).returns(template)
110
+
111
+ result = run_cmd(cmd + params)
112
+ assert_cmd(success_result("Import provisioning template succeeded.\n"), result)
113
+ end
114
+ end
115
+
116
+ describe 'export' do
117
+ let(:cmd) { %w(template export) }
118
+ let(:tempfile) { Tempfile.new('template', '/tmp') }
119
+ let(:params) { ['--id=1', '--path=/tmp'] }
120
+ let(:template_response) do
121
+ response = mock('TemplateResponse')
122
+ response.stubs(:code).returns(200)
123
+ response.stubs(:body).returns('Template content')
124
+ response.stubs(:headers).returns({:content_disposition => "filename=\"#{File.basename(tempfile.path)}\""})
125
+ response
126
+ end
127
+
128
+ it 'download template' do
129
+ api_expects(:provisioning_templates, :export, 'Export template').with_params(
130
+ 'id' => '1').returns(template_response)
131
+
132
+ output = OutputMatcher.new("The provisioning template has been saved to #{tempfile.path}")
133
+ expected_result = success_result(output)
134
+ result = run_cmd(cmd + params)
135
+ assert_cmd(expected_result, result)
136
+ assert_equal('Template content', tempfile.read)
137
+ end
138
+ end
139
+
80
140
  describe 'update' do
81
141
  before do
82
142
  @cmd = %w(template update)
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hammer_cli_foreman
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomáš Strachota
8
8
  - Martin Bačovský
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-02-10 00:00:00.000000000 Z
12
+ date: 2022-05-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hammer_cli
@@ -17,28 +17,28 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 3.1.0
20
+ version: 3.3.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: 3.1.0
27
+ version: 3.3.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: apipie-bindings
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 0.4.0
34
+ version: 0.5.0
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: 0.4.0
41
+ version: 0.5.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rest-client
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -75,12 +75,11 @@ dependencies:
75
75
  version: 2.2.1
76
76
  description: 'Foreman commands for Hammer CLI
77
77
 
78
- '
78
+ '
79
79
  email: tstracho@redhat.com
80
80
  executables: []
81
81
  extensions: []
82
82
  extra_rdoc_files:
83
- - doc/configuration.md
84
83
  - doc/name_id_resolution.md
85
84
  - doc/option_builder.md
86
85
  - doc/using_hammer_cli_foreman_command.md
@@ -88,6 +87,7 @@ extra_rdoc_files:
88
87
  - doc/host_create.md
89
88
  - doc/plugin.md
90
89
  - doc/testing.md
90
+ - doc/configuration.md
91
91
  - doc/release_notes.md
92
92
  - README.md
93
93
  files:
@@ -108,6 +108,7 @@ files:
108
108
  - lib/hammer_cli_foreman/api/authenticator.rb
109
109
  - lib/hammer_cli_foreman/api/connection.rb
110
110
  - lib/hammer_cli_foreman/api/interactive_basic_auth.rb
111
+ - lib/hammer_cli_foreman/api/negotiate_auth.rb
111
112
  - lib/hammer_cli_foreman/api/oauth/authentication_code_grant.rb
112
113
  - lib/hammer_cli_foreman/api/oauth/password_grant.rb
113
114
  - lib/hammer_cli_foreman/api/session_authenticator_wrapper.rb
@@ -267,6 +268,7 @@ files:
267
268
  - test/functional/model_test.rb
268
269
  - test/functional/operating_system_test.rb
269
270
  - test/functional/organization_test.rb
271
+ - test/functional/partition_table_test.rb
270
272
  - test/functional/personal_access_token_test.rb
271
273
  - test/functional/ping_test.rb
272
274
  - test/functional/realm_test.rb
@@ -345,7 +347,7 @@ homepage: https://github.com/theforeman/hammer-cli-foreman
345
347
  licenses:
346
348
  - GPL-3.0+
347
349
  metadata: {}
348
- post_install_message:
350
+ post_install_message:
349
351
  rdoc_options: []
350
352
  require_paths:
351
353
  - lib
@@ -361,7 +363,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
363
  version: '0'
362
364
  requirements: []
363
365
  rubygems_version: 3.1.2
364
- signing_key:
366
+ signing_key:
365
367
  specification_version: 4
366
368
  summary: Foreman commands for Hammer
367
369
  test_files:
@@ -379,61 +381,63 @@ test_files:
379
381
  - test/data/1.24/foreman_api.json
380
382
  - test/data/2.0/foreman_api.json
381
383
  - test/data/2.1/foreman_api.json
384
+ - test/data/README.md
382
385
  - test/data/2.4/foreman_api.json
383
386
  - test/data/2.5/foreman_api.json
384
- - test/data/README.md
385
387
  - test/data/3.1/foreman_api.json
386
388
  - test/functional/auth_source_test.rb
387
389
  - test/functional/commands/list_test.rb
388
- - test/functional/usergroup_test.rb
389
390
  - test/functional/hostgroup/create_test.rb
390
391
  - test/functional/hostgroup/update_test.rb
391
- - test/functional/personal_access_token_test.rb
392
- - test/functional/template_test.rb
392
+ - test/functional/architecture_test.rb
393
393
  - test/functional/compute_attribute_test.rb
394
- - test/functional/model_test.rb
394
+ - test/functional/ping_test.rb
395
+ - test/functional/user_test.rb
395
396
  - test/functional/ssh_keys_test.rb
396
397
  - test/functional/subnet/update_test.rb
397
398
  - test/functional/subnet/create_test.rb
398
399
  - test/functional/test_helper.rb
399
- - test/functional/filter_test.rb
400
- - test/functional/http_proxy_test.rb
400
+ - test/functional/location_test.rb
401
401
  - test/functional/media_test.rb
402
- - test/functional/registration_test.rb
402
+ - test/functional/partition_table_test.rb
403
+ - test/functional/personal_access_token_test.rb
404
+ - test/functional/report_template_test.rb
405
+ - test/functional/settings_test.rb
406
+ - test/functional/status_test.rb
403
407
  - test/functional/user_mail_notification_test.rb
404
- - test/functional/domain/create_test.rb
405
- - test/functional/domain/update_test.rb
406
- - test/functional/operating_system_test.rb
407
- - test/functional/compute_resource_test.rb
408
+ - test/functional/compute_profile_test.rb
409
+ - test/functional/realm_test.rb
410
+ - test/functional/usergroup_test.rb
408
411
  - test/functional/organization_test.rb
409
- - test/functional/report_template_test.rb
410
- - test/functional/user_test.rb
411
412
  - test/functional/virtual_machine_test.rb
413
+ - test/functional/compute_resource_test.rb
414
+ - test/functional/domain/create_test.rb
415
+ - test/functional/domain/update_test.rb
416
+ - test/functional/filter_test.rb
412
417
  - test/functional/host_test.rb
418
+ - test/functional/http_proxy_test.rb
413
419
  - test/functional/mail_notification_test.rb
414
- - test/functional/bookmark_test.rb
415
- - test/functional/location_test.rb
420
+ - test/functional/operating_system_test.rb
421
+ - test/functional/template_test.rb
416
422
  - test/functional/associating_commands_test.rb
417
423
  - test/functional/audit_test.rb
418
- - test/functional/ping_test.rb
419
- - test/functional/realm_test.rb
420
424
  - test/functional/role_test.rb
421
- - test/functional/status_test.rb
422
- - test/functional/architecture_test.rb
423
- - test/functional/compute_profile_test.rb
424
- - test/functional/settings_test.rb
425
+ - test/functional/bookmark_test.rb
426
+ - test/functional/model_test.rb
427
+ - test/functional/registration_test.rb
425
428
  - test/unit/api/void_auth_test.rb
426
429
  - test/unit/api/interactive_basic_auth_test.rb
427
430
  - test/unit/api/oauth/oauth_authentication_code_grant_test.rb
428
431
  - test/unit/api/oauth/oauth_password_grant_test.rb
429
432
  - test/unit/api/session_authenticator_wrapper_test.rb
430
433
  - test/unit/test_output_adapter.rb
431
- - test/unit/settings_test.rb
434
+ - test/unit/host_test.rb
432
435
  - test/unit/auth_source_ldap_test.rb
433
436
  - test/unit/config_report_test.rb
434
437
  - test/unit/compute_resource_test.rb
435
438
  - test/unit/data/test_api.json
436
439
  - test/unit/defaults_test.rb
440
+ - test/unit/id_resolver_test.rb
437
441
  - test/unit/external_usergroup_test.rb
438
442
  - test/unit/fact_test.rb
439
443
  - test/unit/helpers/fake_searchables.rb
@@ -442,26 +446,25 @@ test_files:
442
446
  - test/unit/image_test.rb
443
447
  - test/unit/location_test.rb
444
448
  - test/unit/messages_test.rb
449
+ - test/unit/mail_notification_test.rb
445
450
  - test/unit/option_sources/id_params_test.rb
446
451
  - test/unit/option_sources/ids_params_test.rb
447
452
  - test/unit/organization_test.rb
448
453
  - test/unit/output/formatters_test.rb
449
454
  - test/unit/common_parameter_test.rb
450
455
  - test/unit/realm_test.rb
451
- - test/unit/compute_profile_test.rb
452
- - test/unit/host_test.rb
456
+ - test/unit/settings_test.rb
457
+ - test/unit/usergroup_test.rb
453
458
  - test/unit/subnet_test.rb
454
459
  - test/unit/test_helper.rb
455
460
  - test/unit/user_test.rb
456
461
  - test/unit/param_filters_test.rb
457
- - test/unit/partition_table_test.rb
458
462
  - test/unit/role_test.rb
459
- - test/unit/hostgroup_test.rb
460
- - test/unit/id_resolver_test.rb
461
- - test/unit/mail_notification_test.rb
462
463
  - test/unit/model_test.rb
463
464
  - test/unit/operating_system_test.rb
464
465
  - test/unit/option_builders_test.rb
466
+ - test/unit/architecture_test.rb
467
+ - test/unit/commands_test.rb
465
468
  - test/unit/audit_test.rb
466
469
  - test/unit/auth_source_external.rb
467
470
  - test/unit/dependency_resolver_test.rb
@@ -469,13 +472,13 @@ test_files:
469
472
  - test/unit/filter_test.rb
470
473
  - test/unit/media_test.rb
471
474
  - test/unit/sessions_test.rb
472
- - test/unit/apipie_resource_mock.rb
473
- - test/unit/commands_test.rb
475
+ - test/unit/bookmark_test.rb
476
+ - test/unit/hostgroup_test.rb
474
477
  - test/unit/api_test.rb
475
- - test/unit/architecture_test.rb
476
- - test/unit/smart_proxy_test.rb
477
- - test/unit/usergroup_test.rb
478
+ - test/unit/apipie_resource_mock.rb
479
+ - test/unit/compute_profile_test.rb
480
+ - test/unit/partition_table_test.rb
478
481
  - test/unit/template_test.rb
479
- - test/unit/bookmark_test.rb
482
+ - test/unit/smart_proxy_test.rb
480
483
  - test/unit/domain_test.rb
481
484
  - test/test_helper.rb