morpheus-cli 5.0.0 → 5.2.2

Sign up to get free protection for your applications and to get access to all the features.
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
  ]