hammer_cli_foreman 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/doc/host_create.md +120 -85
  3. data/doc/release_notes.md +12 -0
  4. data/lib/hammer_cli_foreman/compute_resource.rb +106 -11
  5. data/lib/hammer_cli_foreman/compute_resources/vmware/host_help_extenstion.rb +25 -21
  6. data/lib/hammer_cli_foreman/host.rb +42 -1
  7. data/lib/hammer_cli_foreman/hosts/common_update_options.rb +9 -3
  8. data/lib/hammer_cli_foreman/output/fields.rb +45 -10
  9. data/lib/hammer_cli_foreman/output/formatters.rb +82 -45
  10. data/lib/hammer_cli_foreman/subnet.rb +25 -0
  11. data/lib/hammer_cli_foreman/version.rb +1 -1
  12. data/locale/ca/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  13. data/locale/de/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  14. data/locale/en/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  15. data/locale/en_GB/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  16. data/locale/es/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  17. data/locale/fr/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  18. data/locale/it/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  19. data/locale/ja/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  20. data/locale/ko/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  21. data/locale/pt_BR/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  22. data/locale/ru/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  23. data/locale/zh_CN/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  24. data/locale/zh_TW/LC_MESSAGES/hammer-cli-foreman.mo +0 -0
  25. data/test/functional/compute_resource_test.rb +260 -0
  26. data/test/functional/host_test.rb +49 -0
  27. data/test/functional/subnet/create_test.rb +131 -0
  28. data/test/functional/subnet/update_test.rb +130 -0
  29. data/test/unit/apipie_resource_mock.rb +4 -0
  30. data/test/unit/compute_resource_test.rb +22 -0
  31. data/test/unit/host_test.rb +2 -2
  32. data/test/unit/output/formatters_test.rb +77 -68
  33. metadata +10 -6
@@ -33,6 +33,7 @@ module HammerCLIForeman
33
33
  field nil, _("Host Group"), Fields::SingleReference, :key => :hostgroup, :display_field => 'title'
34
34
  field :ip, _("IP")
35
35
  field :mac, _("MAC")
36
+ field :global_status_label, _("Global Status")
36
37
  end
37
38
 
38
39
  build_options :without => [:include, :thin]
@@ -70,6 +71,11 @@ module HammerCLIForeman
70
71
  field :installed_at, _("Installed at"), Fields::Date
71
72
  field :last_report, _("Last report"), Fields::Date
72
73
 
74
+ label _("Status") do
75
+ field :global_status_label, _("Global Status")
76
+ field :build_status_label, _("Build Status")
77
+ end
78
+
73
79
  label _("Network") do
74
80
  field :ip, _("IPv4 address"), Fields::Field, :hide_blank => true
75
81
  field :ip6, _("IPv6 address"), Fields::Field, :hide_blank => true
@@ -422,6 +428,21 @@ module HammerCLIForeman
422
428
  build_options :without => :power_action
423
429
  end
424
430
 
431
+ class ResetCommand < HammerCLIForeman::SingleResourceCommand
432
+ action :power
433
+
434
+ command_name 'reset'
435
+ desc _('Reset a host')
436
+ success_message _('Host reset started.')
437
+ failure_message _('Failed to reset the host')
438
+
439
+ def option_power_action
440
+ :cycle
441
+ end
442
+
443
+ build_options without: [:power_action]
444
+ end
445
+
425
446
  class SCParamsCommand < HammerCLIForeman::SmartClassParametersList
426
447
  build_options_for :hosts
427
448
 
@@ -474,11 +495,31 @@ module HammerCLIForeman
474
495
  build_options
475
496
  end
476
497
 
498
+ class BootCommand < HammerCLIForeman::SingleResourceCommand
499
+ action :boot
500
+
501
+ command_name 'boot'
502
+ success_message _('The host is booting.')
503
+ failure_message _('Failed to boot the host from device')
504
+
505
+ def execute
506
+ response = send_request
507
+ if response['result']
508
+ output.print_message(success_message)
509
+ HammerCLI::EX_OK
510
+ else
511
+ output.print_error(failure_message)
512
+ HammerCLI::EX_DATAERR
513
+ end
514
+ end
515
+
516
+ build_options
517
+ end
518
+
477
519
  autoload_subcommands
478
520
 
479
521
  subcommand 'interface', HammerCLIForeman::Interface.desc, HammerCLIForeman::Interface
480
522
  end
481
-
482
523
  end
483
524
 
484
525
  require 'hammer_cli_foreman/compute_resources/all'
@@ -72,10 +72,16 @@ module HammerCLIForeman
72
72
  end
73
73
  params['host']['overwrite'] = option_overwrite unless option_overwrite.nil?
74
74
 
75
- params['host']['host_parameters_attributes'] = parameter_attributes
75
+ params['host']['host_parameters_attributes'] = parameter_attributes unless option_parameters.nil?
76
76
  params['host']['compute_attributes'] = option_compute_attributes || {}
77
- params['host']['compute_attributes']['volumes_attributes'] = nested_attributes(option_volume_list)
78
- params['host']['interfaces_attributes'] = interfaces_attributes
77
+
78
+ if action == :update
79
+ params['host']['compute_attributes']['volumes_attributes'] = nested_attributes(option_volume_list) unless option_volume_list.empty?
80
+ params['host']['interfaces_attributes'] = interfaces_attributes unless option_interface_list.empty?
81
+ else
82
+ params['host']['compute_attributes']['volumes_attributes'] = nested_attributes(option_volume_list)
83
+ params['host']['interfaces_attributes'] = interfaces_attributes
84
+ end
79
85
 
80
86
  params['host']['root_pass'] = option_root_password unless option_root_password.nil?
81
87
 
@@ -2,25 +2,60 @@ require 'hammer_cli'
2
2
 
3
3
  module Fields
4
4
 
5
- class SingleReference < Field
5
+ class Reference < Field
6
+ def initialize(options={})
7
+ super
8
+ initialize_options
9
+ end
6
10
 
7
- def display?(value)
8
- id_key = "#{parameters[:key]}_id"
9
- display_field = parameters[:display_field] || 'name'
10
- display_key = "#{parameters[:key]}_#{display_field}"
11
+ def initialize_options
12
+ @options[:details] ||= []
13
+ @options[:details] = [@options[:details]] unless @options[:details].is_a?(Array)
14
+ @options[:details] = [id_detail] + @options[:details]
15
+ @options[:display_field_key] ||= @options[:name_key] || :name
16
+ end
11
17
 
12
- (value[display_key.to_sym] || value[display_key]) && (value[id_key.to_sym] || value[id_key])
18
+ protected
19
+
20
+ def id_detail
21
+ {
22
+ :label => _('id'),
23
+ :structured_label => _('Id'),
24
+ :key => @options[:id_key] || :id,
25
+ :id => true
26
+ }
13
27
  end
14
28
  end
15
29
 
16
- class Reference < Field
30
+ class SingleReference < Reference
31
+ def initialize_options
32
+ key = @options[:key]
33
+ display_field = @options[:display_field] || 'name'
34
+
35
+ @options[:id_key] ||= "#{key}_id"
36
+ @options[:display_field_key] ||= "#{key}_#{display_field}"
37
+ super
38
+ end
39
+
40
+ def display?(value)
41
+ id_key = @options[:id_key]
42
+ display_key = @options[:display_field_key]
43
+
44
+ (value[display_key.to_sym] || value[display_key]) && (value[id_key.to_sym] || value[id_key])
45
+ end
17
46
  end
18
47
 
19
48
  class Template < Reference
49
+ def initialize_options
50
+ super
51
+ @options[:details] << template_kind_detail
52
+ end
20
53
 
21
- def initialize(options={})
22
- options[:details] ||= [:template_kind_name]
23
- super(options)
54
+ def template_kind_detail
55
+ {
56
+ :structured_label => _('Kind'),
57
+ :key => :template_kind_name,
58
+ }
24
59
  end
25
60
  end
26
61
 
@@ -1,69 +1,106 @@
1
1
  module HammerCLIForeman::Output
2
2
  module Formatters
3
-
4
- class SingleReferenceFormatter < HammerCLI::Output::Formatters::FieldFormatter
5
-
3
+ class ReferenceFormatter < HammerCLI::Output::Formatters::FieldFormatter
6
4
  def tags
7
5
  [:flat]
8
6
  end
9
7
 
10
- def format(resource, field_params={})
11
- return "" if resource.nil?
12
-
13
- key = field_params[:key]
14
- display_field = field_params[:display_field] || 'name'
15
-
16
- id_key = "#{key}_id"
17
- display_key = "#{key}_#{display_field}"
18
-
19
- name = resource[display_key.to_sym] || resource[display_key]
20
- id = resource[id_key.to_sym] || resource[id_key]
21
-
8
+ # Parameters:
9
+ # :display_field_key - key where the formmatter will look for the main field to display, default is :name
10
+ # :details - detail fields to be displayed
11
+ # example format:
12
+ # :details => [
13
+ # { :label => _('Type'), :key => :provider_friendly_name, :structured_label => _('Type') },
14
+ # { :label => _('Id'), :key => :id }
15
+ # ]
16
+ def format(data, field_params={})
17
+ return "" if data.nil?
18
+
19
+ name = get_value(data, field_params[:display_field_key] || :name)
22
20
  context = field_params[:context] || {}
23
21
 
24
- out = "#{name}"
25
- out += " (id: #{id})" if context[:show_ids] && id
26
- out
22
+ details = format_details(data, field_params[:details] || [], context[:show_ids])
23
+ if details.empty?
24
+ "#{name}" if name
25
+ else
26
+ "#{name} (#{details.join(', ')})" if name
27
+ end
27
28
  end
28
29
 
29
- end
30
+ protected
31
+ def format_details(data, details, show_ids)
32
+ details = [details] unless details.is_a?(Array)
33
+
34
+ details.map do |detail|
35
+ if detail.is_a?(Hash)
36
+ next if detail[:id] && !show_ids
37
+ if detail[:label]
38
+ "#{detail[:label]}: #{get_value(data, detail[:key])}"
39
+ else
40
+ get_value(data, detail[:key])
41
+ end
42
+ else
43
+ get_value(data, detail)
44
+ end
45
+ end.compact
46
+ end
30
47
 
31
- class ReferenceFormatter < HammerCLI::Output::Formatters::FieldFormatter
48
+ def get_value(data, key)
49
+ data[key] || data[key.to_s]
50
+ end
51
+ end
32
52
 
53
+ class StructuredReferenceFormatter < HammerCLI::Output::Formatters::FieldFormatter
33
54
  def tags
34
- [:flat]
55
+ [:data]
35
56
  end
36
57
 
37
- def format(reference, field_params={})
38
- return "" if reference.nil? || reference == ""
39
-
40
- id_key = field_params[:id_key] || :id
41
- name_key = field_params[:name_key] || :name
42
-
43
- name = reference[name_key] || reference[name_key.to_s]
44
- id = reference[id_key] || reference[id_key.to_s]
45
-
46
- context = field_params[:context] || {}
47
-
48
- details = field_params[:details] || []
49
- details = [details] unless details.is_a? Array
50
- values = details.collect do |key|
51
- reference[key] || reference[key.to_s]
52
- end
53
- values << "id: #{id}" if context[:show_ids]
54
-
55
- if values.empty?
56
- "#{name}" if name
57
- else
58
- "#{name} (#{values.join(', ')})" if name && !values.empty?
58
+ # Parameters:
59
+ # :display_field_key - key where the formmatter will look for the main field to display, default is :name
60
+ # :details - detail fields to be displayed
61
+ # example format:
62
+ # :details => [
63
+ # { :label => _('Type'), :key => :provider_friendly_name, :structured_label => _('Type') },
64
+ # { :label => _('Id'), :key => :id }
65
+ # ]
66
+ def format(data, field_params={})
67
+ return {} if data.nil? || data == ""
68
+
69
+ display_field_key = field_params[:display_field_key] || :name
70
+
71
+ # TODO: hardcoded name
72
+ formatted = {
73
+ _('Name') => get_value(data, display_field_key)
74
+ }
75
+
76
+ details = field_params[:details]
77
+ details = [details] unless details.is_a?(Array)
78
+
79
+ details.map do |detail|
80
+ if detail.is_a?(Hash)
81
+ label = detail[:structured_label]
82
+ label = detail[:label].capitalize if !label && detail[:label]
83
+ if label
84
+ formatted[label] = get_value(data, detail[:key])
85
+ end
86
+ end
59
87
  end
88
+ formatted
60
89
  end
61
90
 
91
+ protected
92
+ def get_value(data, key)
93
+ data[key] || data[key.to_s]
94
+ end
62
95
  end
63
96
 
64
- HammerCLI::Output::Output.register_formatter(SingleReferenceFormatter.new, :SingleReference)
97
+ HammerCLI::Output::Output.register_formatter(ReferenceFormatter.new, :SingleReference)
98
+ HammerCLI::Output::Output.register_formatter(StructuredReferenceFormatter.new, :SingleReference)
99
+
65
100
  HammerCLI::Output::Output.register_formatter(ReferenceFormatter.new, :Reference)
101
+ HammerCLI::Output::Output.register_formatter(StructuredReferenceFormatter.new, :Reference)
66
102
  HammerCLI::Output::Output.register_formatter(ReferenceFormatter.new, :Template)
67
-
103
+ HammerCLI::Output::Output.register_formatter(StructuredReferenceFormatter.new, :Template)
68
104
  end
69
105
  end
106
+
@@ -1,5 +1,28 @@
1
1
  module HammerCLIForeman
2
2
 
3
+ module SubnetUpdateCreateCommons
4
+
5
+ def self.included(base)
6
+ base.option "--dns", "DNS_NAME", _("DNS Proxy to use within this subnet")
7
+ base.option "--dhcp", "DHCP_NAME", _("DHCP Proxy to use within this subnet")
8
+ base.option "--tftp", "TFTP_NAME", _("TFTP Proxy to use within this subnet")
9
+ end
10
+
11
+ def request_params
12
+ params = super
13
+ params['subnet']["dns_id"] ||= proxy_feature_id(option_dns) if option_dns
14
+ params['subnet']["dhcp_id"] ||= proxy_feature_id(option_dhcp) if option_dhcp
15
+ params['subnet']["tftp_id"] ||= proxy_feature_id(option_tftp) if option_tftp
16
+ params
17
+ end
18
+
19
+ private
20
+
21
+ def proxy_feature_id(name)
22
+ resolver.smart_proxy_id('option_name' => name) if name
23
+ end
24
+ end
25
+
3
26
  class Subnet < HammerCLIForeman::Command
4
27
 
5
28
  resource :subnets
@@ -55,6 +78,7 @@ module HammerCLIForeman
55
78
 
56
79
 
57
80
  class CreateCommand < HammerCLIForeman::CreateCommand
81
+ include SubnetUpdateCreateCommons
58
82
 
59
83
  success_message _("Subnet created.")
60
84
  failure_message _("Could not create the subnet")
@@ -64,6 +88,7 @@ module HammerCLIForeman
64
88
 
65
89
 
66
90
  class UpdateCommand < HammerCLIForeman::UpdateCommand
91
+ include SubnetUpdateCreateCommons
67
92
 
68
93
  success_message _("Subnet updated.")
69
94
  failure_message _("Could not update the subnet")
@@ -1,5 +1,5 @@
1
1
  module HammerCLIForeman
2
2
  def self.version
3
- @version ||= Gem::Version.new '0.14.0'
3
+ @version ||= Gem::Version.new '0.15.0'
4
4
  end
5
5
  end
@@ -1,6 +1,15 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  describe 'compute-resource' do
4
+ let(:base_cmd) { ['compute-resource'] }
5
+ let(:base_params) { ['--id=1'] }
6
+ let(:compute_resource) do
7
+ {
8
+ :id => 1,
9
+ :name => 'resource'
10
+ }
11
+ end
12
+
4
13
  describe 'create' do
5
14
  before do
6
15
  @cmd = %w(compute-resource create)
@@ -114,4 +123,255 @@ describe 'compute-resource' do
114
123
  assert_cmd(success_result("Compute resource created.\n"), result)
115
124
  end
116
125
  end
126
+
127
+ describe 'clusters' do
128
+ let(:cmd) { base_cmd << 'clusters' }
129
+ let(:cluster1) { { id: 1, name: 'cluster1' } }
130
+ let(:cluster2) { { id: 2, name: 'cluster2' } }
131
+ let(:clusters) { [cluster1, cluster2] }
132
+
133
+ it 'lists available clusters for a compute resource' do
134
+ api_expects(:compute_resources, :available_clusters, 'clusters').with_params(
135
+ 'id' => '1'
136
+ ).returns(index_response(clusters))
137
+
138
+ output = IndexMatcher.new(
139
+ [
140
+ %w[ID NAME],
141
+ %w[1 cluster1],
142
+ %w[2 cluster2]
143
+ ]
144
+ )
145
+ expected_result = success_result(output)
146
+
147
+ result = run_cmd(cmd + base_params)
148
+ assert_cmd(expected_result, result)
149
+ end
150
+ end
151
+
152
+ describe 'networks' do
153
+ let(:cmd) { base_cmd << 'networks' }
154
+ let(:network1) { { id: 1, name: 'network1' } }
155
+ let(:network2) { { id: 2, name: 'network2' } }
156
+ let(:networks) { [network1, network2] }
157
+
158
+ it 'lists available networks for a compute resource' do
159
+ api_expects(:compute_resources, :available_networks, 'networks').with_params(
160
+ 'id' => '1'
161
+ ).returns(index_response(networks))
162
+
163
+ output = IndexMatcher.new(
164
+ [
165
+ %w[ID NAME],
166
+ %w[1 network1],
167
+ %w[2 network2]
168
+ ]
169
+ )
170
+ expected_result = success_result(output)
171
+
172
+ result = run_cmd(cmd + base_params)
173
+ assert_cmd(expected_result, result)
174
+ end
175
+ end
176
+
177
+ describe 'images' do
178
+ let(:cmd) { base_cmd << 'images' }
179
+ let(:image1) { { id: 1, name: 'image1' } }
180
+ let(:image2) { { id: 2, name: 'image2' } }
181
+ let(:images) { [image1, image2] }
182
+
183
+ it 'lists available images for a compute resource' do
184
+ api_expects(:compute_resources, :available_images, 'images').with_params(
185
+ 'id' => '1'
186
+ ).returns(index_response(images))
187
+
188
+ output = IndexMatcher.new(
189
+ [
190
+ %w[ID NAME],
191
+ %w[1 image1],
192
+ %w[2 image2]
193
+ ]
194
+ )
195
+ expected_result = success_result(output)
196
+
197
+ result = run_cmd(cmd + base_params)
198
+ assert_cmd(expected_result, result)
199
+ end
200
+ end
201
+
202
+ describe 'flavors' do
203
+ let(:cmd) { base_cmd << 'flavors' }
204
+ let(:flavor1) { { id: 1, name: 'flavor1' } }
205
+ let(:flavor2) { { id: 2, name: 'flavor2' } }
206
+ let(:flavors) { [flavor1, flavor2] }
207
+
208
+ it 'lists available flavors for a compute resource' do
209
+ api_expects(:compute_resources, :available_flavors, 'flavors').with_params(
210
+ 'id' => '1'
211
+ ).returns(index_response(flavors))
212
+
213
+ output = IndexMatcher.new(
214
+ [
215
+ %w[ID NAME],
216
+ %w[1 flavor1],
217
+ %w[2 flavor2]
218
+ ]
219
+ )
220
+ expected_result = success_result(output)
221
+
222
+ result = run_cmd(cmd + base_params)
223
+ assert_cmd(expected_result, result)
224
+ end
225
+ end
226
+
227
+ describe 'folders' do
228
+ let(:cmd) { base_cmd << 'folders' }
229
+ let(:folder1) { { id: 1, name: 'folder1' } }
230
+ let(:folder2) { { id: 2, name: 'folder2' } }
231
+ let(:folders) { [folder1, folder2] }
232
+
233
+ it 'lists available folders for a compute resource' do
234
+ api_expects(:compute_resources, :available_folders, 'folders').with_params(
235
+ 'id' => '1'
236
+ ).returns(index_response(folders))
237
+
238
+ output = IndexMatcher.new(
239
+ [
240
+ %w[ID NAME],
241
+ %w[1 folder1],
242
+ %w[2 folder2]
243
+ ]
244
+ )
245
+ expected_result = success_result(output)
246
+
247
+ result = run_cmd(cmd + base_params)
248
+ assert_cmd(expected_result, result)
249
+ end
250
+ end
251
+
252
+ describe 'zones' do
253
+ let(:cmd) { base_cmd << 'zones' }
254
+ let(:zone1) { { id: 1, name: 'zone1' } }
255
+ let(:zone2) { { id: 2, name: 'zone2' } }
256
+ let(:zones) { [zone1, zone2] }
257
+
258
+ it 'lists available zones for a compute resource' do
259
+ api_expects(:compute_resources, :available_zones, 'zones').with_params(
260
+ 'id' => '1'
261
+ ).returns(index_response(zones))
262
+
263
+ output = IndexMatcher.new(
264
+ [
265
+ %w[ID NAME],
266
+ %w[1 zone1],
267
+ %w[2 zone2]
268
+ ]
269
+ )
270
+ expected_result = success_result(output)
271
+
272
+ result = run_cmd(cmd + base_params)
273
+ assert_cmd(expected_result, result)
274
+ end
275
+ end
276
+
277
+ describe 'resource_pools' do
278
+ let(:cmd) { base_cmd << 'resource-pools' }
279
+ let(:params) { base_params + ['--cluster-id=1'] }
280
+ let(:resource_pool1) { { id: 1, name: 'resource_pool1' } }
281
+ let(:resource_pool2) { { id: 2, name: 'resource_pool2' } }
282
+ let(:resource_pools) { [resource_pool1, resource_pool2] }
283
+
284
+ it 'lists available resource_pools for a compute resource' do
285
+ api_expects(:compute_resources, :available_resource_pools, 'resource-pools').with_params(
286
+ 'id' => '1', 'cluster_id' => '1'
287
+ ).returns(index_response(resource_pools))
288
+
289
+ output = IndexMatcher.new(
290
+ [
291
+ %w[ID NAME],
292
+ %w[1 resource_pool1],
293
+ %w[2 resource_pool2]
294
+ ]
295
+ )
296
+ expected_result = success_result(output)
297
+
298
+ result = run_cmd(cmd + params)
299
+ assert_cmd(expected_result, result)
300
+ end
301
+ end
302
+
303
+ describe 'storage_domains' do
304
+ let(:cmd) { base_cmd << 'storage-domains' }
305
+ let(:storage_domain1) { { id: 1, name: 'storage_domain1' } }
306
+ let(:storage_domain2) { { id: 2, name: 'storage_domain2' } }
307
+ let(:storage_domains) { [storage_domain1, storage_domain2] }
308
+
309
+ it 'lists available storage_domains for a compute resource' do
310
+ api_expects(:compute_resources, :available_storage_domains, 'storage-domains').with_params(
311
+ 'id' => '1'
312
+ ).returns(index_response(storage_domains))
313
+
314
+ output = IndexMatcher.new(
315
+ [
316
+ %w[ID NAME],
317
+ %w[1 storage_domain1],
318
+ %w[2 storage_domain2]
319
+ ]
320
+ )
321
+ expected_result = success_result(output)
322
+
323
+ result = run_cmd(cmd + base_params)
324
+ assert_cmd(expected_result, result)
325
+ end
326
+ end
327
+
328
+ describe 'storage_pods' do
329
+ let(:cmd) { base_cmd << 'storage-pods' }
330
+ let(:storage_pod1) { { id: 1, name: 'storage_pod1' } }
331
+ let(:storage_pod2) { { id: 2, name: 'storage_pod2' } }
332
+ let(:storage_pods) { [storage_pod1, storage_pod2] }
333
+
334
+ it 'lists available storage_pods for a compute resource' do
335
+ api_expects(:compute_resources, :available_storage_pods, 'storage-pods').with_params(
336
+ 'id' => '1'
337
+ ).returns(index_response(storage_pods))
338
+
339
+ output = IndexMatcher.new(
340
+ [
341
+ %w[ID NAME],
342
+ %w[1 storage_pod1],
343
+ %w[2 storage_pod2]
344
+ ]
345
+ )
346
+ expected_result = success_result(output)
347
+
348
+ result = run_cmd(cmd + base_params)
349
+ assert_cmd(expected_result, result)
350
+ end
351
+ end
352
+
353
+ describe 'security_groups' do
354
+ let(:cmd) { base_cmd << 'security-groups' }
355
+ let(:security_group1) { { id: 1, name: 'security_group1' } }
356
+ let(:security_group2) { { id: 2, name: 'security_group2' } }
357
+ let(:security_groups) { [security_group1, security_group2] }
358
+
359
+ it 'lists available security_groups for a compute resource' do
360
+ api_expects(:compute_resources, :available_security_groups, 'security-groups').with_params(
361
+ 'id' => '1'
362
+ ).returns(index_response(security_groups))
363
+
364
+ output = IndexMatcher.new(
365
+ [
366
+ %w[ID NAME],
367
+ %w[1 security_group1],
368
+ %w[2 security_group2]
369
+ ]
370
+ )
371
+ expected_result = success_result(output)
372
+
373
+ result = run_cmd(cmd + base_params)
374
+ assert_cmd(expected_result, result)
375
+ end
376
+ end
117
377
  end