morpheus-cli 5.0.0 → 5.2.2

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 (61) 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 +16 -0
  5. data/lib/morpheus/api/billing_interface.rb +1 -0
  6. data/lib/morpheus/api/deploy_interface.rb +1 -1
  7. data/lib/morpheus/api/deployments_interface.rb +20 -1
  8. data/lib/morpheus/api/forgot_password_interface.rb +17 -0
  9. data/lib/morpheus/api/instances_interface.rb +16 -2
  10. data/lib/morpheus/api/invoices_interface.rb +12 -3
  11. data/lib/morpheus/api/search_interface.rb +13 -0
  12. data/lib/morpheus/api/servers_interface.rb +14 -0
  13. data/lib/morpheus/api/service_catalog_interface.rb +89 -0
  14. data/lib/morpheus/api/usage_interface.rb +18 -0
  15. data/lib/morpheus/cli.rb +6 -2
  16. data/lib/morpheus/cli/apps.rb +3 -23
  17. data/lib/morpheus/cli/budgets_command.rb +389 -319
  18. data/lib/morpheus/cli/{catalog_command.rb → catalog_item_types_command.rb} +182 -67
  19. data/lib/morpheus/cli/cli_command.rb +51 -10
  20. data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -13
  21. data/lib/morpheus/cli/commands/standard/history_command.rb +9 -3
  22. data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
  23. data/lib/morpheus/cli/containers_command.rb +0 -24
  24. data/lib/morpheus/cli/cypher_command.rb +6 -2
  25. data/lib/morpheus/cli/dashboard_command.rb +260 -20
  26. data/lib/morpheus/cli/deploy.rb +199 -90
  27. data/lib/morpheus/cli/deployments.rb +341 -28
  28. data/lib/morpheus/cli/deploys.rb +206 -41
  29. data/lib/morpheus/cli/error_handler.rb +7 -0
  30. data/lib/morpheus/cli/forgot_password.rb +133 -0
  31. data/lib/morpheus/cli/groups.rb +1 -1
  32. data/lib/morpheus/cli/health_command.rb +59 -2
  33. data/lib/morpheus/cli/hosts.rb +271 -39
  34. data/lib/morpheus/cli/instances.rb +228 -129
  35. data/lib/morpheus/cli/invoices_command.rb +100 -20
  36. data/lib/morpheus/cli/jobs_command.rb +94 -92
  37. data/lib/morpheus/cli/library_option_lists_command.rb +1 -1
  38. data/lib/morpheus/cli/library_option_types_command.rb +10 -5
  39. data/lib/morpheus/cli/logs_command.rb +9 -6
  40. data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -1
  41. data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -2
  42. data/lib/morpheus/cli/mixins/print_helper.rb +13 -27
  43. data/lib/morpheus/cli/mixins/provisioning_helper.rb +108 -5
  44. data/lib/morpheus/cli/option_types.rb +271 -22
  45. data/lib/morpheus/cli/remote.rb +35 -10
  46. data/lib/morpheus/cli/reports_command.rb +99 -30
  47. data/lib/morpheus/cli/roles.rb +193 -155
  48. data/lib/morpheus/cli/search_command.rb +182 -0
  49. data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
  50. data/lib/morpheus/cli/setup.rb +1 -1
  51. data/lib/morpheus/cli/shell.rb +33 -11
  52. data/lib/morpheus/cli/tasks.rb +29 -32
  53. data/lib/morpheus/cli/usage_command.rb +64 -11
  54. data/lib/morpheus/cli/version.rb +1 -1
  55. data/lib/morpheus/cli/virtual_images.rb +429 -254
  56. data/lib/morpheus/cli/whoami.rb +6 -6
  57. data/lib/morpheus/cli/workflows.rb +33 -40
  58. data/lib/morpheus/formatters.rb +75 -18
  59. data/lib/morpheus/terminal.rb +6 -2
  60. metadata +10 -4
  61. data/lib/morpheus/cli/mixins/catalog_helper.rb +0 -66
@@ -52,7 +52,7 @@ class Morpheus::Cli::Groups
52
52
  end
53
53
  json_response = @groups_interface.list(params)
54
54
  exit_code, err = 0, nil
55
- render_response(json_response, options) do
55
+ render_response(json_response, options, "groups") do
56
56
  groups = json_response['groups']
57
57
  subtitles = []
58
58
  subtitles += parse_list_subtitles(options)
@@ -30,6 +30,7 @@ class Morpheus::Cli::HealthCommand
30
30
  opts.on('-a', '--all', "Display all details: CPU, Memory, Database, etc." ) do
31
31
  options[:details] = true
32
32
  options[:show_cpu] = true
33
+ options[:show_threads] = true
33
34
  options[:show_memory] = true
34
35
  options[:show_database] = true
35
36
  options[:show_elastic] = true
@@ -47,6 +48,9 @@ class Morpheus::Cli::HealthCommand
47
48
  opts.on('--cpu', "Display CPU details" ) do
48
49
  options[:show_cpu] = true
49
50
  end
51
+ opts.on('--threads', "Display Thread details" ) do
52
+ options[:show_threads] = true
53
+ end
50
54
  opts.on('--memory', "Display Memory details" ) do
51
55
  options[:show_memory] = true
52
56
  end
@@ -184,6 +188,59 @@ class Morpheus::Cli::HealthCommand
184
188
  end
185
189
  end
186
190
 
191
+ # Threads ()
192
+ if options[:show_threads]
193
+ print_h2 "Threads", options
194
+ if health['threads'].nil?
195
+ print yellow,"No thread information returned.",reset,"\n\n"
196
+ else
197
+ print cyan
198
+
199
+ thread_summary_columns = {
200
+ "Thread Count" => lambda {|it| it['totalThreads'].size rescue '' },
201
+ "Busy Threads" => lambda {|it| it['busyThreads'].size rescue '' },
202
+ "Running Threads" => lambda {|it| it['runningThreads'].size rescue '' },
203
+ "Blocked Threads" => lambda {|it| it['blockedThreads'].size rescue '' },
204
+ }
205
+ print_description_list(thread_summary_columns, health['threads'], options)
206
+
207
+
208
+ thread_columns = [
209
+ {"Name".upcase => lambda {|it| it['name']} },
210
+ {"Status".upcase => lambda {|it|
211
+ # hrmm
212
+ status_string = (it['status'] || it['state']).to_s.downcase
213
+ status_color = cyan
214
+ # if status_string.include?('waiting')
215
+ # status_color = yellow
216
+ # end
217
+ "#{status_color}#{status_string.upcase}#{cyan}"
218
+ } },
219
+ # {"CPU Time" => lambda {|it| it['cpuTime'].to_s } },
220
+ # {"CPU Time" => lambda {|it| format_human_duration(it['cpuTime'].to_f / 1000) rescue '' } },
221
+ {"CPU Percent" => lambda {|it| it['cpuPercent'].to_i.to_s + '%' } }
222
+ ]
223
+
224
+ if health['threads']['busyThreads'] && health['threads']['busyThreads'].size > 0
225
+ print_h2 "Busy Threads"
226
+ print cyan
227
+ print as_pretty_table(health['threads']['busyThreads'], thread_columns, options)
228
+ end
229
+
230
+ if health['threads']['runningThreads'] && health['threads']['runningThreads'].size > 0
231
+ print_h2 "Running Threads"
232
+ print cyan
233
+ print as_pretty_table(health['threads']['runningThreads'], thread_columns, options)
234
+ end
235
+
236
+ if health['threads']['blockedThreads'] && health['threads']['blockedThreads'].size > 0
237
+ print_h2 "Blocked Threads"
238
+ print cyan
239
+ print as_pretty_table(health['threads']['blockedThreads'], thread_columns, options)
240
+ end
241
+ end
242
+ end
243
+
187
244
  # Memory
188
245
  if options[:show_memory]
189
246
  if health['memory'].nil?
@@ -475,8 +532,8 @@ class Morpheus::Cli::HealthCommand
475
532
  opts.footer = "List health logs. These are the logs of the morpheus appliance itself."
476
533
  end
477
534
  optparse.parse!(args)
478
- if args.count != 0
479
- raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
535
+ if args.count > 0
536
+ options[:phrase] = args.join(" ")
480
537
  end
481
538
  connect(options)
482
539
  begin
@@ -16,10 +16,11 @@ class Morpheus::Cli::Hosts
16
16
  include Morpheus::Cli::LogsHelper
17
17
  set_command_name :hosts
18
18
  set_command_description "View and manage hosts (servers)."
19
- register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize, :run_workflow, :make_managed, :upgrade_agent
20
- register_subcommands :'types' => :list_types
21
- register_subcommands :exec => :execution_request
22
- register_subcommands :wiki, :update_wiki
19
+ register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize,
20
+ :run_workflow, :make_managed, :upgrade_agent, :snapshots, :software,
21
+ {:'types' => :list_types},
22
+ {:exec => :execution_request},
23
+ :wiki, :update_wiki
23
24
  alias_subcommand :details, :get
24
25
  set_default_subcommand :list
25
26
 
@@ -53,9 +54,6 @@ class Morpheus::Cli::Hosts
53
54
  params = {}
54
55
  optparse = Morpheus::Cli::OptionParser.new do |opts|
55
56
  opts.banner = subcommand_usage()
56
- opts.on( '-a', '--account ACCOUNT', "Account Name or ID" ) do |val|
57
- options[:account] = val
58
- end
59
57
  opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
60
58
  options[:group] = val
61
59
  end
@@ -81,6 +79,17 @@ class Morpheus::Cli::Hosts
81
79
  # params[:clusterId] = val
82
80
  options[:cluster] = val
83
81
  end
82
+ opts.on( '--plan NAME', String, "Filter by Plan name(s)" ) do |val|
83
+ # commas used in names a lot so use --plan one --plan two
84
+ params['plan'] ||= []
85
+ params['plan'] << val
86
+ end
87
+ opts.on( '--plan-id ID', String, "Filter by Plan id(s)" ) do |val|
88
+ params['planId'] = parse_id_list(val)
89
+ end
90
+ opts.on( '--plan-code CODE', String, "Filter by Plan code(s)" ) do |val|
91
+ params['planCode'] = parse_id_list(val)
92
+ end
84
93
  opts.on( '', '--vm', "Show only virtual machines" ) do |val|
85
94
  params[:vm] = true
86
95
  end
@@ -105,8 +114,16 @@ class Morpheus::Cli::Hosts
105
114
  opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
106
115
  options[:created_by] = val
107
116
  end
108
- opts.on('--details', "Display more details: memory and storage usage used / max values." ) do
109
- options[:details] = true
117
+ opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
118
+ options[:account] = val
119
+ end
120
+ opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
121
+ val.split(",").each do |value_pair|
122
+ k,v = value_pair.strip.split("=")
123
+ options[:tags] ||= {}
124
+ options[:tags][k] ||= []
125
+ options[:tags][k] << (v || '')
126
+ end
110
127
  end
111
128
  opts.on('--tag-compliant', "Displays only servers that are valid according to applied tag policies. Does not show servers that do not have tag policies." ) do
112
129
  params[:tagCompliant] = true
@@ -114,7 +131,13 @@ class Morpheus::Cli::Hosts
114
131
  opts.on('--non-tag-compliant', "Displays only servers with tag compliance warnings." ) do
115
132
  params[:tagCompliant] = false
116
133
  end
117
- build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
134
+ opts.on('--stats', "Display values for memory and storage usage used / max values." ) do
135
+ options[:stats] = true
136
+ end
137
+ opts.on('-a', '--details', "Display all details: hostname, private ip, plan, stats, etc." ) do
138
+ options[:details] = true
139
+ end
140
+ build_standard_list_options(opts, options)
118
141
  opts.footer = "List hosts."
119
142
  end
120
143
  optparse.parse!(args)
@@ -163,6 +186,11 @@ class Morpheus::Cli::Hosts
163
186
  params['clusterId'] = cluster['id']
164
187
  end
165
188
  end
189
+ if options[:tags] && !options[:tags].empty?
190
+ options[:tags].each do |k,v|
191
+ params['tags.' + k] = v
192
+ end
193
+ end
166
194
 
167
195
  @servers_interface.setopts(options)
168
196
  if options[:dry_run]
@@ -194,6 +222,9 @@ class Morpheus::Cli::Hosts
194
222
  multi_tenant = json_response['multiTenant'] == true
195
223
  title = "Morpheus Hosts"
196
224
  subtitles = []
225
+ if account
226
+ subtitles << "Tenant: #{account['name']}".strip
227
+ end
197
228
  if group
198
229
  subtitles << "Group: #{group['name']}".strip
199
230
  end
@@ -234,7 +265,7 @@ class Morpheus::Cli::Hosts
234
265
  cpu_usage_str = !stats ? "" : generate_usage_bar((stats['usedCpu'] || stats['cpuUsage']).to_f, 100, {max_bars: 10})
235
266
  memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
236
267
  storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
237
- if options[:details]
268
+ if options[:details] || options[:stats]
238
269
  if stats['maxMemory'] && stats['maxMemory'].to_i != 0
239
270
  memory_usage_str = memory_usage_str + cyan + format_bytes_short(stats['usedMemory']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxMemory']).strip
240
271
  end
@@ -244,31 +275,76 @@ class Morpheus::Cli::Hosts
244
275
  end
245
276
  row = {
246
277
  id: server['id'],
247
- tenant: server['account'] ? server['account']['name'] : server['accountId'],
248
278
  name: server['name'],
279
+ external_name: server['externalName'],
280
+ hostname: server['hostname'],
249
281
  platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
250
- cloud: server['zone'] ? server['zone']['name'] : '',
251
282
  type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
283
+ tenant: server['account'] ? server['account']['name'] : server['accountId'],
284
+ owner: server['owner'] ? server['owner']['username'] : server['owner'],
285
+ cloud: server['zone'] ? server['zone']['name'] : '',
286
+ plan: server['plan'] ? server['plan']['name'] : '',
287
+ ip: server['externalIp'],
288
+ internal_ip: server['internalIp'],
252
289
  nodes: server['containers'] ? server['containers'].size : '',
253
- status: format_server_status(server, cyan),
290
+ # status: format_server_status(server, cyan),
291
+ status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
254
292
  power: format_server_power_state(server, cyan),
255
293
  cpu: cpu_usage_str + cyan,
256
294
  memory: memory_usage_str + cyan,
257
- storage: storage_usage_str + cyan
295
+ storage: storage_usage_str + cyan,
296
+ created: format_local_dt(server['dateCreated']),
297
+ updated: format_local_dt(server['lastUpdated']),
258
298
  }
259
299
  row
260
300
  }
261
- columns = [:id, :name, :type, :cloud, :nodes, :status, :power]
262
- if multi_tenant
263
- columns.insert(4, :tenant)
301
+ # columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
302
+ columns = {
303
+ "ID" => :id,
304
+ "Name" => :name,
305
+ "External Name" => :external_name,
306
+ "Hostname" => :hostname,
307
+ "Type" => :type,
308
+ "Owner" => :owner,
309
+ "Tenant" => :tenant,
310
+ "Cloud" => :cloud,
311
+ "Plan" => :plan,
312
+ "IP" => :ip,
313
+ "Private IP" => :internal_ip,
314
+ "Nodes" => :nodes,
315
+ "Status" => :status,
316
+ "Power" => :power,
317
+ "CPU" => :cpu,
318
+ "Memory" => :memory,
319
+ "Storage" => :storage,
320
+ "Created" => :created,
321
+ "Updated" => :updated,
322
+ }
323
+ if options[:details] != true
324
+ columns.delete("External Name")
325
+ columns.delete("Hostname")
326
+ columns.delete("Plan")
327
+ columns.delete("Private IP")
328
+ columns.delete("Owner")
329
+ columns.delete("Tenant")
330
+ columns.delete("Power")
331
+ columns.delete("Created")
332
+ columns.delete("Updated")
264
333
  end
265
- columns += [:cpu, :memory, :storage]
266
- # custom pretty table columns ...
267
- if options[:include_fields]
268
- columns = options[:include_fields]
334
+ # hide External Name if there are none
335
+ if !servers.find {|it| it['externalName'] && it['externalName'] != it['name']}
336
+ columns.delete("External Name")
269
337
  end
338
+ if !multi_tenant
339
+ columns.delete("Tenant")
340
+ end
341
+ # columns += [:cpu, :memory, :storage]
342
+ # # custom pretty table columns ...
343
+ # if options[:include_fields]
344
+ # columns = options[:include_fields]
345
+ # end
270
346
  print cyan
271
- print as_pretty_table(rows, columns, options)
347
+ print as_pretty_table(rows, columns.upcase_keys!, options)
272
348
  print reset
273
349
  print_results_pagination(json_response)
274
350
  end
@@ -285,7 +361,7 @@ class Morpheus::Cli::Hosts
285
361
  options = {}
286
362
  optparse = Morpheus::Cli::OptionParser.new do |opts|
287
363
  opts.banner = subcommand_usage("[options]")
288
- opts.on( '-a', '--account ACCOUNT', "Account Name or ID" ) do |val|
364
+ opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
289
365
  options[:account] = val
290
366
  end
291
367
  opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
@@ -454,36 +530,43 @@ class Morpheus::Cli::Hosts
454
530
  puts records_as_csv([json_response['server']], options)
455
531
  return 0
456
532
  end
457
- server = json_response['server']
533
+ server = json_response['server'] || json_response['host'] || {}
458
534
  #stats = server['stats'] || json_response['stats'] || {}
459
535
  stats = json_response['stats'] || {}
536
+ tags = server['tags'] || server['metadata']
460
537
  title = "Host Details"
461
538
  print_h1 title, [], options
462
539
  print cyan
463
540
  server_columns = {
464
541
  "ID" => 'id',
465
542
  "Name" => 'name',
543
+ "Hostname" => 'hostname',
466
544
  "Description" => 'description',
467
- "Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
545
+ "Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
546
+ "Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
547
+ "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
468
548
  #"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
469
549
  "Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
550
+ "IP" => lambda {|it| it['externalIp'] },
551
+ "Private IP" => lambda {|it| it['internalIp'] },
470
552
  "Type" => lambda {|it| it['computeServerType'] ? it['computeServerType']['name'] : 'unmanaged' },
471
553
  "Platform" => lambda {|it| it['serverOs'] ? it['serverOs']['name'].upcase : 'N/A' },
472
554
  "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
473
555
  "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
474
556
  "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
475
557
  "Agent" => lambda {|it| it['agentInstalled'] ? "#{server['agentVersion'] || ''} updated at #{format_local_dt(server['lastAgentUpdate'])}" : '(not installed)' },
476
- "Status" => lambda {|it| format_server_status(it) },
477
558
  "Nodes" => lambda {|it| it['containers'] ? it['containers'].size : 0 },
478
- "Power" => lambda {|it| format_server_power_state(it) },
559
+ # "Status" => lambda {|it| format_server_status(it) },
560
+ # "Power" => lambda {|it| format_server_power_state(it) },
561
+ "Status" => lambda {|it| format_server_status_friendly(it) }, # combo
479
562
  }
480
-
481
- if server['hourlyCost'].to_f == 0
482
- server_columns.delete("Cost")
483
- end
484
- if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
485
- server_columns.delete("Price")
486
- end
563
+ server_columns.delete("Hostname") if server['hostname'].to_s.empty? || server['hostname'] == server['name']
564
+ server_columns.delete("IP") if server['externalIp'].to_s.empty?
565
+ server_columns.delete("Private IP") if server['internalIp'].to_s.empty?
566
+ # server_columns.delete("Tenant") if multi_tenant != true
567
+ server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
568
+ server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
569
+ server_columns.delete("Tags") if tags.nil? || tags.empty?
487
570
 
488
571
  print_description_list(server_columns, server)
489
572
 
@@ -910,6 +993,19 @@ class Morpheus::Cli::Hosts
910
993
  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
911
994
  params['powerScheduleType'] = val == "null" ? nil : val
912
995
  end
996
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
997
+ options[:tags] = val
998
+ end
999
+ opts.on('--metadata LIST', String, "Alias for --tags.") do |val|
1000
+ options[:tags] = val
1001
+ end
1002
+ opts.add_hidden_option('--metadata')
1003
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
1004
+ options[:add_tags] = val
1005
+ end
1006
+ opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
1007
+ options[:remove_tags] = val
1008
+ end
913
1009
  # opts.on('--created-by ID', String, "Created By User ID") do |val|
914
1010
  # params['createdById'] = val
915
1011
  # end
@@ -928,6 +1024,18 @@ class Morpheus::Cli::Hosts
928
1024
  new_group = nil
929
1025
  passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
930
1026
  params.deep_merge!(passed_options) unless passed_options.empty?
1027
+ # metadata tags
1028
+ if options[:tags]
1029
+ params['tags'] = parse_metadata(options[:tags])
1030
+ else
1031
+ # params['tags'] = prompt_metadata(options)
1032
+ end
1033
+ if options[:add_tags]
1034
+ params['addTags'] = parse_metadata(options[:add_tags])
1035
+ end
1036
+ if options[:remove_tags]
1037
+ params['removeTags'] = parse_metadata(options[:remove_tags])
1038
+ end
931
1039
  payload = nil
932
1040
  if options[:payload]
933
1041
  payload = options[:payload]
@@ -1809,6 +1917,103 @@ class Morpheus::Cli::Hosts
1809
1917
  end
1810
1918
  end
1811
1919
 
1920
+ def snapshots(args)
1921
+ options = {}
1922
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1923
+ opts.banner = subcommand_usage("[host]")
1924
+ # no pagination yet
1925
+ # build_standard_list_options(opts, options)
1926
+ build_standard_get_options(opts, options)
1927
+ end
1928
+ optparse.parse!(args)
1929
+ verify_args!(args:args, optparse:optparse, count:1)
1930
+ connect(options)
1931
+ begin
1932
+ server = find_host_by_name_or_id(args[0])
1933
+ return 1 if server.nil?
1934
+ params = {}
1935
+ @servers_interface.setopts(options)
1936
+ if options[:dry_run]
1937
+ print_dry_run @servers_interface.dry.snapshots(server['id'], params)
1938
+ return
1939
+ end
1940
+ json_response = @servers_interface.snapshots(server['id'], params)
1941
+ snapshots = json_response['snapshots']
1942
+ render_response(json_response, options, 'snapshots') do
1943
+ print_h1 "Snapshots: #{server['name']}", [], options
1944
+ if snapshots.empty?
1945
+ print cyan,"No snapshots found",reset,"\n"
1946
+ else
1947
+ snapshot_column_definitions = {
1948
+ "ID" => lambda {|it| it['id'] },
1949
+ "Name" => lambda {|it| it['name'] },
1950
+ "Description" => lambda {|it| it['description'] },
1951
+ # "Type" => lambda {|it| it['snapshotType'] },
1952
+ "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
1953
+ "Status" => lambda {|it| format_snapshot_status(it) }
1954
+ }
1955
+ print cyan
1956
+ print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
1957
+ print_results_pagination({size: snapshots.size, total: snapshots.size})
1958
+ end
1959
+ print reset, "\n"
1960
+ end
1961
+ return 0
1962
+ rescue RestClient::Exception => e
1963
+ print_rest_exception(e, options)
1964
+ exit 1
1965
+ end
1966
+ end
1967
+
1968
+ def software(args)
1969
+ options = {}
1970
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1971
+ opts.banner = subcommand_usage("[host]")
1972
+ build_standard_list_options(opts, options)
1973
+ end
1974
+ optparse.parse!(args)
1975
+ verify_args!(args:args, optparse:optparse, count:1)
1976
+ connect(options)
1977
+ begin
1978
+ server = find_host_by_name_or_id(args[0])
1979
+ return 1 if server.nil?
1980
+ params = {}
1981
+ params.merge!(parse_list_options(options))
1982
+ @servers_interface.setopts(options)
1983
+ if options[:dry_run]
1984
+ print_dry_run @servers_interface.dry.software(server['id'], params)
1985
+ return
1986
+ end
1987
+ json_response = @servers_interface.software(server['id'], params)
1988
+ software = json_response['software']
1989
+ render_response(json_response, options, 'software') do
1990
+ print_h1 "Software: #{server['name']}", [], options
1991
+ if software.empty?
1992
+ print cyan,"No software found",reset,"\n"
1993
+ else
1994
+ software_column_definitions = {
1995
+ # "ID" => lambda {|it| it['id'] },
1996
+ "Name" => lambda {|it| it['name'] },
1997
+ "Version" => lambda {|it| it['packageVersion'] },
1998
+ "Publisher" => lambda {|it| it['packagePublisher'] },
1999
+ # "Release" => lambda {|it| it['packageRelease'] },
2000
+ # "Type" => lambda {|it| it['packageType'] },
2001
+ # "Architecture" => lambda {|it| it['architecture'] },
2002
+ # "Install Date" => lambda {|it| format_local_dt(it['installDate']) },
2003
+ }
2004
+ print cyan
2005
+ print as_pretty_table(software, software_column_definitions.upcase_keys!, options)
2006
+ print_results_pagination({size: software.size, total: software.size})
2007
+ end
2008
+ print reset, "\n"
2009
+ end
2010
+ return 0
2011
+ rescue RestClient::Exception => e
2012
+ print_rest_exception(e, options)
2013
+ exit 1
2014
+ end
2015
+ end
2016
+
1812
2017
  private
1813
2018
 
1814
2019
  def find_host_by_id(id)
@@ -1925,16 +2130,43 @@ class Morpheus::Cli::Hosts
1925
2130
 
1926
2131
  def format_server_status(server, return_color=cyan)
1927
2132
  out = ""
1928
- status_string = server['status']
1929
- # todo: colorize, upcase?
1930
- out << status_string.to_s
2133
+ status_string = server['status'].to_s.downcase
2134
+ if status_string == 'provisioned'
2135
+ out = "#{cyan}#{status_string.upcase}#{return_color}"
2136
+ elsif status_string == 'provisioning'
2137
+ out = "#{cyan}#{status_string.upcase}#{cyan}"
2138
+ elsif status_string == 'failed' or status_string == 'error'
2139
+ out = "#{red}#{status_string.upcase}#{return_color}"
2140
+ else
2141
+ out = "#{yellow}#{status_string.upcase}#{return_color}"
2142
+ end
2143
+ out
2144
+ end
2145
+
2146
+ def format_server_status_friendly(server, return_color=cyan)
2147
+ out = ""
2148
+ status_string = server['status'].to_s.downcase
2149
+ if status_string == 'provisioned'
2150
+ # out = format_server_power_state(server, return_color)
2151
+ # make it looks like format_instance_status
2152
+ if server['powerState'] == 'on'
2153
+ out << "#{green}RUNNING#{return_color}"
2154
+ elsif server['powerState'] == 'off'
2155
+ out << "#{red}STOPPED#{return_color}"
2156
+ else
2157
+ out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
2158
+ end
2159
+ else
2160
+ out = format_server_status(server, return_color)
2161
+ end
1931
2162
  out
1932
2163
  end
2164
+
1933
2165
 
1934
2166
  def make_managed_option_types(connected=true)
1935
2167
  [
1936
2168
  #{'fieldName' => 'account', 'fieldLabel' => 'Account', 'type' => 'select', 'optionSource' => 'accounts', 'required' => true},
1937
- {'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => true},
2169
+ {'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text'},
1938
2170
  {'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false},
1939
2171
  {'fieldName' => 'serverOs', 'fieldLabel' => 'OS Type', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false},
1940
2172
  ]