morpheus-cli 4.2.22 → 5.2.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Dockerfile +1 -1
  4. data/lib/morpheus/api/api_client.rb +30 -0
  5. data/lib/morpheus/api/billing_interface.rb +34 -0
  6. data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
  7. data/lib/morpheus/api/deploy_interface.rb +1 -1
  8. data/lib/morpheus/api/deployments_interface.rb +20 -1
  9. data/lib/morpheus/api/forgot_password_interface.rb +17 -0
  10. data/lib/morpheus/api/instances_interface.rb +16 -2
  11. data/lib/morpheus/api/rest_interface.rb +0 -6
  12. data/lib/morpheus/api/roles_interface.rb +14 -0
  13. data/lib/morpheus/api/search_interface.rb +13 -0
  14. data/lib/morpheus/api/servers_interface.rb +14 -0
  15. data/lib/morpheus/api/service_catalog_interface.rb +89 -0
  16. data/lib/morpheus/api/usage_interface.rb +18 -0
  17. data/lib/morpheus/cli.rb +7 -3
  18. data/lib/morpheus/cli/apps.rb +6 -27
  19. data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
  20. data/lib/morpheus/cli/backups_command.rb +3 -0
  21. data/lib/morpheus/cli/catalog_item_types_command.rb +622 -0
  22. data/lib/morpheus/cli/cli_command.rb +70 -21
  23. data/lib/morpheus/cli/commands/standard/curl_command.rb +3 -5
  24. data/lib/morpheus/cli/commands/standard/history_command.rb +3 -1
  25. data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
  26. data/lib/morpheus/cli/commands/standard/source_command.rb +1 -1
  27. data/lib/morpheus/cli/commands/standard/update_command.rb +76 -0
  28. data/lib/morpheus/cli/containers_command.rb +14 -24
  29. data/lib/morpheus/cli/cypher_command.rb +6 -2
  30. data/lib/morpheus/cli/deploy.rb +199 -90
  31. data/lib/morpheus/cli/deployments.rb +341 -28
  32. data/lib/morpheus/cli/deploys.rb +206 -41
  33. data/lib/morpheus/cli/error_handler.rb +7 -0
  34. data/lib/morpheus/cli/forgot_password.rb +133 -0
  35. data/lib/morpheus/cli/groups.rb +1 -1
  36. data/lib/morpheus/cli/health_command.rb +59 -2
  37. data/lib/morpheus/cli/hosts.rb +295 -35
  38. data/lib/morpheus/cli/instances.rb +247 -130
  39. data/lib/morpheus/cli/invoices_command.rb +37 -19
  40. data/lib/morpheus/cli/library_option_lists_command.rb +15 -7
  41. data/lib/morpheus/cli/library_option_types_command.rb +5 -2
  42. data/lib/morpheus/cli/logs_command.rb +9 -6
  43. data/lib/morpheus/cli/mixins/accounts_helper.rb +12 -7
  44. data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
  45. data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -3
  46. data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
  47. data/lib/morpheus/cli/mixins/print_helper.rb +46 -21
  48. data/lib/morpheus/cli/mixins/provisioning_helper.rb +108 -5
  49. data/lib/morpheus/cli/option_types.rb +271 -22
  50. data/lib/morpheus/cli/ping.rb +0 -1
  51. data/lib/morpheus/cli/remote.rb +35 -12
  52. data/lib/morpheus/cli/reports_command.rb +99 -30
  53. data/lib/morpheus/cli/roles.rb +453 -113
  54. data/lib/morpheus/cli/search_command.rb +182 -0
  55. data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
  56. data/lib/morpheus/cli/setup.rb +1 -1
  57. data/lib/morpheus/cli/shell.rb +33 -11
  58. data/lib/morpheus/cli/storage_providers_command.rb +40 -56
  59. data/lib/morpheus/cli/tasks.rb +29 -32
  60. data/lib/morpheus/cli/usage_command.rb +203 -0
  61. data/lib/morpheus/cli/user_settings_command.rb +1 -0
  62. data/lib/morpheus/cli/users.rb +12 -1
  63. data/lib/morpheus/cli/version.rb +1 -1
  64. data/lib/morpheus/cli/virtual_images.rb +429 -254
  65. data/lib/morpheus/cli/whoami.rb +6 -6
  66. data/lib/morpheus/cli/workflows.rb +33 -40
  67. data/lib/morpheus/formatters.rb +75 -7
  68. data/lib/morpheus/terminal.rb +6 -2
  69. metadata +14 -2
@@ -25,16 +25,19 @@ class Morpheus::Cli::InvoicesCommand
25
25
  options = {}
26
26
  params = {}
27
27
  ref_ids = []
28
- query_tags = {}
29
28
  optparse = Morpheus::Cli::OptionParser.new do |opts|
30
29
  opts.banner = subcommand_usage()
31
30
  opts.on('-a', '--all', "Display all details, costs and prices." ) do
32
31
  options[:show_all] = true
32
+ options[:show_dates] = true
33
33
  options[:show_estimates] = true
34
34
  # options[:show_costs] = true
35
35
  options[:show_prices] = true
36
36
  # options[:show_raw_data] = true
37
37
  end
38
+ opts.on('--dates', "Display Ref Start, Ref End, etc.") do |val|
39
+ options[:show_dates] = true
40
+ end
38
41
  opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network, Extra" ) do
39
42
  options[:show_estimates] = true
40
43
  end
@@ -107,9 +110,12 @@ class Morpheus::Cli::InvoicesCommand
107
110
  params['accountId'] = val
108
111
  end
109
112
  opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
110
- k,v = val.split("=")
111
- query_tags[k] ||= []
112
- query_tags[k] << v
113
+ val.split(",").each do |value_pair|
114
+ k,v = value_pair.strip.split("=")
115
+ options[:tags] ||= {}
116
+ options[:tags][k] ||= []
117
+ options[:tags][k] << (v || '')
118
+ end
113
119
  end
114
120
  opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
115
121
  options[:show_raw_data] = true
@@ -169,8 +175,8 @@ class Morpheus::Cli::InvoicesCommand
169
175
  end
170
176
  params['rawData'] = true if options[:show_raw_data]
171
177
  params['refId'] = ref_ids unless ref_ids.empty?
172
- if query_tags && !query_tags.empty?
173
- query_tags.each do |k,v|
178
+ if options[:tags] && !options[:tags].empty?
179
+ options[:tags].each do |k,v|
174
180
  params['tags.' + k] = v
175
181
  end
176
182
  end
@@ -203,6 +209,7 @@ class Morpheus::Cli::InvoicesCommand
203
209
  {"INVOICE ID" => lambda {|it| it['id'] } },
204
210
  {"TYPE" => lambda {|it| format_invoice_ref_type(it) } },
205
211
  {"REF ID" => lambda {|it| it['refId'] } },
212
+ {"REF UUID" => lambda {|it| it['refUuid'] } },
206
213
  {"REF NAME" => lambda {|it|
207
214
  if options[:show_all]
208
215
  it['refName']
@@ -218,9 +225,11 @@ class Morpheus::Cli::InvoicesCommand
218
225
  {"PERIOD" => lambda {|it| format_invoice_period(it) } },
219
226
  {"START" => lambda {|it| format_date(it['startDate']) } },
220
227
  {"END" => lambda {|it| format_date(it['endDate']) } },
221
- ] + (options[:show_all] ? [
228
+ ] + ((options[:show_dates] || options[:show_all]) ? [
222
229
  {"REF START" => lambda {|it| format_dt(it['refStart']) } },
223
230
  {"REF END" => lambda {|it| format_dt(it['refEnd']) } },
231
+ # {"LAST COST DATE" => lambda {|it| format_local_dt(it['lastCostDate']) } },
232
+ # {"LAST ACTUAL DATE" => lambda {|it| format_local_dt(it['lastActualDate']) } },
224
233
  ] : []) + [
225
234
  {"COMPUTE" => lambda {|it| format_money(it['computeCost'], 'usd', {sigdig:options[:sigdig]}) } },
226
235
  # {"MEMORY" => lambda {|it| format_money(it['memoryCost']) } },
@@ -263,7 +272,7 @@ class Morpheus::Cli::InvoicesCommand
263
272
  {"ESTIMATE" => lambda {|it| format_boolean(it['estimate']) } },
264
273
  {"ACTIVE" => lambda {|it| format_boolean(it['active']) } },
265
274
  {"ITEMS" => lambda {|it| it['lineItems'].size rescue '' } },
266
- {"TAGS" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
275
+ {"TAGS" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
267
276
  ]
268
277
  if show_projects
269
278
  columns += [
@@ -272,9 +281,15 @@ class Morpheus::Cli::InvoicesCommand
272
281
  {"PROJECT TAGS" => lambda {|it| it['project'] ? truncate_string(format_metadata(it['project']['tags']), 50) : '' } },
273
282
  ]
274
283
  end
284
+ if options[:show_dates]
285
+ columns += [
286
+ {"LAST COST DATE" => lambda {|it| format_local_dt(it['lastCostDate']) } },
287
+ {"LAST ACTUAL DATE" => lambda {|it| format_local_dt(it['lastActualDate']) } },
288
+ ]
289
+ end
275
290
  columns += [
276
291
  {"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
277
- {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } }
292
+ {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
278
293
  ]
279
294
  if options[:show_raw_data]
280
295
  columns += [{"RAW DATA" => lambda {|it| truncate_string(it['rawData'].to_s, 10) } }]
@@ -423,7 +438,7 @@ EOT
423
438
  "Ref Start" => lambda {|it| format_dt(it['refStart']) },
424
439
  "Ref End" => lambda {|it| format_dt(it['refEnd']) },
425
440
  "Items" => lambda {|it| it['lineItems'].size rescue '' },
426
- "Tags" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
441
+ "Tags" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
427
442
  "Project ID" => lambda {|it| it['project'] ? it['project']['id'] : '' },
428
443
  "Project Name" => lambda {|it| it['project'] ? it['project']['name'] : '' },
429
444
  "Project Tags" => lambda {|it| it['project'] ? format_metadata(it['project']['tags']) : '' },
@@ -439,7 +454,8 @@ EOT
439
454
  description_cols.delete("Project Name")
440
455
  description_cols.delete("Project Tags")
441
456
  end
442
- if invoice['metadata'].nil? || invoice['metadata'].empty?
457
+ tags = (invoice['metadata'] || invoice['tags'])
458
+ if tags.nil? || tags.empty?
443
459
  description_cols.delete("Tags")
444
460
  end
445
461
  if !['ComputeServer','Instance','Container'].include?(invoice['refType'])
@@ -656,7 +672,6 @@ EOT
656
672
  options = {}
657
673
  params = {}
658
674
  ref_ids = []
659
- query_tags = {}
660
675
  optparse = Morpheus::Cli::OptionParser.new do |opts|
661
676
  opts.banner = subcommand_usage()
662
677
  opts.on('-a', '--all', "Display all details, costs and prices." ) do
@@ -744,11 +759,14 @@ EOT
744
759
  opts.on('--tenant ID', String, "View invoice line items for a tenant. Default is your own account.") do |val|
745
760
  params['accountId'] = val
746
761
  end
747
- # opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
748
- # k,v = val.split("=")
749
- # query_tags[k] ||= []
750
- # query_tags[k] << v
751
- # end
762
+ opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
763
+ val.split(",").each do |value_pair|
764
+ k,v = value_pair.strip.split("=")
765
+ options[:tags] ||= {}
766
+ options[:tags][k] ||= []
767
+ options[:tags][k] << (v || '')
768
+ end
769
+ end
752
770
  opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
753
771
  options[:show_raw_data] = true
754
772
  end
@@ -808,8 +826,8 @@ EOT
808
826
  end
809
827
  params['rawData'] = true if options[:show_raw_data]
810
828
  params['refId'] = ref_ids unless ref_ids.empty?
811
- if query_tags && !query_tags.empty?
812
- query_tags.each do |k,v|
829
+ if options[:tags] && !options[:tags].empty?
830
+ options[:tags].each do |k,v|
813
831
  params['tags.' + k] = v
814
832
  end
815
833
  end
@@ -90,6 +90,9 @@ class Morpheus::Cli::LibraryOptionListsCommand
90
90
  optparse = Morpheus::Cli::OptionParser.new do |opts|
91
91
  opts.banner = subcommand_usage("[name]")
92
92
  build_standard_get_options(opts, options)
93
+ opts.on(nil,'--no-items', "Do not display List Items") do |val|
94
+ options[:no_list_items] = true
95
+ end
93
96
  opts.footer = "Get details about an option list.\n" +
94
97
  "[name] is required. This is the name or id of an option list. Supports 1-N [name] arguments."
95
98
  end
@@ -166,15 +169,20 @@ class Morpheus::Cli::LibraryOptionListsCommand
166
169
  print_h2 "Translation Script"
167
170
  print reset,"#{option_type_list['translationScript']}","\n",reset
168
171
  end
172
+ if !option_type_list['requestScript'].empty?
173
+ print_h2 "Request Script"
174
+ print reset,"#{option_type_list['requestScript']}","\n",reset
175
+ end
169
176
  end
170
- print_h2 "List Items"
171
- if option_type_list['listItems']
172
- print as_pretty_table(option_type_list['listItems'], ['name', 'value'], options)
173
- else
174
- puts "No data"
177
+ if options[:no_list_items] != true
178
+ list_items = option_type_list['listItems']
179
+ if list_items && list_items.size > 0
180
+ print_h2 "List Items"
181
+ print as_pretty_table(list_items, [:name, :value], options)
182
+ print_results_pagination({size: list_items.size, total: list_items.size})
183
+ end
175
184
  end
176
185
  print reset,"\n"
177
-
178
186
  rescue RestClient::Exception => e
179
187
  print_rest_exception(e, options)
180
188
  exit 1
@@ -262,7 +270,7 @@ class Morpheus::Cli::LibraryOptionListsCommand
262
270
  else
263
271
  payload = {}
264
272
  payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
265
- list_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_option_types(), options[:options], @api_client)
273
+ list_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_list_option_types(), options[:options], @api_client)
266
274
  if list_payload['type'] == 'rest'
267
275
  # parse Source Headers
268
276
  if !(payload['optionTypeList']['config'] && payload['optionTypeList']['config']['sourceHeaders'])
@@ -129,7 +129,7 @@ class Morpheus::Cli::LibraryOptionTypesCommand
129
129
 
130
130
  print_h1 "Option Type Details"
131
131
  print cyan
132
- print_description_list({
132
+ columns = {
133
133
  "ID" => 'id',
134
134
  "Name" => 'name',
135
135
  "Description" => 'description',
@@ -138,11 +138,14 @@ class Morpheus::Cli::LibraryOptionTypesCommand
138
138
  # "Field Name" => 'fieldName',
139
139
  "Full Field Name" => lambda {|it| [it['fieldContext'], it['fieldName']].select {|it| !it.to_s.empty? }.join('.') },
140
140
  "Type" => lambda {|it| it['type'].to_s.capitalize },
141
+ "Option List" => lambda {|it| it['optionList'] ? it['optionList']['name'] : nil },
141
142
  "Placeholder" => 'placeHolder',
142
143
  "Default Value" => 'defaultValue',
143
144
  "Required" => lambda {|it| format_boolean(it['required']) },
144
145
  "Export As Tag" => lambda {|it| it['exportMeta'].nil? ? '' : format_boolean(it['exportMeta']) },
145
- }, option_type)
146
+ }
147
+ columns.delete("Option List") if option_type['optionList'].nil?
148
+ print as_description_list(option_type, columns, options)
146
149
  print reset,"\n"
147
150
  return 0
148
151
  rescue RestClient::Exception => e
@@ -34,7 +34,7 @@ class Morpheus::Cli::LogsCommand
34
34
  options = {}
35
35
  params = {}
36
36
  optparse = Morpheus::Cli::OptionParser.new do |opts|
37
- opts.banner = subcommand_usage("[id]")
37
+ opts.banner = subcommand_usage("[search]")
38
38
  opts.on('--hosts HOSTS', String, "Filter logs to specific Host ID(s)") do |val|
39
39
  params['servers'] = val.to_s.split(",").collect {|it| it.to_s.strip }.select {|it| it }.compact
40
40
  end
@@ -72,18 +72,21 @@ class Morpheus::Cli::LogsCommand
72
72
  options[:details] = true
73
73
  end
74
74
  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
75
- opts.footer = "List logs for a container.\n" +
76
- "[id] is required. This is the id of a container."
75
+ opts.footer = "List logs for all hosts and containers."
77
76
  end
78
77
  optparse.parse!(args)
79
- if args.count != 0
80
- raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
78
+ if args.count > 0
79
+ options[:phrase] = args.join(" ")
81
80
  end
82
81
  connect(options)
83
82
  begin
84
83
  params['level'] = params['level'].collect {|it| it.to_s.upcase }.join('|') if params['level'] # api works with INFO|WARN
85
84
  params.merge!(parse_list_options(options))
86
- params['query'] = params.delete('phrase') if params['phrase']
85
+ if params['phrase']
86
+ options.delete(:phrase)
87
+ search_phrase = params.delete('phrase')
88
+ params['query'] = search_phrase
89
+ end
87
90
  params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
88
91
  params['startMs'] = (options[:start].to_i * 1000) if options[:start]
89
92
  params['endMs'] = (options[:end].to_i * 1000) if options[:end]
@@ -136,6 +136,7 @@ module Morpheus::Cli::AccountsHelper
136
136
  "Multitenant" => lambda {|it|
137
137
  format_boolean(it['multitenant']).to_s + (it['multitenantLocked'] ? " (LOCKED)" : "")
138
138
  },
139
+ "Default Persona" => lambda {|it| it['defaultPersona'] ? it['defaultPersona']['name'] : '(standard)' },
139
140
  "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
140
141
  #"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
141
142
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
@@ -196,7 +197,7 @@ module Morpheus::Cli::AccountsHelper
196
197
 
197
198
  ## Users
198
199
 
199
- def user_column_definitions()
200
+ def user_column_definitions(opts={})
200
201
  {
201
202
  "ID" => 'id',
202
203
  "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
@@ -206,15 +207,15 @@ module Morpheus::Cli::AccountsHelper
206
207
  "Email" => 'email',
207
208
  "Role" => lambda {|it| format_user_role_names(it) },
208
209
  "Notifications" => lambda {|it| it['receiveNotifications'].nil? ? '' : format_boolean(it['receiveNotifications']) },
209
- "Status" => lambda {|it| format_user_status(it) },
210
+ "Status" => lambda {|it| format_user_status(it, opts[:color] || cyan) },
210
211
  "Last Login" => lambda {|it| format_duration_ago(it['lastLoginDate']) },
211
212
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
212
213
  "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
213
214
  }
214
215
  end
215
216
 
216
- def list_user_column_definitions()
217
- columns = user_column_definitions
217
+ def list_user_column_definitions(opts={})
218
+ columns = user_column_definitions(opts)
218
219
  columns.delete("Notifications")
219
220
  return columns.upcase_keys!
220
221
  end
@@ -261,8 +262,8 @@ module Morpheus::Cli::AccountsHelper
261
262
  return nil
262
263
  elsif users.size > 1
263
264
  print_red_alert "Found #{users.size} users by username '#{username}'. Try using ID instead: #{format_list(users.collect {|it| it['id']}, 'or', 3)}"
264
- print "\n"
265
- print as_pretty_table(users, list_user_column_definitions, {color: red, thin: true})
265
+ print_error "\n"
266
+ print_error as_pretty_table(users, list_user_column_definitions({color: red}), {color: red, thin: true})
266
267
  print reset,"\n"
267
268
  return nil
268
269
  else
@@ -400,7 +401,7 @@ module Morpheus::Cli::AccountsHelper
400
401
  end
401
402
 
402
403
  def get_access_string(access, return_color=cyan)
403
- get_access_color(access) + access + return_color
404
+ get_access_color(access) + access.to_s + return_color.to_s
404
405
  # access ||= 'none'
405
406
  # if access == 'none'
406
407
  # "#{white}#{access.to_s}#{return_color}"
@@ -425,10 +426,14 @@ module Morpheus::Cli::AccountsHelper
425
426
  # Examples: format_permission_access("read")
426
427
  # format_permission_access("custom", "full,custom,none")
427
428
  def format_access_string(access, access_levels=nil, return_color=cyan)
429
+ # nevermind all this, just colorized access level
430
+ return get_access_string(access, return_color)
431
+
428
432
  access = access.to_s.downcase.strip
429
433
  if access.empty?
430
434
  access = "none"
431
435
  end
436
+
432
437
  if access_levels.nil?
433
438
  access_levels = ["none","read","user","full"]
434
439
  elsif access_levels.is_a?(Array)
@@ -1,6 +1,6 @@
1
1
  require 'morpheus/cli/mixins/print_helper'
2
2
  # Mixin for Morpheus::Cli command classes
3
- # Provides common methods for infrastructure management
3
+ # Provides common methods for backups management
4
4
  module Morpheus::Cli::BackupsHelper
5
5
 
6
6
  def self.included(klass)
@@ -8,13 +8,11 @@ module Morpheus::Cli::BackupsHelper
8
8
  end
9
9
 
10
10
  def backups_interface
11
- # @api_client.groups
12
11
  raise "#{self.class} has not defined @backups_interface" if @backups_interface.nil?
13
12
  @backups_interface
14
13
  end
15
14
 
16
- def backup_jobs_interface
17
- # @api_client.groups
15
+ def backup_jobs_interfaces
18
16
  raise "#{self.class} has not defined @backup_jobs_interface" if @backup_jobs_interface.nil?
19
17
  @backup_jobs_interface
20
18
  end
@@ -10,7 +10,6 @@ module Morpheus::Cli::DeploymentsHelper
10
10
  ## Deployments
11
11
 
12
12
  def deployments_interface
13
- # @api_client.groups
14
13
  raise "#{self.class} has not defined @deployments_interface" if @deployments_interface.nil?
15
14
  @deployments_interface
16
15
  end
@@ -52,9 +51,10 @@ module Morpheus::Cli::DeploymentsHelper
52
51
  return nil
53
52
  elsif deployments.size > 1
54
53
  print_red_alert "#{deployments.size} deployments found by name '#{name}'"
54
+ print_error "\n"
55
55
  puts_error as_pretty_table(deployments, [:id, :name], {color:red})
56
56
  print_red_alert "Try using ID instead"
57
- print reset,"\n"
57
+ print_error reset,"\n"
58
58
  return nil
59
59
  else
60
60
  return deployments[0]
@@ -123,13 +123,41 @@ module Morpheus::Cli::DeploymentsHelper
123
123
  return nil
124
124
  elsif deployment_versions.size > 1
125
125
  print_red_alert "#{deployment_versions.size} deployment versions found by version '#{name}'"
126
+ print_error "\n"
126
127
  puts_error as_pretty_table(deployment_versions, {"ID" => 'id', "VERSION" => 'userVersion'}, {color:red})
127
128
  print_red_alert "Try using ID instead"
128
- print reset,"\n"
129
+ print_error reset,"\n"
129
130
  return nil
130
131
  else
131
132
  return deployment_versions[0]
132
133
  end
133
134
  end
134
135
 
136
+ def format_deployment_version_number(deployment_version)
137
+ if deployment_version
138
+ deployment_version['userVersion'] || deployment_version['version'] || ''
139
+ else
140
+ ''
141
+ end
142
+ end
143
+
144
+ def format_app_deploy_status(status, return_color=cyan)
145
+ out = ""
146
+ s = status.to_s.downcase
147
+ if s == 'deployed' || s == 'committed'
148
+ out << "#{green}#{s.upcase}#{return_color}"
149
+ elsif s == 'open' || s == 'archived'
150
+ out << "#{cyan}#{s.upcase}#{return_color}"
151
+ elsif s == 'failed'
152
+ out << "#{red}#{s.upcase}#{return_color}"
153
+ else
154
+ out << "#{yellow}#{s.upcase}#{return_color}"
155
+ end
156
+ out
157
+ end
158
+
159
+ def format_deploy_type(val)
160
+ return val
161
+ end
162
+
135
163
  end
@@ -75,7 +75,7 @@ module Morpheus::Cli::OptionSourceHelper
75
75
 
76
76
  def get_cloud_options(refresh=false, api_params={})
77
77
  if !@available_cloud_options || refresh
78
- option_results = options_interface.options_for_source('clouds', api_params.mege({'default' => 'false'}))
78
+ option_results = options_interface.options_for_source('clouds', api_params.merge({'default' => 'false'}))
79
79
  @available_cloud_options = option_results['data'].collect {|it|
80
80
  {"name" => it["name"], "value" => it["value"], "id" => it["value"]}
81
81
  }
@@ -1151,27 +1151,6 @@ module Morpheus::Cli::PrintHelper
1151
1151
  out
1152
1152
  end
1153
1153
 
1154
- def format_list(items, conjunction="and", limit=nil)
1155
- items = items ? items.clone : []
1156
- if limit
1157
- items = items.first(limit)
1158
- end
1159
- last_item = items.pop
1160
- if items.empty?
1161
- return "#{last_item}"
1162
- else
1163
- return items.join(", ") + (conjunction.to_s.empty? ? ", " : " #{conjunction} ") + "#{last_item}" + ((limit && limit < (items.size+1)) ? " ..." : "")
1164
- end
1165
- end
1166
-
1167
- def anded_list(items, limit=nil)
1168
- format_list(items, "and", limit)
1169
- end
1170
-
1171
- def ored_list(items, limit=nil)
1172
- format_list(items, "or", limit)
1173
- end
1174
-
1175
1154
  def sleep_with_dots(sleep_seconds, dots=3, dot_chr=".")
1176
1155
  dot_interval = (sleep_seconds.to_f / dots.to_i)
1177
1156
  dots.to_i.times do |dot_index|
@@ -1285,4 +1264,50 @@ module Morpheus::Cli::PrintHelper
1285
1264
  end
1286
1265
  end
1287
1266
 
1267
+ # convert JSON or YAML string to a map
1268
+ def parse_json_or_yaml(config, parsers = [:json, :yaml])
1269
+ rtn = {success: false, data: nil, err: nil}
1270
+ err = nil
1271
+ config = config.strip
1272
+ if config[0..2] == "---"
1273
+ parsers = [:yaml]
1274
+ end
1275
+ # ok only parse json for strings that start with {, consolidated yaml can look like json and cause issues}
1276
+ if config[0] && config[0].chr == "{" && config[-1] && config[-1].chr == "}"
1277
+ parsers = [:json]
1278
+ end
1279
+ parsers.each do |parser|
1280
+ if parser == :yaml
1281
+ begin
1282
+ # todo: one method to parse and return Hash
1283
+ # load does not raise an exception, it just returns the bad string
1284
+ #YAML.parse(config)
1285
+ config_map = YAML.load(config)
1286
+ if !config_map.is_a?(Hash)
1287
+ raise "Failed to parse config as YAML"
1288
+ end
1289
+ rtn[:data] = config_map
1290
+ rtn[:success] = true
1291
+ break
1292
+ rescue => ex
1293
+ rtn[:err] = ex if rtn[:err].nil?
1294
+ end
1295
+ elsif parser == :json
1296
+ begin
1297
+ config_map = JSON.parse(config)
1298
+ rtn[:data] = config_map
1299
+ rtn[:success] = true
1300
+ break
1301
+ rescue => ex
1302
+ rtn[:err] = ex if rtn[:err].nil?
1303
+ end
1304
+ end
1305
+ end
1306
+ return rtn
1307
+ end
1308
+
1309
+ def parse_yaml_or_json(config, parsers = [:yaml, :json])
1310
+ parse_json_or_yaml(config, parsers)
1311
+ end
1312
+
1288
1313
  end