morpheus-cli 7.0.6 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -294,6 +294,13 @@ class Morpheus::Cli::License
294
294
  elsif license['zoneTypesExcluded'] && license['zoneTypesExcluded'].size > 0
295
295
  description_cols["Excluded Clouds"] = lambda {|it| it['zoneTypesExcluded'].join(', ') }
296
296
  end
297
+
298
+ if license['taskTypes'] && license['taskTypes'].size > 0
299
+ description_cols["Included Tasks"] = lambda {|it| it['taskTypes'].join(', ') }
300
+ elsif license['taskTypesExcluded'] && license['taskTypesExcluded'].size > 0
301
+ description_cols["Excluded Tasks"] = lambda {|it| it['taskTypesExcluded'].join(', ') }
302
+ end
303
+
297
304
  print_description_list(description_cols, license)
298
305
  end
299
306
 
@@ -306,6 +313,7 @@ class Morpheus::Cli::License
306
313
  used_discovered_servers = current_usage['discoveredServers']
307
314
  used_hosts = current_usage['hosts']
308
315
  used_mvm = current_usage['mvm']
316
+ used_mvm_sockets = current_usage['mvmSockets']
309
317
  used_iac = current_usage['iac']
310
318
  used_xaas = current_usage['xaas']
311
319
  used_executions = current_usage['executions']
@@ -317,6 +325,7 @@ class Morpheus::Cli::License
317
325
  max_discovered_servers = license['maxDiscoveredServers']
318
326
  max_hosts = license['maxHosts']
319
327
  max_mvm = license['maxMvm']
328
+ max_mvm_sockets = license['maxMvmSockets']
320
329
  max_iac = license['maxIac']
321
330
  max_xaas = license['maxXaas']
322
331
  max_executions = license['maxExecutions']
@@ -328,7 +337,8 @@ class Morpheus::Cli::License
328
337
  out << cyan + "Managed Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_managed_servers, max_managed_servers, chart_opts) + cyan + used_managed_servers.to_s.rjust(8, ' ') + " / " + (max_managed_servers ? max_managed_servers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
329
338
  out << cyan + "Discovered Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_discovered_servers, max_discovered_servers, chart_opts) + cyan + used_discovered_servers.to_s.rjust(8, ' ') + " / " + (max_discovered_servers ? max_discovered_servers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
330
339
  out << cyan + "Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_hosts, max_hosts, chart_opts) + cyan + used_hosts.to_s.rjust(8, ' ') + " / " + (max_hosts ? max_hosts.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
331
- out << cyan + "MVM Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_mvm, max_mvm, chart_opts) + cyan + used_mvm.to_s.rjust(8, ' ') + " / " + (max_mvm ? max_mvm.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
340
+ out << cyan + "HPE VM Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_mvm, max_mvm, chart_opts) + cyan + used_mvm.to_s.rjust(8, ' ') + " / " + (max_mvm ? max_mvm.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
341
+ out << cyan + "HPE VM Sockets".rjust(label_width, ' ') + ": " + generate_usage_bar(used_mvm_sockets, max_mvm_sockets, chart_opts) + cyan + used_mvm_sockets.to_s.rjust(8, ' ') + " / " + (max_mvm_sockets ? max_mvm_sockets.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
332
342
  out << cyan + "Iac Deployments".rjust(label_width, ' ') + ": " + generate_usage_bar(used_iac, max_iac, chart_opts) + cyan + used_iac.to_s.rjust(8, ' ') + " / " + (max_iac ? max_iac.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
333
343
  out << cyan + "Xaas Instances".rjust(label_width, ' ') + ": " + generate_usage_bar(used_xaas, max_xaas, chart_opts) + cyan + used_xaas.to_s.rjust(8, ' ') + " / " + (max_xaas ? max_xaas.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
334
344
  out << cyan + "Executions".rjust(label_width, ' ') + ": " + generate_usage_bar(used_executions, max_executions, chart_opts) + cyan + used_executions.to_s.rjust(8, ' ') + " / " + (max_executions ? max_executions.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
@@ -16,7 +16,7 @@ class Morpheus::Cli::PluginsCommand
16
16
  params = {}
17
17
  filename = nil
18
18
  optparse = Morpheus::Cli::OptionParser.new do|opts|
19
- opts.banner = subcommand_usage("[name] [file]")
19
+ opts.banner = subcommand_usage("[file]")
20
20
  build_standard_post_options(opts, options)
21
21
  opts.footer = <<-EOT
22
22
  Upload a plugin file.
@@ -55,7 +55,7 @@ EOT
55
55
  params = {}
56
56
  filename = nil
57
57
  optparse = Morpheus::Cli::OptionParser.new do|opts|
58
- opts.banner = subcommand_usage("[name] [file]")
58
+ opts.banner = subcommand_usage("")
59
59
  build_standard_post_options(opts, options)
60
60
  opts.footer = <<-EOT
61
61
  Check for installed plugins that have available updates.
@@ -9,7 +9,7 @@ class Morpheus::Cli::Processes
9
9
 
10
10
  set_command_name :'process'
11
11
 
12
- register_subcommands :list, :get, {:'get-event' => :event_details}
12
+ register_subcommands :list, :get, {:'get-event' => :event_details}, :retry, :cancel
13
13
 
14
14
  # alias_subcommand :details, :get
15
15
  # set_default_subcommand :list
@@ -346,6 +346,76 @@ class Morpheus::Cli::Processes
346
346
  end
347
347
  end
348
348
 
349
+ def retry(args)
350
+ options = {}
351
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
352
+ opts.banner = subcommand_usage("[id]")
353
+ build_standard_update_options(opts, options, [:auto_confirm])
354
+ opts.footer = <<-EOT
355
+ Retry a process.
356
+ [id] is required. This is the id of a process.
357
+ Only a process that is failed or cancelled and is of a retryable type can be retried.
358
+ EOT
359
+ end
360
+ optparse.parse!(args)
361
+ verify_args!(args:args, optparse:optparse, count:1)
362
+ connect(options)
363
+ # process = find_process_by_id(args[0])
364
+ # return 1 if process.nil?
365
+ process_id = args[0]
366
+ payload = parse_payload(options)
367
+ if payload.nil?
368
+ payload = parse_passed_options(options)
369
+ # prompt
370
+ end
371
+ confirm!("Are you sure you would like to retry process #{process_id}?", options)
372
+ @processes_interface.setopts(options)
373
+ if options[:dry_run]
374
+ print_dry_run @processes_interface.dry.retry(process_id, payload)
375
+ return
376
+ end
377
+ json_response = @processes_interface.retry(process_id, payload)
378
+ render_response(json_response, options) do
379
+ print_green_success "Retrying process #{process_id}"
380
+ end
381
+ return 0, nil
382
+ end
383
+
384
+ def cancel(args)
385
+ options = {}
386
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
387
+ opts.banner = subcommand_usage("[id]")
388
+ build_standard_update_options(opts, options, [:auto_confirm])
389
+ opts.footer = <<-EOT
390
+ Cancel a process.
391
+ [id] is required. This is the id of a process.
392
+ Only a process that is currently running and is of a cancellable type can be canceled.
393
+ EOT
394
+ end
395
+ optparse.parse!(args)
396
+ verify_args!(args:args, optparse:optparse, count:1)
397
+ connect(options)
398
+ # process = find_process_by_id(args[0])
399
+ # return 1 if process.nil?
400
+ process_id = args[0]
401
+ payload = parse_payload(options)
402
+ if payload.nil?
403
+ payload = parse_passed_options(options)
404
+ # prompt
405
+ end
406
+ confirm!("Are you sure you would like to cancel process #{process_id}?", options)
407
+ @processes_interface.setopts(options)
408
+ if options[:dry_run]
409
+ print_dry_run @processes_interface.dry.cancel(process_id, payload)
410
+ return
411
+ end
412
+ json_response = @processes_interface.cancel(process_id, payload)
413
+ render_response(json_response, options) do
414
+ print_green_success "Cancelling process #{process_id}"
415
+ end
416
+ return 0, nil
417
+ end
418
+
349
419
  def event_details(args)
350
420
  options = {}
351
421
  params = {}
@@ -35,6 +35,9 @@ class Morpheus::Cli::Setup
35
35
  opts.on('--hubmode MODE','--hubmode MODE', "Choose an option for hub registration possible values are login, register, skip.") do |val|
36
36
  options[:hubmode] = val.to_s.downcase
37
37
  end
38
+ opts.on('--license KEY', String, "License key to install") do |val|
39
+ options[:license] = val
40
+ end
38
41
  opts.on('--force','--force', "Force setup, make api request even if setup is unavailable.") do
39
42
  options[:force] = true
40
43
  end
@@ -127,10 +130,10 @@ EOT
127
130
  puts "It looks like you are the first one here, so let's begin."
128
131
  print reset, "\n"
129
132
  # print "\n"
130
- unless Morpheus::Cli::OptionTypes.confirm("Would you like to setup and initialize the remote appliance now?", options)
131
- return 9, "aborted command"
132
- end
133
- print "\n"
133
+ # unless Morpheus::Cli::OptionTypes.confirm("Would you like to setup and initialize the remote appliance now?", options)
134
+ # return 9, "aborted command"
135
+ # end
136
+ # print "\n"
134
137
  hubmode = nil
135
138
  hub_init_payload = nil # gets included as payload for hub scoped like hub.email
136
139
  if hub_settings['enabled']
@@ -354,6 +357,15 @@ EOT
354
357
  payload.delete('hub')
355
358
  end
356
359
 
360
+ # License Key prompt
361
+ print_h2 "License", options
362
+ if options[:license]
363
+ payload['licenseKey'] = options[:license].strip
364
+ else
365
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'licenseKey', 'fieldLabel' => 'License Key', 'type' => 'text', 'description' => "Enter a License Key to install now or leave blank to use a community license or install one manually later."}], options[:options])
366
+ key = v_prompt['licenseKey']
367
+ payload['licenseKey'] = key.strip if !key.to_s.strip.empty?
368
+ end
357
369
  end
358
370
 
359
371
  # ok, make the api request
@@ -383,24 +395,26 @@ EOT
383
395
  print reset
384
396
  #print "\n"
385
397
 
386
- if hubmode == 'skip'
387
- if ::Morpheus::Cli::OptionTypes::confirm("Would you like to install your License Key now?", options.merge({:default => true}))
388
- cmd_res = Morpheus::Cli::License.new.install([] + (options[:remote] ? ["-r",options[:remote]] : []))
389
- # license_is_valid = cmd_res != false
398
+ unless options[:no_prompt]
399
+ if hubmode == 'skip' && payload['licenseKey'].to_s.empty?
400
+ if ::Morpheus::Cli::OptionTypes::confirm("Would you like to install your License Key now?", options.merge({:default => true}))
401
+ cmd_res = Morpheus::Cli::License.new.install([] + (options[:remote] ? ["-r",options[:remote]] : []))
402
+ # license_is_valid = cmd_res != false
403
+ end
390
404
  end
391
- end
392
405
 
393
- if ::Morpheus::Cli::OptionTypes::confirm("Would you like to create the first group now?", options.merge({:default => true}))
394
- cmd_res = Morpheus::Cli::Groups.new.add(['--use'] + (options[:remote] ? ["-r",options[:remote]] : []))
406
+ if ::Morpheus::Cli::OptionTypes::confirm("Would you like to create the first group now?", options.merge({:default => true}))
407
+ cmd_res = Morpheus::Cli::Groups.new.add(['--use'] + (options[:remote] ? ["-r",options[:remote]] : []))
395
408
 
396
- #print "\n"
409
+ #print "\n"
397
410
 
398
- # if cmd_res !=
399
- if ::Morpheus::Cli::OptionTypes::confirm("Would you like to create the first cloud now?", options.merge({:default => true}))
400
- cmd_res = Morpheus::Cli::Clouds.new.add([] + (options[:remote] ? ["-r",options[:remote]] : []))
401
- #print "\n"
402
- end
403
- # end
411
+ # if cmd_res !=
412
+ if ::Morpheus::Cli::OptionTypes::confirm("Would you like to create the first cloud now?", options.merge({:default => true}))
413
+ cmd_res = Morpheus::Cli::Clouds.new.add([] + (options[:remote] ? ["-r",options[:remote]] : []))
414
+ #print "\n"
415
+ end
416
+ # end
417
+ end
404
418
  end
405
419
  print "\n",reset
406
420
  return exit_code, err
@@ -531,6 +531,7 @@ EOT
531
531
  v_prompt.deep_compact!
532
532
  virtual_image_payload.deep_merge!(v_prompt)
533
533
  virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
534
+ upload_type = virtual_image_payload.delete('uploadType') # not used serverside
534
535
  virtual_image_payload['imageType'] = image_type['code']
535
536
  storage_provider_id = virtual_image_payload.delete('storageProviderId')
536
537
  if !storage_provider_id.to_s.empty?
@@ -551,6 +552,11 @@ EOT
551
552
  if virtual_image_payload && virtual_image_payload['imageType'] == 'vmware'
552
553
  virtual_image_payload['imageType'] == 'vmdk'
553
554
  end
555
+ # no need to make second request anymore, just include virtualImage.url
556
+ if file_url
557
+ virtual_image_payload['url'] = file_url
558
+ file_url = nil
559
+ end
554
560
  #payload = {'virtualImage' => virtual_image_payload}
555
561
  payload.deep_merge!({'virtualImage' => virtual_image_payload})
556
562
  end
@@ -967,7 +973,7 @@ EOT
967
973
  {'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Install Agent?', 'displayOrder' => 6},
968
974
  {'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' => 7},
969
975
  {'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false, 'description' => 'Enter an SSH Password', 'displayOrder' => 8},
970
- {'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 9},
976
+ {'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Bucket', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 9},
971
977
  {'fieldName' => 'userData', 'fieldLabel' => 'Cloud-Init User Data', 'type' => 'textarea', 'required' => false, 'displayOrder' => 10},
972
978
  {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 40},
973
979
  {'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Auto Join Domain?', 'category' => 'advanced', 'displayOrder' => 40},
@@ -999,7 +1005,9 @@ EOT
999
1005
  tmp_option_types.reject! {|opt| ['storageProviderId', 'userData', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
1000
1006
  else
1001
1007
  if include_file_selection
1002
- tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 11}
1008
+ tmp_option_types << {'code' => 'virtualImage.uploadType', 'fieldName' => 'uploadType', 'fieldLabel' => 'Create Image ID', 'type' => 'select', 'selectOptions' => [{'name' => 'File', 'value' => 'file'},{'name' => 'URL/Path', 'value' => 'url'},{'name' => 'None', 'value' => 'none'}], 'defaultValue' => 'file', 'required' => false, 'description' => 'Choose upload type: file, url or none', 'displayOrder' => 11}
1009
+ tmp_option_types << {'dependsOnCode' => 'virtualImage.uploadType:file', 'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 12}
1010
+ tmp_option_types << {'dependsOnCode' => 'virtualImage.uploadType:url', 'fieldName' => 'url', 'fieldLabel' => 'URL/Path', 'type' => 'text', 'required' => false, 'description' => 'Enter URL/Path to virtual image file(s)', 'displayOrder' => 13}
1003
1011
  end
1004
1012
  end
1005
1013
  end
@@ -2150,25 +2150,51 @@ module Morpheus::Cli::ProvisioningHelper
2150
2150
  end
2151
2151
 
2152
2152
  # Tenants
2153
+ default_stores = []
2154
+ default_targets = []
2153
2155
  unless excludes.include?('tenants')
2154
2156
  if !options[:tenants].nil?
2155
2157
  accounts = options[:tenants].collect {|id| id.to_i}
2156
2158
  elsif !options[:no_prompt]
2157
2159
  account_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'account', 'type' => 'select', 'fieldLabel' => 'Add Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account']
2158
2160
 
2159
- if !account_id.nil?
2161
+ unless account_id.nil?
2160
2162
  accounts << account_id
2161
2163
  available_accounts = available_accounts.reject {|it| it['value'] == account_id}
2162
2164
 
2165
+ # Prompt default store / target
2166
+ if options[:for_datastore]
2167
+ if Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultTarget', 'type' => 'checkbox', 'fieldLabel' => 'Default', 'required' => false, 'description' => 'Designate as Default Store.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultTarget']
2168
+ default_targets << account_id
2169
+ end
2170
+ if Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultStore', 'type' => 'checkbox', 'fieldLabel' => 'Image Target', 'required' => false, 'description' => 'Designate as Image Target.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultStore']
2171
+ default_stores << account_id
2172
+ end
2173
+ end
2174
+
2163
2175
  while !available_accounts.empty? && (account_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'account', 'type' => 'select', 'fieldLabel' => 'Add Another Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account'])
2164
2176
  if !account_id.nil?
2165
2177
  accounts << account_id
2166
2178
  available_accounts = available_accounts.reject {|it| it['value'] == account_id}
2179
+
2180
+ # Prompt default store / target
2181
+ if options[:for_datastore]
2182
+ if Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultTarget', 'type' => 'checkbox', 'fieldLabel' => 'Default', 'required' => false, 'description' => 'Designate as Default Store.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultTarget']
2183
+ default_targets << account_id
2184
+ end
2185
+ if Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultStore', 'type' => 'checkbox', 'fieldLabel' => 'Image Target', 'required' => false, 'description' => 'Designate as Image Target.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultStore']
2186
+ default_stores << account_id
2187
+ end
2188
+ end
2167
2189
  end
2168
2190
  end
2169
2191
  end
2170
2192
  end
2171
- permissions['tenantPermissions'] = {'accounts' => accounts}
2193
+ if options[:for_datastore]
2194
+ permissions['tenantPermissions'] = accounts.collect {|it| {'id' => it, 'defaultStore' => default_stores.include?(it), 'defaultTarget' => default_targets.include?(it)}}
2195
+ else
2196
+ permissions['tenantPermissions'] = {'accounts' => accounts}
2197
+ end
2172
2198
  end
2173
2199
  end
2174
2200
  permissions
@@ -404,6 +404,9 @@ module Morpheus
404
404
  value = password_prompt(option_type)
405
405
  elsif option_type['type'] == 'checkbox'
406
406
  value = checkbox_prompt(option_type)
407
+ if options[:checkbox_as_boolean]
408
+ value = (value == 'on')
409
+ end
407
410
  elsif option_type['type'] == 'radio'
408
411
  value = radio_prompt(option_type)
409
412
  elsif option_type['type'] == 'textarea'
@@ -1324,15 +1327,19 @@ module Morpheus
1324
1327
 
1325
1328
  # supports multi-part fields via config.fields
1326
1329
  # {"fields": [{"name":"tag", "required":true, "label": "Tag"}, {"name":"value", "required":false, "label": "Scope"}]}
1330
+ min_count = option_type['minCount'] || 1
1331
+ count = 0
1332
+
1327
1333
  if option_type['config']['fields']
1328
- while (option_type['required'] && rtn.empty?) || self.confirm("Add#{rtn.empty? ? '': ' more'} #{option_type['fieldLabel']}?", {:default => false})
1334
+ while (option_type['required'] && (rtn.empty? || count < min_count)) || self.confirm("Add#{rtn.empty? ? '': ' more'} #{option_type['fieldLabel']}?", {:default => false})
1329
1335
  rtn ||= []
1330
1336
  value = {}
1331
1337
  option_type['config']['fields'].each do |field|
1332
1338
  field_label = field['label'] || field['name'].capitalize
1333
- value[field['name']] = generic_prompt(option_type.merge({'fieldLabel' => field_label, 'required' => field['required'], 'description' => "#{option_type['fieldLabel']} #{field_label}"}))
1339
+ value[field['name']] = generic_prompt(option_type.merge({'fieldLabel' => min_count > 1 ? "#{field_label} #{count + 1}" : field_label, 'required' => field['required'], 'description' => "#{option_type['fieldLabel']} #{field_label}"}))
1334
1340
  end
1335
1341
  rtn << value
1342
+ count += 1
1336
1343
  end
1337
1344
  else
1338
1345
  if rtn = generic_prompt(option_type)
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "7.0.6"
4
+ VERSION = "8.0.0"
5
5
  end
6
6
  end
@@ -478,6 +478,18 @@ def format_name_values(obj)
478
478
  end
479
479
  end
480
480
 
481
+ def format_name_and_id(obj)
482
+ if(obj.is_a?(Array))
483
+ return "" if obj.empty? # && hide_empty
484
+ names, ids = obj.collect {|it| it['name'] rescue "" }, obj.collect {|it| it['id'] rescue "" }
485
+ "#{names.join(", ")} [#{ids.join(",")}]"
486
+ elsif(obj.is_a?(Hash))
487
+ "#{obj['name']} [#{obj['id']}]" rescue ""
488
+ else
489
+ object.to_s
490
+ end
491
+ end
492
+
481
493
  def a_or_an(v)
482
494
  v.to_s =~ /^[aeiou]/i ? "an" : "a"
483
495
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.6
4
+ version: 8.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2024-09-11 00:00:00.000000000 Z
14
+ date: 2024-11-15 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: public_suffix
@@ -289,6 +289,7 @@ files:
289
289
  - lib/morpheus/api/library_container_upgrades_interface.rb
290
290
  - lib/morpheus/api/library_instance_types_interface.rb
291
291
  - lib/morpheus/api/library_layouts_interface.rb
292
+ - lib/morpheus/api/library_operating_systems_interface.rb
292
293
  - lib/morpheus/api/library_spec_template_types_interface.rb
293
294
  - lib/morpheus/api/library_spec_templates_interface.rb
294
295
  - lib/morpheus/api/license_interface.rb
@@ -473,6 +474,7 @@ files:
473
474
  - lib/morpheus/cli/commands/library_forms_command.rb
474
475
  - lib/morpheus/cli/commands/library_instance_types_command.rb
475
476
  - lib/morpheus/cli/commands/library_layouts_command.rb
477
+ - lib/morpheus/cli/commands/library_operating_systems_command.rb
476
478
  - lib/morpheus/cli/commands/library_option_lists_command.rb
477
479
  - lib/morpheus/cli/commands/library_option_types_command.rb
478
480
  - lib/morpheus/cli/commands/library_spec_templates_command.rb
@@ -667,7 +669,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
667
669
  - !ruby/object:Gem::Version
668
670
  version: '0'
669
671
  requirements: []
670
- rubygems_version: 3.1.6
672
+ rubygems_version: 3.4.10
671
673
  signing_key:
672
674
  specification_version: 4
673
675
  summary: Provides CLI Interface to the Morpheus Public/Private Cloud Appliance