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
@@ -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, :snapshot, :snapshots,
23
23
  :console, :status_check, {:containers => :list_containers},
24
24
  :scaling, {:'scaling-update' => :scaling_update},
25
25
  :wiki, :update_wiki,
@@ -80,9 +80,6 @@ class Morpheus::Cli::Instances
80
80
  options[:owner] = val
81
81
  end
82
82
  opts.add_hidden_option('--created-by')
83
- opts.on('--details', "Display more details: memory and storage usage used / max values." ) do
84
- options[:details] = true
85
- end
86
83
  opts.on('--status STATUS', "Filter by status i.e. provisioning,running,starting,stopping") do |val|
87
84
  params['status'] = (params['status'] || []) + val.to_s.split(',').collect {|s| s.strip }.select {|s| s != "" }
88
85
  end
@@ -92,6 +89,37 @@ class Morpheus::Cli::Instances
92
89
  opts.on('--pending-removal-only', "Only instances pending removal.") do
93
90
  options[:deleted] = true
94
91
  end
92
+ opts.on( '--plan NAME', String, "Filter by Plan name(s)" ) do |val|
93
+ # commas used in names a lot so use --plan one --plan two
94
+ params['plan'] ||= []
95
+ params['plan'] << val
96
+ end
97
+ opts.on( '--plan-id ID', String, "Filter by Plan id(s)" ) do |val|
98
+ params['planId'] = parse_id_list(val)
99
+ end
100
+ opts.on( '--plan-code CODE', String, "Filter by Plan code(s)" ) do |val|
101
+ params['planCode'] = parse_id_list(val)
102
+ end
103
+ opts.on('--labels label',String, "Filter by labels (keywords).") do |val|
104
+ val.split(",").each do |k|
105
+ options[:labels] ||= []
106
+ options[:labels] << k.strip
107
+ end
108
+ end
109
+ opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
110
+ val.split(",").each do |value_pair|
111
+ k,v = value_pair.strip.split("=")
112
+ options[:tags] ||= {}
113
+ options[:tags][k] ||= []
114
+ options[:tags][k] << (v || '')
115
+ end
116
+ end
117
+ opts.on('--stats', "Display values for memory and storage usage used / max values." ) do
118
+ options[:stats] = true
119
+ end
120
+ opts.on('-a', '--details', "Display all details: plan, stats, etc" ) do
121
+ options[:details] = true
122
+ end
95
123
  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
96
124
  opts.footer = "List instances."
97
125
  end
@@ -132,7 +160,13 @@ class Morpheus::Cli::Instances
132
160
 
133
161
  params['showDeleted'] = true if options[:showDeleted]
134
162
  params['deleted'] = true if options[:deleted]
135
-
163
+ params['labels'] = options[:labels] if options[:labels]
164
+ if options[:tags]
165
+ options[:tags].each do |k,v|
166
+ params['tags.' + k] = v
167
+ end
168
+ end
169
+
136
170
  @instances_interface.setopts(options)
137
171
  if options[:dry_run]
138
172
  print_dry_run @instances_interface.dry.list(params)
@@ -196,7 +230,7 @@ class Morpheus::Cli::Instances
196
230
  cpu_usage_str = !stats ? "" : generate_usage_bar((stats['usedCpu'] || stats['cpuUsage']).to_f, 100, {max_bars: 10})
197
231
  memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
198
232
  storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
199
- if options[:details]
233
+ if options[:details] || options[:stats]
200
234
  if stats['maxMemory'] && stats['maxMemory'].to_i != 0
201
235
  memory_usage_str = memory_usage_str + cyan + format_bytes_short(stats['usedMemory']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxMemory']).strip
202
236
  end
@@ -214,8 +248,9 @@ class Morpheus::Cli::Instances
214
248
  nodes: instance['containers'].count,
215
249
  status: format_instance_status(instance, cyan),
216
250
  type: instance['instanceType']['name'],
217
- group: !instance['group'].nil? ? instance['group']['name'] : nil,
218
- cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil,
251
+ group: instance['group'] ? instance['group']['name'] : nil,
252
+ cloud: instance['cloud'] ? instance['cloud']['name'] : nil,
253
+ plan: instance['plan'] ? instance['plan']['name'] : '',
219
254
  version: instance['instanceVersion'] ? instance['instanceVersion'] : '',
220
255
  created: format_local_dt(instance['dateCreated']),
221
256
  cpu: cpu_usage_str + cyan,
@@ -229,12 +264,13 @@ class Morpheus::Cli::Instances
229
264
  {:created => {:display_name => "CREATED"}},
230
265
  # {:tenant => {:display_name => "TENANT"}},
231
266
  {:user => {:display_name => "OWNER", :max_width => 20}},
267
+ :plan,
232
268
  :nodes, {:connection => {:max_width => 30}}, :status, :cpu, :memory, :storage]
233
269
  # custom pretty table columns ... this is handled in as_pretty_table now(),
234
270
  # todo: remove all these.. and try to always pass rows as the json data itself..
235
- # if options[:include_fields]
236
- # columns = options[:include_fields]
237
- # end
271
+ if options[:details] != true
272
+ columns.delete(:plan)
273
+ end
238
274
  print cyan
239
275
  print as_pretty_table(rows, columns, options)
240
276
  print reset
@@ -347,18 +383,16 @@ class Morpheus::Cli::Instances
347
383
  opts.on("--environment ENV", String, "Environment code") do |val|
348
384
  options[:environment] = val.to_s
349
385
  end
350
- opts.on('--metadata LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
386
+ opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
351
387
  options[:metadata] = val
352
388
  end
353
- opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
354
- #options[:tags] = val
355
- options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
389
+ opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
390
+ options[:metadata] = val
356
391
  end
357
- opts.on('--tags LIST', String, "Tags") do |val|
358
- #options[:tags] = val
359
- options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
392
+ opts.add_hidden_option('--metadata')
393
+ opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
394
+ options[:labels] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
360
395
  end
361
- opts.add_hidden_option('--tags')
362
396
  opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
363
397
  options[:copies] = val.to_i
364
398
  end
@@ -425,17 +459,58 @@ class Morpheus::Cli::Instances
425
459
  options[:instance_name] = args[0]
426
460
  end
427
461
 
428
- # use active group by default
429
- options[:group] ||= @active_group_id
430
- options[:select_datastore] = true
431
- options[:name_required] = true
432
462
  begin
433
463
  payload = nil
434
464
  if options[:payload]
435
465
  payload = options[:payload]
436
466
  # support -O OPTION switch on top of --payload
437
467
  payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
468
+ # obviously should support every option that prompt supports on top of -- payload as well
469
+ # group, cloud and type for now
470
+ # todo: also support :layout, service_plan, :resource_pool, etc.
471
+ group = nil
472
+ if options[:group]
473
+ group = find_group_by_name_or_id_for_provisioning(options[:group])
474
+ if group.nil?
475
+ return 1, "group not found by #{options[:group]}"
476
+ end
477
+ #payload["siteId"] = group["id"]
478
+ payload.deep_merge!({"instance" => {"site" => {"id" => group["id"]} } })
479
+ end
480
+ if options[:cloud]
481
+ group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
482
+ cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
483
+ if cloud.nil?
484
+ return 1, "cloud not found by #{options[:cloud]}"
485
+ end
486
+ payload["zoneId"] = cloud["id"]
487
+ payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
488
+ end
489
+ if options[:cloud]
490
+ group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
491
+ cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
492
+ if cloud.nil?
493
+ return 1, "cloud not found by #{options[:cloud]}"
494
+ end
495
+ payload["zoneId"] = cloud["id"]
496
+ payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
497
+ end
498
+ if options[:instance_type_code]
499
+ # should just use find_instance_type_by_name_or_id
500
+ # note that the api actually will match name name or code
501
+ instance_type = (options[:instance_type_code].to_s =~ /\A\d{1,}\Z/) ? find_instance_type_by_id(options[:instance_type_code]) : find_instance_type_by_code(options[:instance_type_code])
502
+ if instance_type.nil?
503
+ return 1, "instance type not found by #{options[:cloud]}"
504
+ end
505
+ payload.deep_merge!({"instance" => {"type" => instance_type["code"] } })
506
+ payload.deep_merge!({"instance" => {"instanceType" => {"code" => instance_type["code"]} } })
507
+ end
508
+
438
509
  else
510
+ # use active group by default
511
+ options[:group] ||= @active_group_id
512
+ options[:select_datastore] = true
513
+ options[:name_required] = true
439
514
  # prompt for all the instance configuration options
440
515
  # this provisioning helper method handles all (most) of the parsing and prompting
441
516
  # and it relies on the method to exit non-zero on error, like a bad CLOUD or TYPE value
@@ -528,18 +603,18 @@ class Morpheus::Cli::Instances
528
603
  opts.on('--group GROUP', String, "Group Name or ID") do |val|
529
604
  options[:group] = val
530
605
  end
531
- opts.on('--metadata LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
532
- options[:metadata] = val
533
- end
534
606
  opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
535
- #params['tags'] = val
536
- params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
607
+ params['labels'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
608
+ end
609
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
610
+ options[:tags] = val
537
611
  end
538
- opts.on('--tags LIST', String, "Tags") do |val|
539
- #params['tags'] = val
540
- params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
612
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
613
+ options[:add_tags] = val
614
+ end
615
+ 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|
616
+ options[:remove_tags] = val
541
617
  end
542
- opts.add_hidden_option('--tags')
543
618
  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
544
619
  params['powerScheduleType'] = val == "null" ? nil : val
545
620
  end
@@ -594,29 +669,17 @@ class Morpheus::Cli::Instances
594
669
  payload['instance']['site'] = {'id' => group['id']}
595
670
  end
596
671
  # metadata tags
597
- # if options[:options]['metadata'].is_a?(Array) && !options[:metadata]
598
- # options[:metadata] = options[:options]['metadata']
599
- # end
600
- if options[:metadata]
601
- metadata = []
602
- if options[:metadata] == "[]" || options[:metadata] == "null"
603
- payload['instance']['metadata'] = []
604
- elsif options[:metadata].is_a?(Array)
605
- payload['instance']['metadata'] = options[:metadata]
606
- else
607
- # parse string into format name:value, name:value
608
- # merge IDs from current metadata
609
- # todo: should allow quoted semicolons..
610
- metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
611
- metadata_list = metadata_list.collect do |it|
612
- metadata_pair = it.split(":")
613
- row = {}
614
- row['name'] = metadata_pair[0].to_s.strip
615
- row['value'] = metadata_pair[1].to_s.strip
616
- row
617
- end
618
- payload['instance']['metadata'] = metadata_list
619
- end
672
+ if options[:tags]
673
+ # api version 4.2.5 and later supports tags, older versions expect metadata
674
+ # todo: use tags instead like everywhere else
675
+ # payload['instance']['tags'] = parse_metadata(options[:tags])
676
+ payload['instance']['metadata'] = parse_metadata(options[:tags])
677
+ end
678
+ if options[:add_tags]
679
+ payload['instance']['addTags'] = parse_metadata(options[:add_tags])
680
+ end
681
+ if options[:remove_tags]
682
+ payload['instance']['removeTags'] = parse_metadata(options[:remove_tags])
620
683
  end
621
684
  if payload['instance'].empty? && params.empty? && options[:owner].nil?
622
685
  raise_command_error "Specify at least one option to update.\n#{optparse}"
@@ -1217,7 +1280,18 @@ class Morpheus::Cli::Instances
1217
1280
  instance = json_response['instance']
1218
1281
  stats = instance['stats'] || json_response['stats'] || {}
1219
1282
  # load_balancers = json_response['loadBalancers'] || {}
1220
-
1283
+ # metadata tags used to be returned as metadata and are now returned as tags
1284
+ # the problem is tags is what we used to call Labels (keywords)
1285
+ # the api will change to tags and labels, so handle the old format as long as metadata is returned.
1286
+ labels = nil
1287
+ tags = nil
1288
+ if instance.key?('labels')
1289
+ labels = instance['labels']
1290
+ tags = instance['tags']
1291
+ else
1292
+ labels = instance['tags']
1293
+ tags = instance['metadata']
1294
+ end
1221
1295
  # containers are fetched via separate api call
1222
1296
  containers = nil
1223
1297
  if options[:include_containers]
@@ -1258,8 +1332,8 @@ class Morpheus::Cli::Instances
1258
1332
  # "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1259
1333
  # "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1260
1334
  "Environment" => 'instanceContext',
1261
- "Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
1262
- "Metadata" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
1335
+ "Labels" => lambda {|it| labels ? labels.join(',') : '' },
1336
+ "Tags" => lambda {|it| tags ? tags.collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
1263
1337
  "Owner" => lambda {|it|
1264
1338
  if it['owner']
1265
1339
  (it['owner']['username'] || it['owner']['id'])
@@ -1278,11 +1352,14 @@ class Morpheus::Cli::Instances
1278
1352
  "Connection" => lambda {|it| format_instance_connection_string(it) },
1279
1353
  "Status" => lambda {|it| format_instance_status(it) }
1280
1354
  }
1355
+ description_cols.delete("Labels") if labels.nil? || labels.empty?
1356
+ description_cols.delete("Tags") if tags.nil? || tags.empty?
1281
1357
  description_cols.delete("Power Schedule") if instance['powerSchedule'].nil?
1282
1358
  description_cols.delete("Expire Date") if instance['expireDate'].nil?
1283
1359
  description_cols.delete("Shutdown Date") if instance['shutdownDate'].nil?
1284
1360
  description_cols["Removal Date"] = lambda {|it| format_local_dt(it['removalDate'])} if instance['status'] == 'pendingRemoval'
1285
1361
  description_cols.delete("Last Deployment") if instance['lastDeploy'].nil?
1362
+ #description_cols.delete("Environment") if instance['instanceContext'].nil?
1286
1363
  print_description_list(description_cols, instance)
1287
1364
 
1288
1365
  if instance['statusMessage']
@@ -2596,6 +2673,48 @@ class Morpheus::Cli::Instances
2596
2673
  end
2597
2674
  end
2598
2675
 
2676
+ def snapshot(args)
2677
+ options = {}
2678
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2679
+ opts.banner = subcommand_usage("[instance]")
2680
+ opts.on( '--name VALUE', String, "Snapshot Name. Default is server name + timestamp" ) do |val|
2681
+ options[:options]['name'] = val
2682
+ end
2683
+ opts.on( '--description VALUE', String, "Snapshot Description." ) do |val|
2684
+ options[:options]['description'] = val
2685
+ end
2686
+ build_standard_add_options(opts, options, [:auto_confirm])
2687
+ opts.footer = <<-EOT
2688
+ Create a snapshot for an instance.
2689
+ [instance] is required. This is the name or id of an instance
2690
+ EOT
2691
+ end
2692
+ optparse.parse!(args)
2693
+ verify_args!(args:args, optparse:optparse, count:1)
2694
+ connect(options)
2695
+ instance = find_instance_by_name_or_id(args[0])
2696
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to snapshot the instance '#{instance['name']}'?", options)
2697
+ exit 1
2698
+ end
2699
+ payload = {}
2700
+ if options[:payload]
2701
+ payload = options[:payload]
2702
+ payload.deep_merge!({'snapshot' => parse_passed_options(options)})
2703
+ else
2704
+ payload.deep_merge!({'snapshot' => parse_passed_options(options)})
2705
+ end
2706
+ @instances_interface.setopts(options)
2707
+ if options[:dry_run]
2708
+ print_dry_run @instances_interface.dry.snapshot(instance['id'], payload)
2709
+ return
2710
+ end
2711
+ json_response = @instances_interface.snapshot(instance['id'], payload)
2712
+ render_response(json_response, options, 'snapshots') do
2713
+ print_green_success "Snapshot initiated."
2714
+ end
2715
+ return 0, nil
2716
+ end
2717
+
2599
2718
  def remove(args)
2600
2719
  options = {}
2601
2720
  query_params = {}
@@ -2898,6 +3017,57 @@ class Morpheus::Cli::Instances
2898
3017
  end
2899
3018
  end
2900
3019
 
3020
+ def snapshots(args)
3021
+ options = {}
3022
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
3023
+ opts.banner = subcommand_usage("[instance]")
3024
+ # no pagination yet
3025
+ # build_standard_list_options(opts, options)
3026
+ build_standard_get_options(opts, options)
3027
+ opts.footer = <<-EOT
3028
+ List snapshots for an instance.
3029
+ [instance] is required. This is the name or id of an instance
3030
+ EOT
3031
+ end
3032
+ optparse.parse!(args)
3033
+ verify_args!(args:args, optparse:optparse, count:1)
3034
+ connect(options)
3035
+ begin
3036
+ instance = find_instance_by_name_or_id(args[0])
3037
+ params = {}
3038
+ @instances_interface.setopts(options)
3039
+ if options[:dry_run]
3040
+ print_dry_run @instances_interface.dry.snapshots(instance['id'], params)
3041
+ return
3042
+ end
3043
+ json_response = @instances_interface.snapshots(instance['id'], params)
3044
+ snapshots = json_response['snapshots']
3045
+ render_response(json_response, options, 'snapshots') do
3046
+ print_h1 "Snapshots: #{instance['name']} (#{instance['instanceType']['name']})", [], options
3047
+ if snapshots.empty?
3048
+ print cyan,"No snapshots found",reset,"\n"
3049
+ else
3050
+ snapshot_column_definitions = {
3051
+ "ID" => lambda {|it| it['id'] },
3052
+ "Name" => lambda {|it| it['name'] },
3053
+ "Description" => lambda {|it| it['description'] },
3054
+ # "Type" => lambda {|it| it['snapshotType'] },
3055
+ "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
3056
+ "Status" => lambda {|it| format_snapshot_status(it) }
3057
+ }
3058
+ print cyan
3059
+ print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
3060
+ print_results_pagination({size: snapshots.size, total: snapshots.size})
3061
+ end
3062
+ print reset, "\n"
3063
+ end
3064
+ return 0
3065
+ rescue RestClient::Exception => e
3066
+ print_rest_exception(e, options)
3067
+ exit 1
3068
+ end
3069
+ end
3070
+
2901
3071
  def import_snapshot(args)
2902
3072
  options = {}
2903
3073
  query_params = {}
@@ -3810,51 +3980,6 @@ private
3810
3980
  end
3811
3981
  end
3812
3982
 
3813
- def format_instance_status(instance, return_color=cyan)
3814
- out = ""
3815
- status_string = instance['status'].to_s
3816
- if status_string == 'running'
3817
- out << "#{green}#{status_string.upcase}#{return_color}"
3818
- elsif status_string == 'provisioning'
3819
- out << "#{cyan}#{status_string.upcase}#{return_color}"
3820
- elsif status_string == 'stopped' or status_string == 'failed'
3821
- out << "#{red}#{status_string.upcase}#{return_color}"
3822
- else
3823
- out << "#{yellow}#{status_string.upcase}#{return_color}"
3824
- end
3825
- out
3826
- end
3827
-
3828
- def format_instance_connection_string(instance)
3829
- if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
3830
- connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
3831
- end
3832
- end
3833
-
3834
- def format_container_status(container, return_color=cyan)
3835
- out = ""
3836
- status_string = container['status'].to_s
3837
- if status_string == 'running'
3838
- out << "#{green}#{status_string.upcase}#{return_color}"
3839
- elsif status_string == 'provisioning'
3840
- out << "#{cyan}#{status_string.upcase}#{return_color}"
3841
- elsif status_string == 'stopped' or status_string == 'failed'
3842
- out << "#{red}#{status_string.upcase}#{return_color}"
3843
- else
3844
- out << "#{yellow}#{status_string.upcase}#{return_color}"
3845
- end
3846
- out
3847
- end
3848
-
3849
- def format_container_connection_string(container)
3850
- if !container['ports'].nil? && container['ports'].empty? == false
3851
- connection_string = "#{container['ip']}:#{container['ports'][0]['external']}"
3852
- else
3853
- # eh? more logic needed here i think, see taglib morph:containerLocationMenu
3854
- connection_string = "#{container['ip']}"
3855
- end
3856
- end
3857
-
3858
3983
  def instance_scaling_option_types(instance=nil)
3859
3984
 
3860
3985
  # Group
@@ -3908,17 +4033,6 @@ private
3908
4033
  list
3909
4034
  end
3910
4035
 
3911
- def format_instance_container_display_name(instance, plural=false)
3912
- #<span class="info-label">${[null,'docker'].contains(instance.layout?.provisionType?.code) ? 'Containers' : 'Virtual Machines'}:</span> <span class="info-value">${instance.containers?.size()}</span>
3913
- v = plural ? "Containers" : "Container"
3914
- if instance && instance['layout'] && instance['layout'].key?("provisionTypeCode")
3915
- if [nil, 'docker'].include?(instance['layout']["provisionTypeCode"])
3916
- v = plural ? "Virtual Machines" : "Virtual Machine"
3917
- end
3918
- end
3919
- return v
3920
- end
3921
-
3922
4036
  def print_instance_threshold_description_list(instance_threshold)
3923
4037
  description_cols = {
3924
4038
  # "Instance" => lambda {|it| "#{instance['id']} - #{instance['name']}" },
@@ -4024,19 +4138,4 @@ private
4024
4138
  }
4025
4139
  end
4026
4140
 
4027
- def format_app_deploy_status(status, return_color=cyan)
4028
- out = ""
4029
- s = status.to_s.downcase
4030
- if s == 'deployed'
4031
- out << "#{green}#{s.upcase}#{return_color}"
4032
- elsif s == 'open' || s == 'archived' || s == 'committed'
4033
- out << "#{cyan}#{s.upcase}#{return_color}"
4034
- elsif s == 'failed'
4035
- out << "#{red}#{s.upcase}#{return_color}"
4036
- else
4037
- out << "#{yellow}#{s.upcase}#{return_color}"
4038
- end
4039
- out
4040
- end
4041
-
4042
4141
  end