morpheus-cli 5.4.5.1 → 5.5.1.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -0
  4. data/lib/morpheus/api/backup_service_types_interface.rb +9 -0
  5. data/lib/morpheus/api/backup_services_interface.rb +9 -0
  6. data/lib/morpheus/api/clusters_interface.rb +12 -0
  7. data/lib/morpheus/api/network_pool_servers_interface.rb +7 -0
  8. data/lib/morpheus/api/prices_interface.rb +6 -0
  9. data/lib/morpheus/api/scale_thresholds_interface.rb +9 -0
  10. data/lib/morpheus/cli/cli_command.rb +55 -23
  11. data/lib/morpheus/cli/commands/apps.rb +1 -1
  12. data/lib/morpheus/cli/commands/backup_services_command.rb +44 -0
  13. data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
  14. data/lib/morpheus/cli/commands/clouds.rb +67 -31
  15. data/lib/morpheus/cli/commands/clusters.rb +66 -5
  16. data/lib/morpheus/cli/commands/cypher_command.rb +22 -23
  17. data/lib/morpheus/cli/commands/hosts.rb +5 -1
  18. data/lib/morpheus/cli/commands/instances.rb +11 -11
  19. data/lib/morpheus/cli/commands/integrations_command.rb +1 -1
  20. data/lib/morpheus/cli/commands/invoices_command.rb +8 -1
  21. data/lib/morpheus/cli/commands/jobs_command.rb +45 -225
  22. data/lib/morpheus/cli/commands/library_container_types_command.rb +52 -3
  23. data/lib/morpheus/cli/commands/library_option_lists_command.rb +18 -8
  24. data/lib/morpheus/cli/commands/library_option_types_command.rb +56 -62
  25. data/lib/morpheus/cli/commands/load_balancers.rb +11 -19
  26. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +5 -2
  27. data/lib/morpheus/cli/commands/prices_command.rb +25 -11
  28. data/lib/morpheus/cli/commands/roles.rb +475 -70
  29. data/lib/morpheus/cli/commands/scale_thresholds.rb +103 -0
  30. data/lib/morpheus/cli/commands/tasks.rb +64 -22
  31. data/lib/morpheus/cli/commands/user_sources_command.rb +107 -39
  32. data/lib/morpheus/cli/commands/users.rb +10 -10
  33. data/lib/morpheus/cli/commands/view.rb +1 -0
  34. data/lib/morpheus/cli/commands/workflows.rb +21 -14
  35. data/lib/morpheus/cli/error_handler.rb +13 -4
  36. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  37. data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
  38. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +3 -3
  39. data/lib/morpheus/cli/mixins/jobs_helper.rb +173 -0
  40. data/lib/morpheus/cli/mixins/print_helper.rb +120 -38
  41. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -3
  42. data/lib/morpheus/cli/mixins/rest_command.rb +58 -15
  43. data/lib/morpheus/cli/option_types.rb +69 -13
  44. data/lib/morpheus/cli/version.rb +1 -1
  45. data/lib/morpheus/logging.rb +6 -8
  46. data/lib/morpheus/routes.rb +3 -5
  47. metadata +9 -4
@@ -148,6 +148,28 @@ module Morpheus::Cli::RestCommand
148
148
 
149
149
  alias :set_rest_interface_name :rest_interface_name=
150
150
 
151
+ # rest_perms_config enables and configures permissions prompt
152
+ def rest_perms_config
153
+ @rest_perms_config || {}
154
+ end
155
+
156
+ def rest_perms_config=(v)
157
+ @rest_perms_config = v
158
+ end
159
+
160
+ alias :set_rest_perms_config :rest_perms_config=
161
+
162
+ # rest_option_context_map specifies context mapping during option prompt. default is domain => ''
163
+ def rest_option_context_map
164
+ @option_context_map || {'domain' => ''}
165
+ end
166
+
167
+ def rest_option_context_map=(v)
168
+ @option_context_map = v
169
+ end
170
+
171
+ alias :set_rest_option_context_map :rest_option_context_map=
172
+
151
173
  # rest_has_type indicates a resource has a type. default is false
152
174
  def rest_has_type
153
175
  @rest_has_type == true
@@ -329,6 +351,14 @@ module Morpheus::Cli::RestCommand
329
351
  self.class.rest_interface_name
330
352
  end
331
353
 
354
+ def rest_perms_config
355
+ self.class.rest_perms_config
356
+ end
357
+
358
+ def rest_option_context_map
359
+ self.class.rest_option_context_map
360
+ end
361
+
332
362
  # returns the default rest interface, allows using rest_interface_name = "your"
333
363
  # or override this method to return @your_interface if needed
334
364
  def rest_interface
@@ -567,7 +597,8 @@ EOT
567
597
  def add(args)
568
598
  record_type = nil
569
599
  record_type_id = nil
570
- options = {}
600
+ options = {:options => {:context_map => rest_option_context_map}}
601
+ #respond_to?("#{rest_key}_option_context_map", true) ? send("#{rest_key}_option_context_map") : {'domain' => ''}}}
571
602
  option_types = respond_to?("add_#{rest_key}_option_types", true) ? send("add_#{rest_key}_option_types") : []
572
603
  advanced_option_types = respond_to?("add_#{rest_key}_advanced_option_types", true) ? send("add_#{rest_key}_advanced_option_types") : []
573
604
  type_option_type = option_types.find {|it| it['fieldName'] == 'type'}
@@ -600,25 +631,25 @@ EOT
600
631
  verify_args!(args:args, optparse:optparse, count: 0)
601
632
  end
602
633
  connect(options)
603
- # load or prompt for type
604
- if rest_has_type && type_option_type.nil?
605
- if record_type_id.nil?
606
- #raise_command_error "#{rest_type_label} is required.\n#{optparse}"
607
- type_list = rest_type_interface.list({max:10000, creatable:true})[rest_type_list_key]
608
- type_dropdown_options = respond_to?("#{rest_key}_type_list_to_options", true) ? send("#{rest_key}_type_list_to_options", type_list) : type_list.collect {|it| {'name' => it['name'], 'value' => it['code']} }
609
- record_type_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => rest_type_label, 'type' => 'select', 'selectOptions' => type_dropdown_options, 'required' => true}], options[:options], @api_client)['type']
610
- end
611
- record_type = rest_type_find_by_name_or_id(record_type_id)
612
- if record_type.nil?
613
- return 1, "#{rest_type_label} not found for '#{record_type_id}"
614
- end
615
- end
616
634
  passed_options = parse_passed_options(options)
617
635
  payload = {}
618
636
  if options[:payload]
619
637
  payload = options[:payload]
620
638
  payload.deep_merge!({rest_object_key => passed_options})
621
639
  else
640
+ # load or prompt for type
641
+ if rest_has_type && type_option_type.nil?
642
+ if record_type_id.nil?
643
+ #raise_command_error "#{rest_type_label} is required.\n#{optparse}"
644
+ type_list = rest_type_interface.list({max:10000, creatable:true})[rest_type_list_key]
645
+ type_dropdown_options = respond_to?("#{rest_key}_type_list_to_options", true) ? send("#{rest_key}_type_list_to_options", type_list) : type_list.collect {|it| {'name' => it['name'], 'value' => it['code']} }
646
+ record_type_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => rest_type_label, 'type' => 'select', 'selectOptions' => type_dropdown_options, 'required' => true}], options[:options], @api_client)['type']
647
+ end
648
+ record_type = rest_type_find_by_name_or_id(record_type_id)
649
+ if record_type.nil?
650
+ return 1, "#{rest_type_label} not found for '#{record_type_id}"
651
+ end
652
+ end
622
653
  record_payload = {}
623
654
  if record_name
624
655
  record_payload['name'] = record_name
@@ -667,7 +698,7 @@ EOT
667
698
  end
668
699
  end
669
700
  api_params = (options[:params] || {}).merge(record_payload)
670
- v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, api_params)
701
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, api_params, false, true)
671
702
  v_prompt.deep_compact!
672
703
  v_prompt.booleanize! # 'on' => true
673
704
  record_payload.deep_merge!(v_prompt)
@@ -679,6 +710,18 @@ EOT
679
710
  v_prompt.booleanize! # 'on' => true
680
711
  record_payload.deep_merge!(v_prompt)
681
712
  end
713
+ # permissions
714
+ if rest_perms_config[:enabled]
715
+ if rest_perms_config[:version] == 2
716
+ perms = prompt_permissions_v2(options.deep_merge(rest_perms_config[:options] || {}), rest_perms_config[:excludes] || [])
717
+ else
718
+ perms = prompt_permissions(options.deep_merge(rest_perms_config[:options] || {}), rest_perms_config[:excludes] || [])
719
+ end
720
+ if !rest_perms_config[:name].nil?
721
+ perms.transform_keys! {|k| k == 'resourcePermissions' ? rest_perms_config[:name] : k}
722
+ end
723
+ record_payload.merge!(perms)
724
+ end
682
725
  payload[rest_object_key] = record_payload
683
726
  end
684
727
  rest_interface.setopts(options)
@@ -61,11 +61,24 @@ module Morpheus
61
61
  if option_type['fieldName'] == 'sshHosts'
62
62
  option_type['type'] = 'multiText'
63
63
  end
64
+ # swap types to multiSelect when flag is set..
65
+ if option_type["config"] && ["true","on"].include?(option_type["config"]["multiSelect"].to_s)
66
+ if option_type["type"] == "typeahead"
67
+ option_type["type"] = "multiTypeahead"
68
+ elsif option_type["type"] == "select"
69
+ option_type["type"] = "multiSelect"
70
+ elsif option_type["type"] == "textarea"
71
+ option_type["type"] = "multiText"
72
+ end
73
+ end
64
74
  end
75
+
65
76
  # puts "Options Prompt #{options}"
66
77
  # Sort options by default, group, advanced
67
78
  cur_field_group = 'default'
68
- self.sorted_option_types(option_types).each do |option_type|
79
+ prompt_local_credentials = true
80
+ self.sort_option_types(option_types.reject {|it| it[:for_help_only]}).each do |option_type|
81
+ next if option_type['localCredential'] && !prompt_local_credentials
69
82
  context_map = results
70
83
  value = nil
71
84
  value_found = false
@@ -145,6 +158,10 @@ module Morpheus
145
158
  next if !found_dep_value
146
159
  end
147
160
 
161
+ # build parameters for option source api request
162
+ option_params = (option_type['noParams'] ? {} : (api_params || {}).deep_merge(results))
163
+ option_params.merge!(option_type['optionParams']) if option_type['optionParams']
164
+
148
165
  cur_namespace = options
149
166
  parent_context_map = context_map
150
167
  parent_ns = field_name
@@ -159,9 +176,26 @@ module Morpheus
159
176
  context_map = context_map[ns.to_s]
160
177
  end
161
178
 
162
- # build parameters for option source api request
163
- option_params = (option_type['noParams'] ? {} : (api_params || {}).deep_merge(results))
164
- option_params.merge!(option_type['optionParams']) if option_type['optionParams']
179
+ # credential type
180
+ handle_credential_type = -> {
181
+ credential_type = select_prompt(option_type.merge({'defaultValue' => value}), api_client, option_params.merge({'credentialTypes' => option_type['config']['credentialTypes']}), !value.nil?, nil, paging_enabled, ignore_empty)
182
+ # continue prompting for local creds
183
+ if credential_type == 'local'
184
+ parent_context_map.reject! {|k,v| k == 'credential'}
185
+ next
186
+ end
187
+ # hide local cred options
188
+ prompt_local_credentials = false
189
+ if credential_type.is_a?(Numeric)
190
+ # set as credential.id
191
+ credential = {'id' => credential_type}
192
+ else
193
+ # prompt credential type options
194
+ credential = prompt(api_client.credential_types.list({name:credential_type})['credentialTypes'][0]['optionTypes'], options, api_client, option_params, options[:no_prompt], paging_enabled, ignore_empty)['credential']
195
+ credential['type'] = credential_type
196
+ end
197
+ parent_context_map['credential'] = credential
198
+ }
165
199
 
166
200
  # use the value passed in the options map
167
201
  if cur_namespace.respond_to?('key?') && cur_namespace.key?(field_name)
@@ -194,6 +228,8 @@ module Morpheus
194
228
  select_value_list << typeahead_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true)
195
229
  end
196
230
  value = select_value_list
231
+ elsif option_type['type'] == 'credential'
232
+ handle_credential_type.call
197
233
  end
198
234
  if options[:always_prompt] != true
199
235
  value_found = true
@@ -252,6 +288,9 @@ module Morpheus
252
288
  value = multiline_prompt(option_type)
253
289
  elsif option_type['type'] == 'code-editor'
254
290
  value = multiline_prompt(option_type)
291
+ elsif option_type['type'] == 'credential'
292
+ print "\nCREDENTIALS\n#{"=" * ("CREDENTIALS".length)}\n\n"
293
+ handle_credential_type.call
255
294
  elsif ['select', 'multiSelect'].include?(option_type['type'])
256
295
  # so, the /api/options/source is may need ALL the previously
257
296
  # selected values that are being accumulated in options
@@ -262,7 +301,8 @@ module Morpheus
262
301
  value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
263
302
  if value && option_type['type'] == 'multiSelect'
264
303
  value = [value]
265
- while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => false}) do
304
+ recommended_count = (option_type['config'] || {})['recommendedCount'] || 0
305
+ while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => recommended_count > value.count}) do
266
306
  if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
267
307
  value << addn_value
268
308
  else
@@ -366,7 +406,6 @@ module Morpheus
366
406
  return value
367
407
  end
368
408
 
369
-
370
409
  def self.set_last_select(obj)
371
410
  Thread.current[:_last_select] = obj
372
411
  end
@@ -741,15 +780,18 @@ module Morpheus
741
780
  help_prompt(option_type)
742
781
  next
743
782
  end
744
- if input.downcase == 'yes'
783
+ if input.downcase == 'yes' || input.downcase == 'y' || input.downcase == 'on'
745
784
  value_found = true
746
785
  value = 'on'
747
- elsif input.downcase == 'no'
786
+ elsif input.downcase == 'no' || input.downcase == 'n' || input.downcase == 'off'
748
787
  value_found = true
749
788
  value = 'off'
750
789
  elsif input == '' && has_default
751
790
  value_found = true
752
791
  value = default_yes ? 'on' : 'off'
792
+ elsif input != ""
793
+ puts "Invalid Option... Please try again."
794
+ next
753
795
  end
754
796
  if value.nil? && option_type['required']
755
797
  puts "Invalid Option... Please try again."
@@ -795,6 +837,20 @@ module Morpheus
795
837
  elsif !value.nil? || option_type['required'] != true
796
838
  value_found = true
797
839
  end
840
+ # attempt to parse Java regex and validate it
841
+ if option_type["verifyPattern"].to_s != "" && !(value.to_s == "" && option_type['required'])
842
+ begin
843
+ # pattern is matched on the entire string
844
+ verify_pattern = Regexp.compile("^" + option_type["verifyPattern"] + "$")
845
+ if !verify_pattern.match(value)
846
+ value_found = false
847
+ puts "Invalid Option. Value must match the pattern '#{option_type['verifyPattern']}'. Please try again."
848
+ next
849
+ end
850
+ rescue => regex_ex
851
+ puts "Failed to parse verifyPattern '#{option_type['verifyPattern']}' as a regular expression"
852
+ end
853
+ end
798
854
  end
799
855
  return value
800
856
  end
@@ -1058,10 +1114,10 @@ module Morpheus
1058
1114
  return out
1059
1115
  end
1060
1116
 
1061
- def self.sorted_option_types(option_types)
1062
- option_types.reject {|it| (it['fieldGroup'] || 'default') != 'default'}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i} +
1063
- option_types.reject {|it| ['default', 'advanced'].include?(it['fieldGroup'] || 'default')}.sort{|a,b| a['displayOrder'] <=> b['displayOrder']}.group_by{|it| it['fieldGroup']}.values.collect { |it| it.sort{|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}}.flatten +
1064
- option_types.reject {|it| it['fieldGroup'] != 'advanced'}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}
1117
+ def self.sort_option_types(option_types)
1118
+ option_types.select {|it| (it['fieldGroup'] || 'default').casecmp?('default')}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i} +
1119
+ option_types.reject {|it| ['default', 'advanced'].include?((it['fieldGroup'] || 'default').downcase)}.sort{|a,b| a['displayOrder'] <=> b['displayOrder']}.group_by{|it| it['fieldGroup']}.values.collect { |it| it.sort{|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}}.flatten +
1120
+ option_types.select {|it| 'advanced'.casecmp?(it['fieldGroup'])}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}
1065
1121
  end
1066
1122
 
1067
1123
  def self.display_select_options(opt, select_options = [], paging = nil)
@@ -1069,7 +1125,7 @@ module Morpheus
1069
1125
  end
1070
1126
 
1071
1127
  def self.format_option_types_help(option_types, opts={})
1072
- option_types = self.sorted_option_types(option_types).reject {|it| it['hidden']}
1128
+ option_types = self.sort_option_types(option_types).reject {|it| it['hidden']}
1073
1129
 
1074
1130
  if option_types.empty?
1075
1131
  "#{opts[:color]}#{opts[:title] || "Available Options:"}\nNone\n\n"
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "5.4.5.1"
4
+ VERSION = "5.5.1.1"
5
5
  end
6
6
  end
@@ -155,10 +155,9 @@ module Morpheus::Logging
155
155
 
156
156
  def print(*messages)
157
157
  if @io
158
- messages = messages.flatten.collect {|it| scrub_message(it) }
159
- print_with_color do
160
- messages.each do |msg|
161
- @io.print msg
158
+ print_with_color do
159
+ messages.flatten.each do |msg|
160
+ @io.print scrub_message(msg)
162
161
  end
163
162
  end
164
163
  end
@@ -166,10 +165,9 @@ module Morpheus::Logging
166
165
 
167
166
  def puts(*messages)
168
167
  if @io
169
- messages = messages.flatten.collect {|it| scrub_message(it) }
170
- print_with_color do
171
- messages.each do |msg|
172
- @io.puts msg
168
+ print_with_color do
169
+ messages.flatten.each do |msg|
170
+ @io.puts scrub_message(msg)
173
171
  end
174
172
  end
175
173
  end
@@ -16,11 +16,9 @@ module Morpheus::Routes
16
16
  analytics: {},
17
17
  guidance: {},
18
18
  wiki: {},
19
- costing: {
20
- budgets: {},
21
- invoices: {},
22
- usage: {},
23
- },
19
+ budgets: {},
20
+ invoices: {},
21
+ usage: {},
24
22
  approvals: {},
25
23
  activity: {},
26
24
  alarms: {},
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: 5.4.5.1
4
+ version: 5.5.1.1
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: 2022-04-15 00:00:00.000000000 Z
14
+ date: 2022-07-19 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -185,6 +185,8 @@ files:
185
185
  - lib/morpheus/api/audit_interface.rb
186
186
  - lib/morpheus/api/auth_interface.rb
187
187
  - lib/morpheus/api/backup_jobs_interface.rb
188
+ - lib/morpheus/api/backup_service_types_interface.rb
189
+ - lib/morpheus/api/backup_services_interface.rb
188
190
  - lib/morpheus/api/backup_settings_interface.rb
189
191
  - lib/morpheus/api/backups_interface.rb
190
192
  - lib/morpheus/api/billing_interface.rb
@@ -292,6 +294,7 @@ files:
292
294
  - lib/morpheus/api/reports_interface.rb
293
295
  - lib/morpheus/api/rest_interface.rb
294
296
  - lib/morpheus/api/roles_interface.rb
297
+ - lib/morpheus/api/scale_thresholds_interface.rb
295
298
  - lib/morpheus/api/search_interface.rb
296
299
  - lib/morpheus/api/secondary_read_interface.rb
297
300
  - lib/morpheus/api/secondary_rest_interface.rb
@@ -341,6 +344,7 @@ files:
341
344
  - lib/morpheus/cli/commands/archives_command.rb
342
345
  - lib/morpheus/cli/commands/audit.rb
343
346
  - lib/morpheus/cli/commands/backup_jobs_command.rb
347
+ - lib/morpheus/cli/commands/backup_services_command.rb
344
348
  - lib/morpheus/cli/commands/backup_settings_command.rb
345
349
  - lib/morpheus/cli/commands/backups_command.rb
346
350
  - lib/morpheus/cli/commands/benchmark_command.rb
@@ -451,6 +455,7 @@ files:
451
455
  - lib/morpheus/cli/commands/reports_command.rb
452
456
  - lib/morpheus/cli/commands/rm_command.rb
453
457
  - lib/morpheus/cli/commands/roles.rb
458
+ - lib/morpheus/cli/commands/scale_thresholds.rb
454
459
  - lib/morpheus/cli/commands/search_command.rb
455
460
  - lib/morpheus/cli/commands/security_group_rules.rb
456
461
  - lib/morpheus/cli/commands/security_groups.rb
@@ -500,6 +505,7 @@ files:
500
505
  - lib/morpheus/cli/mixins/deployments_helper.rb
501
506
  - lib/morpheus/cli/mixins/execution_request_helper.rb
502
507
  - lib/morpheus/cli/mixins/infrastructure_helper.rb
508
+ - lib/morpheus/cli/mixins/jobs_helper.rb
503
509
  - lib/morpheus/cli/mixins/library_helper.rb
504
510
  - lib/morpheus/cli/mixins/load_balancers_helper.rb
505
511
  - lib/morpheus/cli/mixins/logs_helper.rb
@@ -550,8 +556,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
550
556
  - !ruby/object:Gem::Version
551
557
  version: '0'
552
558
  requirements: []
553
- rubyforge_project:
554
- rubygems_version: 2.7.6
559
+ rubygems_version: 3.1.6
555
560
  signing_key:
556
561
  specification_version: 4
557
562
  summary: Provides CLI Interface to the Morpheus Public/Private Cloud Appliance