morpheus-cli 4.2.19 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +26 -0
  4. data/lib/morpheus/api/billing_interface.rb +34 -0
  5. data/lib/morpheus/api/catalog_item_types_interface.rb +9 -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 +7 -0
  10. data/lib/morpheus/api/rest_interface.rb +0 -6
  11. data/lib/morpheus/api/roles_interface.rb +14 -0
  12. data/lib/morpheus/api/search_interface.rb +13 -0
  13. data/lib/morpheus/api/servers_interface.rb +7 -0
  14. data/lib/morpheus/api/usage_interface.rb +18 -0
  15. data/lib/morpheus/cli.rb +6 -3
  16. data/lib/morpheus/cli/apps.rb +3 -4
  17. data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
  18. data/lib/morpheus/cli/backups_command.rb +3 -0
  19. data/lib/morpheus/cli/budgets_command.rb +4 -4
  20. data/lib/morpheus/cli/catalog_command.rb +507 -0
  21. data/lib/morpheus/cli/cli_command.rb +45 -20
  22. data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
  23. data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -12
  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 -0
  29. data/lib/morpheus/cli/deploy.rb +199 -90
  30. data/lib/morpheus/cli/deployments.rb +342 -29
  31. data/lib/morpheus/cli/deploys.rb +206 -41
  32. data/lib/morpheus/cli/error_handler.rb +7 -0
  33. data/lib/morpheus/cli/forgot_password.rb +133 -0
  34. data/lib/morpheus/cli/health_command.rb +2 -2
  35. data/lib/morpheus/cli/hosts.rb +193 -28
  36. data/lib/morpheus/cli/instances.rb +102 -33
  37. data/lib/morpheus/cli/invoices_command.rb +33 -16
  38. data/lib/morpheus/cli/jobs_command.rb +28 -6
  39. data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
  40. data/lib/morpheus/cli/library_option_lists_command.rb +14 -6
  41. data/lib/morpheus/cli/logs_command.rb +9 -6
  42. data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -6
  43. data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
  44. data/lib/morpheus/cli/mixins/catalog_helper.rb +66 -0
  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 +24 -4
  49. data/lib/morpheus/cli/network_pools_command.rb +14 -6
  50. data/lib/morpheus/cli/option_types.rb +266 -17
  51. data/lib/morpheus/cli/ping.rb +0 -1
  52. data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
  53. data/lib/morpheus/cli/remote.rb +35 -12
  54. data/lib/morpheus/cli/reports_command.rb +99 -30
  55. data/lib/morpheus/cli/roles.rb +305 -3
  56. data/lib/morpheus/cli/search_command.rb +182 -0
  57. data/lib/morpheus/cli/service_plans_command.rb +2 -2
  58. data/lib/morpheus/cli/setup.rb +1 -1
  59. data/lib/morpheus/cli/shell.rb +33 -11
  60. data/lib/morpheus/cli/storage_providers_command.rb +40 -56
  61. data/lib/morpheus/cli/tasks.rb +20 -21
  62. data/lib/morpheus/cli/tenants_command.rb +1 -1
  63. data/lib/morpheus/cli/usage_command.rb +203 -0
  64. data/lib/morpheus/cli/user_settings_command.rb +1 -0
  65. data/lib/morpheus/cli/users.rb +12 -1
  66. data/lib/morpheus/cli/version.rb +1 -1
  67. data/lib/morpheus/cli/virtual_images.rb +280 -199
  68. data/lib/morpheus/cli/whoami.rb +6 -6
  69. data/lib/morpheus/cli/workflows.rb +34 -41
  70. data/lib/morpheus/formatters.rb +48 -5
  71. data/lib/morpheus/terminal.rb +6 -2
  72. metadata +13 -2
@@ -475,8 +475,8 @@ class Morpheus::Cli::HealthCommand
475
475
  opts.footer = "List health logs. These are the logs of the morpheus appliance itself."
476
476
  end
477
477
  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}"
478
+ if args.count > 0
479
+ options[:phrase] = args.join(" ")
480
480
  end
481
481
  connect(options)
482
482
  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,
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,13 @@ 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
57
+ opts.on('-a', '--all', "Display all details: memory and storage usage used / max values." ) do
58
+ options[:details] = true
59
+ end
60
+ opts.on('--details', "Display all details: alias for --all" ) do
61
+ options[:details] = true
58
62
  end
63
+ opts.add_hidden_option('--details')
59
64
  opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
60
65
  options[:group] = val
61
66
  end
@@ -105,20 +110,35 @@ class Morpheus::Cli::Hosts
105
110
  opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
106
111
  options[:created_by] = val
107
112
  end
113
+ opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
114
+ options[:account] = val
115
+ end
108
116
  opts.on('--details', "Display more details: memory and storage usage used / max values." ) do
109
117
  options[:details] = true
110
118
  end
119
+ opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
120
+ val.split(",").each do |value_pair|
121
+ k,v = value_pair.strip.split("=")
122
+ options[:tags] ||= {}
123
+ options[:tags][k] ||= []
124
+ options[:tags][k] << (v || '')
125
+ end
126
+ end
111
127
  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
128
  params[:tagCompliant] = true
113
129
  end
114
130
  opts.on('--non-tag-compliant', "Displays only servers with tag compliance warnings." ) do
115
131
  params[:tagCompliant] = false
116
132
  end
117
- build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
133
+ build_standard_list_options(opts, options)
118
134
  opts.footer = "List hosts."
119
135
  end
120
136
  optparse.parse!(args)
121
137
  connect(options)
138
+ # verify_args!(args:args, optparse:optparse, count:0)
139
+ if args.count > 0
140
+ options[:phrase] = args.join(" ")
141
+ end
122
142
  begin
123
143
  params.merge!(parse_list_options(options))
124
144
  account = nil
@@ -159,6 +179,11 @@ class Morpheus::Cli::Hosts
159
179
  params['clusterId'] = cluster['id']
160
180
  end
161
181
  end
182
+ if options[:tags] && !options[:tags].empty?
183
+ options[:tags].each do |k,v|
184
+ params['tags.' + k] = v
185
+ end
186
+ end
162
187
 
163
188
  @servers_interface.setopts(options)
164
189
  if options[:dry_run]
@@ -190,6 +215,9 @@ class Morpheus::Cli::Hosts
190
215
  multi_tenant = json_response['multiTenant'] == true
191
216
  title = "Morpheus Hosts"
192
217
  subtitles = []
218
+ if account
219
+ subtitles << "Tenant: #{account['name']}".strip
220
+ end
193
221
  if group
194
222
  subtitles << "Group: #{group['name']}".strip
195
223
  end
@@ -240,31 +268,66 @@ class Morpheus::Cli::Hosts
240
268
  end
241
269
  row = {
242
270
  id: server['id'],
243
- tenant: server['account'] ? server['account']['name'] : server['accountId'],
244
271
  name: server['name'],
272
+ hostname: server['hostname'],
245
273
  platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
246
- cloud: server['zone'] ? server['zone']['name'] : '',
247
274
  type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
275
+ tenant: server['account'] ? server['account']['name'] : server['accountId'],
276
+ owner: server['owner'] ? server['owner']['username'] : server['owner'],
277
+ cloud: server['zone'] ? server['zone']['name'] : '',
278
+ ip: server['externalIp'],
279
+ internal_ip: server['internalIp'],
248
280
  nodes: server['containers'] ? server['containers'].size : '',
249
- status: format_server_status(server, cyan),
281
+ # status: format_server_status(server, cyan),
282
+ status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
250
283
  power: format_server_power_state(server, cyan),
251
284
  cpu: cpu_usage_str + cyan,
252
285
  memory: memory_usage_str + cyan,
253
- storage: storage_usage_str + cyan
286
+ storage: storage_usage_str + cyan,
287
+ created: format_local_dt(server['dateCreated']),
288
+ updated: format_local_dt(server['lastUpdated']),
254
289
  }
255
290
  row
256
291
  }
257
- columns = [:id, :name, :type, :cloud, :nodes, :status, :power]
258
- if multi_tenant
259
- columns.insert(4, :tenant)
292
+ # columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
293
+ columns = {
294
+ "ID" => :id,
295
+ "Name" => :name,
296
+ "Hostname" => :hostname,
297
+ "Type" => :type,
298
+ "Owner" => :owner,
299
+ "Tenant" => :tenant,
300
+ "Cloud" => :cloud,
301
+ "IP" => :ip,
302
+ "Private IP" => :internal_ip,
303
+ "Nodes" => :nodes,
304
+ "Status" => :status,
305
+ "Power" => :power,
306
+ "CPU" => :cpu,
307
+ "Memory" => :memory,
308
+ "Storage" => :storage,
309
+ "Created" => :created,
310
+ "Updated" => :updated,
311
+ }
312
+ if options[:details] != true
313
+ columns.delete("Hostname")
314
+ columns.delete("Private IP")
315
+ columns.delete("Owner")
316
+ columns.delete("Tenant")
317
+ columns.delete("Power")
318
+ columns.delete("Created")
319
+ columns.delete("Updated")
260
320
  end
261
- columns += [:cpu, :memory, :storage]
262
- # custom pretty table columns ...
263
- if options[:include_fields]
264
- columns = options[:include_fields]
321
+ if !multi_tenant
322
+ columns.delete("Tenant")
265
323
  end
324
+ # columns += [:cpu, :memory, :storage]
325
+ # # custom pretty table columns ...
326
+ # if options[:include_fields]
327
+ # columns = options[:include_fields]
328
+ # end
266
329
  print cyan
267
- print as_pretty_table(rows, columns, options)
330
+ print as_pretty_table(rows, columns.upcase_keys!, options)
268
331
  print reset
269
332
  print_results_pagination(json_response)
270
333
  end
@@ -392,6 +455,9 @@ class Morpheus::Cli::Hosts
392
455
  options = {}
393
456
  optparse = Morpheus::Cli::OptionParser.new do |opts|
394
457
  opts.banner = subcommand_usage("[name]")
458
+ opts.on( nil, '--costs', "Display Cost and Price" ) do
459
+ options[:include_costs] = true
460
+ end
395
461
  opts.on('--refresh [SECONDS]', String, "Refresh until status is provisioned,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
396
462
  options[:refresh_until_status] ||= "provisioned,failed"
397
463
  if !val.to_s.empty?
@@ -453,22 +519,37 @@ class Morpheus::Cli::Hosts
453
519
  title = "Host Details"
454
520
  print_h1 title, [], options
455
521
  print cyan
456
- print_description_list({
522
+ server_columns = {
457
523
  "ID" => 'id',
458
524
  "Name" => 'name',
525
+ "Hostname" => 'hostname',
459
526
  "Description" => 'description',
460
- "Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
527
+ "Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
528
+ "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
461
529
  #"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
462
530
  "Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
531
+ "IP" => lambda {|it| it['externalIp'] },
532
+ "Private IP" => lambda {|it| it['internalIp'] },
463
533
  "Type" => lambda {|it| it['computeServerType'] ? it['computeServerType']['name'] : 'unmanaged' },
464
534
  "Platform" => lambda {|it| it['serverOs'] ? it['serverOs']['name'].upcase : 'N/A' },
465
535
  "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
536
+ "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
537
+ "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
466
538
  "Agent" => lambda {|it| it['agentInstalled'] ? "#{server['agentVersion'] || ''} updated at #{format_local_dt(server['lastAgentUpdate'])}" : '(not installed)' },
467
- "Status" => lambda {|it| format_server_status(it) },
468
539
  "Nodes" => lambda {|it| it['containers'] ? it['containers'].size : 0 },
469
- "Power" => lambda {|it| format_server_power_state(it) },
470
- }, server)
471
-
540
+ # "Status" => lambda {|it| format_server_status(it) },
541
+ # "Power" => lambda {|it| format_server_power_state(it) },
542
+ "Status" => lambda {|it| format_server_status_friendly(it) }, # combo
543
+ }
544
+ server_columns.delete("Hostname") if server['hostname'].to_s.empty? || server['hostname'] == server['name']
545
+ server_columns.delete("IP") if server['externalIp'].to_s.empty?
546
+ server_columns.delete("Private IP") if server['internalIp'].to_s.empty?
547
+ # server_columns.delete("Tenant") if multi_tenant != true
548
+ server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
549
+ server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
550
+
551
+ print_description_list(server_columns, server)
552
+
472
553
  if server['statusMessage']
473
554
  print_h2 "Status Message", options
474
555
  if server['status'] == 'failed'
@@ -485,6 +566,16 @@ class Morpheus::Cli::Hosts
485
566
 
486
567
  print_h2 "Host Usage", options
487
568
  print_stats_usage(stats)
569
+
570
+ if options[:include_costs]
571
+ print_h2 "Host Cost"
572
+ cost_columns = {
573
+ "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
574
+ "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
575
+ }
576
+ print_description_list(cost_columns, server)
577
+ end
578
+
488
579
  print reset, "\n"
489
580
 
490
581
 
@@ -1781,6 +1872,53 @@ class Morpheus::Cli::Hosts
1781
1872
  end
1782
1873
  end
1783
1874
 
1875
+ def snapshots(args)
1876
+ options = {}
1877
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1878
+ opts.banner = subcommand_usage("[host]")
1879
+ # no pagination yet
1880
+ # build_standard_list_options(opts, options)
1881
+ build_standard_get_options(opts, options)
1882
+ end
1883
+ optparse.parse!(args)
1884
+ verify_args!(args:args, optparse:optparse, count:1)
1885
+ connect(options)
1886
+ begin
1887
+ server = find_host_by_name_or_id(args[0])
1888
+ return 1 if server.nil?
1889
+ params = {}
1890
+ @servers_interface.setopts(options)
1891
+ if options[:dry_run]
1892
+ print_dry_run @servers_interface.dry.snapshots(server['id'], params)
1893
+ return
1894
+ end
1895
+ json_response = @servers_interface.snapshots(server['id'], params)
1896
+ snapshots = json_response['snapshots']
1897
+ render_response(json_response, options, 'snapshots') do
1898
+ print_h1 "Snapshots: #{server['name']}", [], options
1899
+ if snapshots.empty?
1900
+ print cyan,"No snapshots found",reset,"\n"
1901
+ else
1902
+ snapshot_column_definitions = {
1903
+ "ID" => lambda {|it| it['id'] },
1904
+ "Name" => lambda {|it| it['name'] },
1905
+ "Description" => lambda {|it| it['snapshotType'] ? (it['snapshotType']['name'] || it['snapshotType']['code']) : '' },
1906
+ "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
1907
+ "Status" => lambda {|it| format_snapshot_status(it) }
1908
+ }
1909
+ print cyan
1910
+ print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
1911
+ print_results_pagination({size: snapshots.size, total: snapshots.size})
1912
+ end
1913
+ print reset, "\n"
1914
+ end
1915
+ return 0
1916
+ rescue RestClient::Exception => e
1917
+ print_rest_exception(e, options)
1918
+ exit 1
1919
+ end
1920
+ end
1921
+
1784
1922
  private
1785
1923
 
1786
1924
  def find_host_by_id(id)
@@ -1897,11 +2035,38 @@ class Morpheus::Cli::Hosts
1897
2035
 
1898
2036
  def format_server_status(server, return_color=cyan)
1899
2037
  out = ""
1900
- status_string = server['status']
1901
- # todo: colorize, upcase?
1902
- out << status_string.to_s
2038
+ status_string = server['status'].to_s.downcase
2039
+ if status_string == 'provisioned'
2040
+ out = "#{cyan}#{status_string.upcase}#{return_color}"
2041
+ elsif status_string == 'provisioning'
2042
+ out = "#{cyan}#{status_string.upcase}#{cyan}"
2043
+ elsif status_string == 'failed' or status_string == 'error'
2044
+ out = "#{red}#{status_string.upcase}#{return_color}"
2045
+ else
2046
+ out = "#{yellow}#{status_string.upcase}#{return_color}"
2047
+ end
2048
+ out
2049
+ end
2050
+
2051
+ def format_server_status_friendly(server, return_color=cyan)
2052
+ out = ""
2053
+ status_string = server['status'].to_s.downcase
2054
+ if status_string == 'provisioned'
2055
+ # out = format_server_power_state(server, return_color)
2056
+ # make it looks like format_instance_status
2057
+ if server['powerState'] == 'on'
2058
+ out << "#{green}RUNNING#{return_color}"
2059
+ elsif server['powerState'] == 'off'
2060
+ out << "#{red}STOPPED#{return_color}"
2061
+ else
2062
+ out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
2063
+ end
2064
+ else
2065
+ out = format_server_status(server, return_color)
2066
+ end
1903
2067
  out
1904
2068
  end
2069
+
1905
2070
 
1906
2071
  def make_managed_option_types(connected=true)
1907
2072
  [
@@ -19,7 +19,7 @@ class Morpheus::Cli::Instances
19
19
  :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details},
20
20
  :stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
21
21
  :backup, :backups, :resize, :clone, :envs, :setenv, :delenv,
22
- :security_groups, :apply_security_groups, :run_workflow, :import_snapshot,
22
+ :security_groups, :apply_security_groups, :run_workflow, :import_snapshot, :snapshots,
23
23
  :console, :status_check, {:containers => :list_containers},
24
24
  :scaling, {:'scaling-update' => :scaling_update},
25
25
  :wiki, :update_wiki,
@@ -92,11 +92,28 @@ class Morpheus::Cli::Instances
92
92
  opts.on('--pending-removal-only', "Only instances pending removal.") do
93
93
  options[:deleted] = true
94
94
  end
95
+ opts.on('--labels label',String, "Filter by labels (keywords).") do |val|
96
+ val.split(",").each do |k|
97
+ options[:labels] ||= []
98
+ options[:labels] << k.strip
99
+ end
100
+ end
101
+ opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
102
+ val.split(",").each do |value_pair|
103
+ k,v = value_pair.strip.split("=")
104
+ options[:tags] ||= {}
105
+ options[:tags][k] ||= []
106
+ options[:tags][k] << (v || '')
107
+ end
108
+ end
95
109
  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
96
110
  opts.footer = "List instances."
97
111
  end
98
112
  optparse.parse!(args)
99
- verify_args!(args:args, count:0, optparse:optparse)
113
+ # verify_args!(args:args, optparse:optparse, count:0)
114
+ if args.count > 0
115
+ options[:phrase] = args.join(" ")
116
+ end
100
117
  connect(options)
101
118
  begin
102
119
  params.merge!(parse_list_options(options))
@@ -129,7 +146,13 @@ class Morpheus::Cli::Instances
129
146
 
130
147
  params['showDeleted'] = true if options[:showDeleted]
131
148
  params['deleted'] = true if options[:deleted]
132
-
149
+ params['labels'] = options[:labels] if options[:labels]
150
+ if options[:tags]
151
+ options[:tags].each do |k,v|
152
+ params['tags.' + k] = v
153
+ end
154
+ end
155
+
133
156
  @instances_interface.setopts(options)
134
157
  if options[:dry_run]
135
158
  print_dry_run @instances_interface.dry.list(params)
@@ -344,18 +367,16 @@ class Morpheus::Cli::Instances
344
367
  opts.on("--environment ENV", String, "Environment code") do |val|
345
368
  options[:environment] = val.to_s
346
369
  end
347
- opts.on('--metadata LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
370
+ opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
348
371
  options[:metadata] = val
349
372
  end
350
- opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
351
- #options[:tags] = val
352
- options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
373
+ opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
374
+ options[:metadata] = val
353
375
  end
354
- opts.on('--tags LIST', String, "Tags") do |val|
355
- #options[:tags] = val
356
- options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
376
+ opts.add_hidden_option('--metadata')
377
+ opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
378
+ options[:labels] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
357
379
  end
358
- opts.add_hidden_option('--tags')
359
380
  opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
360
381
  options[:copies] = val.to_i
361
382
  end
@@ -525,18 +546,17 @@ class Morpheus::Cli::Instances
525
546
  opts.on('--group GROUP', String, "Group Name or ID") do |val|
526
547
  options[:group] = val
527
548
  end
528
- opts.on('--metadata LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
549
+ opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
529
550
  options[:metadata] = val
530
551
  end
531
- opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
532
- #params['tags'] = val
533
- params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
552
+ opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
553
+ options[:metadata] = val
534
554
  end
535
- opts.on('--tags LIST', String, "Tags") do |val|
536
- #params['tags'] = val
555
+ opts.add_hidden_option('--metadata')
556
+ opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
557
+ # todo switch this from 'tags' to 'labels'
537
558
  params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
538
559
  end
539
- opts.add_hidden_option('--tags')
540
560
  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
541
561
  params['powerScheduleType'] = val == "null" ? nil : val
542
562
  end
@@ -607,6 +627,9 @@ class Morpheus::Cli::Instances
607
627
  metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
608
628
  metadata_list = metadata_list.collect do |it|
609
629
  metadata_pair = it.split(":")
630
+ if metadata_pair.size == 1 && it.include?("=")
631
+ metadata_pair = it.split("=")
632
+ end
610
633
  row = {}
611
634
  row['name'] = metadata_pair[0].to_s.strip
612
635
  row['value'] = metadata_pair[1].to_s.strip
@@ -1148,6 +1171,9 @@ class Morpheus::Cli::Instances
1148
1171
  opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
1149
1172
  options[:include_scaling] = true
1150
1173
  end
1174
+ opts.on( nil, '--costs', "Display Cost and Price" ) do
1175
+ options[:include_costs] = true
1176
+ end
1151
1177
  opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
1152
1178
  options[:refresh_until_status] ||= "running,failed"
1153
1179
  if !val.to_s.empty?
@@ -1249,6 +1275,8 @@ class Morpheus::Cli::Instances
1249
1275
  "Layout" => lambda {|it| it['layout'] ? it['layout']['name'] : '' },
1250
1276
  "Version" => lambda {|it| it['instanceVersion'] },
1251
1277
  "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
1278
+ # "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1279
+ # "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1252
1280
  "Environment" => 'instanceContext',
1253
1281
  "Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
1254
1282
  "Metadata" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
@@ -1304,6 +1332,16 @@ class Morpheus::Cli::Instances
1304
1332
  print_h2 "Instance Usage", options
1305
1333
  print_stats_usage(stats)
1306
1334
  end
1335
+
1336
+ if options[:include_costs]
1337
+ print_h2 "Instance Cost"
1338
+ cost_columns = {
1339
+ "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1340
+ "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1341
+ }
1342
+ print_description_list(cost_columns, instance)
1343
+ end
1344
+
1307
1345
  print reset, "\n"
1308
1346
 
1309
1347
  # if options[:include_lb]
@@ -2880,6 +2918,52 @@ class Morpheus::Cli::Instances
2880
2918
  end
2881
2919
  end
2882
2920
 
2921
+ def snapshots(args)
2922
+ options = {}
2923
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2924
+ opts.banner = subcommand_usage("[instance]")
2925
+ # no pagination yet
2926
+ # build_standard_list_options(opts, options)
2927
+ build_standard_get_options(opts, options)
2928
+ end
2929
+ optparse.parse!(args)
2930
+ verify_args!(args:args, optparse:optparse, count:1)
2931
+ connect(options)
2932
+ begin
2933
+ instance = find_instance_by_name_or_id(args[0])
2934
+ params = {}
2935
+ @instances_interface.setopts(options)
2936
+ if options[:dry_run]
2937
+ print_dry_run @instances_interface.dry.snapshots(instance['id'], params)
2938
+ return
2939
+ end
2940
+ json_response = @instances_interface.snapshots(instance['id'], params)
2941
+ snapshots = json_response['snapshots']
2942
+ render_response(json_response, options, 'snapshots') do
2943
+ print_h1 "Snapshots: #{instance['name']} (#{instance['instanceType']['name']})", [], options
2944
+ if snapshots.empty?
2945
+ print cyan,"No snapshots found",reset,"\n"
2946
+ else
2947
+ snapshot_column_definitions = {
2948
+ "ID" => lambda {|it| it['id'] },
2949
+ "Name" => lambda {|it| it['name'] },
2950
+ "Description" => lambda {|it| it['snapshotType'] ? (it['snapshotType']['name'] || it['snapshotType']['code']) : '' },
2951
+ "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
2952
+ "Status" => lambda {|it| format_snapshot_status(it) }
2953
+ }
2954
+ print cyan
2955
+ print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
2956
+ print_results_pagination({size: snapshots.size, total: snapshots.size})
2957
+ end
2958
+ print reset, "\n"
2959
+ end
2960
+ return 0
2961
+ rescue RestClient::Exception => e
2962
+ print_rest_exception(e, options)
2963
+ exit 1
2964
+ end
2965
+ end
2966
+
2883
2967
  def import_snapshot(args)
2884
2968
  options = {}
2885
2969
  query_params = {}
@@ -4006,19 +4090,4 @@ private
4006
4090
  }
4007
4091
  end
4008
4092
 
4009
- def format_app_deploy_status(status, return_color=cyan)
4010
- out = ""
4011
- s = status.to_s.downcase
4012
- if s == 'deployed'
4013
- out << "#{green}#{s.upcase}#{return_color}"
4014
- elsif s == 'open' || s == 'archived' || s == 'committed'
4015
- out << "#{cyan}#{s.upcase}#{return_color}"
4016
- elsif s == 'failed'
4017
- out << "#{red}#{s.upcase}#{return_color}"
4018
- else
4019
- out << "#{yellow}#{s.upcase}#{return_color}"
4020
- end
4021
- out
4022
- end
4023
-
4024
4093
  end