morpheus-cli 4.1.4 → 4.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus.rb +5 -0
  3. data/lib/morpheus/api.rb +2 -2
  4. data/lib/morpheus/api/api_client.rb +47 -12
  5. data/lib/morpheus/api/appliance_settings_interface.rb +30 -0
  6. data/lib/morpheus/api/auth_interface.rb +14 -10
  7. data/lib/morpheus/api/clouds_interface.rb +7 -0
  8. data/lib/morpheus/api/clusters_interface.rb +17 -5
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +2 -3
  10. data/lib/morpheus/api/deployments_interface.rb +7 -0
  11. data/lib/morpheus/api/execute_schedules_interface.rb +2 -3
  12. data/lib/morpheus/api/groups_interface.rb +7 -0
  13. data/lib/morpheus/api/license_interface.rb +9 -2
  14. data/lib/morpheus/api/load_balancers_interface.rb +7 -0
  15. data/lib/morpheus/api/logs_interface.rb +11 -2
  16. data/lib/morpheus/api/monitoring_alerts_interface.rb +45 -0
  17. data/lib/morpheus/api/monitoring_checks_interface.rb +2 -2
  18. data/lib/morpheus/api/monitoring_interface.rb +13 -8
  19. data/lib/morpheus/api/power_schedules_interface.rb +2 -3
  20. data/lib/morpheus/api/servers_interface.rb +5 -2
  21. data/lib/morpheus/api/setup_interface.rb +25 -7
  22. data/lib/morpheus/api/task_sets_interface.rb +7 -1
  23. data/lib/morpheus/api/tasks_interface.rb +7 -0
  24. data/lib/morpheus/api/virtual_images_interface.rb +2 -3
  25. data/lib/morpheus/api/whitelabel_settings_interface.rb +60 -0
  26. data/lib/morpheus/cli.rb +18 -14
  27. data/lib/morpheus/cli/access_token_command.rb +18 -2
  28. data/lib/morpheus/cli/appliance_settings_command.rb +303 -0
  29. data/lib/morpheus/cli/apps.rb +4 -3
  30. data/lib/morpheus/cli/archives_command.rb +0 -21
  31. data/lib/morpheus/cli/blueprints_command.rb +2 -2
  32. data/lib/morpheus/cli/cli_command.rb +32 -8
  33. data/lib/morpheus/cli/clouds.rb +6 -11
  34. data/lib/morpheus/cli/clusters.rb +346 -117
  35. data/lib/morpheus/cli/command_error.rb +4 -0
  36. data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
  37. data/lib/morpheus/cli/containers_command.rb +2 -1
  38. data/lib/morpheus/cli/credentials.rb +49 -4
  39. data/lib/morpheus/cli/deployments.rb +2 -2
  40. data/lib/morpheus/cli/dot_file.rb +2 -2
  41. data/lib/morpheus/cli/error_handler.rb +6 -3
  42. data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
  43. data/lib/morpheus/cli/groups.rb +4 -4
  44. data/lib/morpheus/cli/hosts.rb +3 -2
  45. data/lib/morpheus/cli/image_builder_command.rb +0 -21
  46. data/lib/morpheus/cli/instances.rb +17 -4
  47. data/lib/morpheus/cli/library_container_types_command.rb +1 -1
  48. data/lib/morpheus/cli/library_layouts_command.rb +1 -1
  49. data/lib/morpheus/cli/library_upgrades_command.rb +1 -1
  50. data/lib/morpheus/cli/license.rb +185 -72
  51. data/lib/morpheus/cli/load_balancers.rb +4 -4
  52. data/lib/morpheus/cli/login.rb +4 -0
  53. data/lib/morpheus/cli/logs_command.rb +132 -0
  54. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +2 -2
  55. data/lib/morpheus/cli/mixins/logs_helper.rb +65 -0
  56. data/lib/morpheus/cli/mixins/monitoring_helper.rb +410 -28
  57. data/lib/morpheus/cli/mixins/print_helper.rb +14 -4
  58. data/lib/morpheus/cli/monitoring_alerts_command.rb +800 -0
  59. data/lib/morpheus/cli/monitoring_apps_command.rb +85 -28
  60. data/lib/morpheus/cli/monitoring_checks_command.rb +60 -27
  61. data/lib/morpheus/cli/monitoring_contacts_command.rb +54 -79
  62. data/lib/morpheus/cli/monitoring_groups_command.rb +62 -23
  63. data/lib/morpheus/cli/monitoring_incidents_command.rb +91 -70
  64. data/lib/morpheus/cli/network_pools_command.rb +39 -23
  65. data/lib/morpheus/cli/power_schedules_command.rb +1 -1
  66. data/lib/morpheus/cli/remote.rb +834 -275
  67. data/lib/morpheus/cli/roles.rb +100 -38
  68. data/lib/morpheus/cli/tasks.rb +1 -1
  69. data/lib/morpheus/cli/user_settings_command.rb +20 -12
  70. data/lib/morpheus/cli/version.rb +1 -1
  71. data/lib/morpheus/cli/virtual_images.rb +1 -1
  72. data/lib/morpheus/cli/whitelabel_settings_command.rb +546 -0
  73. data/lib/morpheus/cli/whoami.rb +1 -1
  74. data/lib/morpheus/cli/workflows.rb +2 -2
  75. data/lib/morpheus/terminal.rb +22 -8
  76. metadata +11 -2
@@ -5,12 +5,14 @@ require 'optparse'
5
5
  require 'morpheus/cli/cli_command'
6
6
  require 'morpheus/cli/option_types'
7
7
  require 'morpheus/cli/mixins/accounts_helper'
8
+ require 'morpheus/cli/mixins/provisioning_helper'
8
9
  require 'json'
9
10
 
10
11
  class Morpheus::Cli::Roles
11
12
  include Morpheus::Cli::CliCommand
12
13
  include Morpheus::Cli::AccountsHelper
13
- register_subcommands :list, :get, :add, :update, :remove, :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access', :'update-global-blueprint-access', :'update-blueprint-access'
14
+ include Morpheus::Cli::ProvisioningHelper
15
+ register_subcommands :list, :get, :add, :update, :remove, :'list-permissions', :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access', :'update-global-blueprint-access', :'update-blueprint-access'
14
16
  alias_subcommand :details, :get
15
17
  set_default_subcommand :list
16
18
 
@@ -22,7 +24,7 @@ class Morpheus::Cli::Roles
22
24
  @roles_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).roles
23
25
  @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
24
26
  @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
25
- #@clouds_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
27
+ @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
26
28
  @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
27
29
  @blueprints_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).blueprints
28
30
  @active_group_id = Morpheus::Cli::Groups.active_group
@@ -88,9 +90,13 @@ class Morpheus::Cli::Roles
88
90
  options = {}
89
91
  optparse = Morpheus::Cli::OptionParser.new do |opts|
90
92
  opts.banner = subcommand_usage("[name]")
91
- opts.on('-f','--feature-access', "Display Feature Access") do |val|
93
+ opts.on('-p','--permissions', "Display Permissions") do |val|
92
94
  options[:include_feature_access] = true
93
95
  end
96
+ opts.on('-f','--feature-access', "Display Feature Access [deprecated]") do |val|
97
+ options[:include_feature_access] = true
98
+ end
99
+ opts.add_hidden_option('--feature-access')
94
100
  opts.on('-g','--group-access', "Display Group Access") do
95
101
  options[:include_group_access] = true
96
102
  end
@@ -189,9 +195,8 @@ class Morpheus::Cli::Roles
189
195
  # "CPU Count" => lambda {|it| (it && it['maxCpu'].to_i != 0) ? it['maxCpu'] : "no limit" }
190
196
  # }, role['instanceLimits'])
191
197
 
192
- # print_h2 "Feature Access", options
193
- # print cyan
194
-
198
+ print_h2 "Permissions", options
199
+ print cyan
195
200
  if options[:include_feature_access]
196
201
  rows = json_response['featurePermissions'].collect do |it|
197
202
  {
@@ -202,7 +207,7 @@ class Morpheus::Cli::Roles
202
207
  end
203
208
  print as_pretty_table(rows, [:code, :name, :access], options)
204
209
  else
205
- puts "Use --feature-access to list feature access"
210
+ puts "Use --permissions to list permissions"
206
211
  end
207
212
 
208
213
  print_h2 "Group Access", options
@@ -283,6 +288,89 @@ class Morpheus::Cli::Roles
283
288
  end
284
289
  end
285
290
 
291
+ def list_permissions(args)
292
+ options = {}
293
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
294
+ opts.banner = subcommand_usage("[role]")
295
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
296
+ opts.footer = "List the permissions for a role.\n" +
297
+ "[role] is required. This is the name or id of a role."
298
+ end
299
+ optparse.parse!(args)
300
+
301
+ if args.count < 1
302
+ puts optparse
303
+ return 1
304
+ end
305
+
306
+ connect(options)
307
+ begin
308
+ account = find_account_from_options(options)
309
+ account_id = account ? account['id'] : nil
310
+
311
+ # role = find_role_by_name_or_id(account_id, args[0])
312
+ # exit 1 if role.nil?
313
+
314
+ @roles_interface.setopts(options)
315
+ if options[:dry_run]
316
+ if args[0].to_s =~ /\A\d{1,}\Z/
317
+ print_dry_run @roles_interface.dry.get(account_id, args[0].to_i)
318
+ else
319
+ print_dry_run @roles_interface.dry.list(account_id, {name: args[0]})
320
+ end
321
+ return
322
+ end
323
+
324
+ json_response = nil
325
+ if args[0].to_s =~ /\A\d{1,}\Z/
326
+ json_response = @roles_interface.get(account_id, args[0].to_i)
327
+ role = json_response['role']
328
+ else
329
+ role = find_role_by_name_or_id(account_id, args[0])
330
+ exit 1 if role.nil?
331
+ # refetch from show action, argh
332
+ json_response = @roles_interface.get(account_id, role['id'])
333
+ role = json_response['role']
334
+ end
335
+
336
+ role_permissions = json_response['featurePermissions']
337
+
338
+ if options[:json]
339
+ puts as_json(role_permissions, options)
340
+ return 0
341
+ elsif options[:yaml]
342
+ puts as_yaml(role_permissions, options)
343
+ return 0
344
+ elsif options[:csv]
345
+ puts records_as_csv(role_permissions)
346
+ return 0
347
+ end
348
+
349
+ print cyan
350
+ print_h1 "Role Permissions: [#{role['id']}] #{role['authority']}", options
351
+
352
+ print cyan
353
+ if role_permissions && role_permissions.size > 0
354
+ rows = role_permissions.collect do |it|
355
+ {
356
+ code: it['code'],
357
+ name: it['name'],
358
+ access: get_access_string(it['access']),
359
+ }
360
+ end
361
+ print as_pretty_table(rows, [:code, :name, :access], options)
362
+ else
363
+ puts "No permissions found?"
364
+ end
365
+
366
+ print reset,"\n"
367
+ return 0
368
+ rescue RestClient::Exception => e
369
+ print_rest_exception(e, options)
370
+ exit 1
371
+ end
372
+ end
373
+
286
374
  def add(args)
287
375
  usage = "Usage: morpheus roles add [options]"
288
376
  options = {}
@@ -387,7 +475,7 @@ class Morpheus::Cli::Roles
387
475
  optparse = Morpheus::Cli::OptionParser.new do |opts|
388
476
  opts.banner = subcommand_usage("[name] [options]")
389
477
  build_option_type_options(opts, options, update_role_option_types)
390
- build_common_options(opts, options, [:options, :json, :dry_run, :remote])
478
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
391
479
  end
392
480
  optparse.parse!(args)
393
481
 
@@ -543,7 +631,7 @@ class Morpheus::Cli::Roles
543
631
  print JSON.pretty_generate(json_response)
544
632
  print "\n"
545
633
  else
546
- print_green_success "Role #{role['authority']} feature access updated"
634
+ print_green_success "Role #{role['authority']} permission #{permission_code} set to #{access_value}"
547
635
  end
548
636
  rescue RestClient::Exception => e
549
637
  print_rest_exception(e, options)
@@ -555,7 +643,7 @@ class Morpheus::Cli::Roles
555
643
  usage = "Usage: morpheus roles update-global-group-access [name] [full|read|custom|none]"
556
644
  options = {}
557
645
  optparse = Morpheus::Cli::OptionParser.new do |opts|
558
- opts.banner = subcommand_usage("[name] [code] [full|read|custom|none]")
646
+ opts.banner = subcommand_usage("[name] [full|read|custom|none]")
559
647
  build_common_options(opts, options, [:json, :dry_run, :remote])
560
648
  end
561
649
  optparse.parse!(args)
@@ -658,12 +746,10 @@ class Morpheus::Cli::Roles
658
746
  exit 1
659
747
  end
660
748
 
661
- # group_id = find_group_id_by_name(group_name)
662
- # exit 1 if group_id.nil?
663
749
  group = nil
664
750
  group_id = nil
665
751
  if !do_all
666
- group = find_group_by_name(group_name)
752
+ group = find_group_by_name_or_id_for_provisioning(group_name)
667
753
  return 1 if group.nil?
668
754
  group_id = group['id']
669
755
  end
@@ -817,9 +903,7 @@ class Morpheus::Cli::Roles
817
903
  if !do_all
818
904
  group_id = nil
819
905
  if !options[:group].nil?
820
- #group_id = find_group_id_by_name(options[:group])
821
- group = find_group_by_name(options[:group])
822
- return 1 if group.nil?
906
+ group = find_group_by_name_or_id_for_provisioning(options[:group])
823
907
  group_id = group['id']
824
908
  else
825
909
  group_id = @active_group_id
@@ -1193,28 +1277,6 @@ class Morpheus::Cli::Roles
1193
1277
  end
1194
1278
 
1195
1279
 
1196
- def find_group_by_name(name)
1197
- group_results = @groups_interface.get(name)
1198
- if group_results['groups'].empty?
1199
- print_red_alert "Group not found by name #{name}"
1200
- return nil
1201
- end
1202
- return group_results['groups'][0]
1203
- end
1204
-
1205
- # no worky, returning {"success"=>true, "data"=>[]}
1206
- # def find_group_id_by_name(name)
1207
- # option_results = @options_interface.options_for_source('groups',{})
1208
- # puts "option_results: #{option_results.inspect}"
1209
- # match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
1210
- # if match.nil?
1211
- # print_red_alert "Group not found by name #{name}"
1212
- # return nil
1213
- # else
1214
- # return match['value']
1215
- # end
1216
- # end
1217
-
1218
1280
  def find_cloud_id_by_name(group_id, name)
1219
1281
  option_results = @options_interface.options_for_source('clouds', {groupId: group_id})
1220
1282
  match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
@@ -641,7 +641,7 @@ class Morpheus::Cli::Tasks
641
641
  end
642
642
 
643
643
  def find_task_by_name(name)
644
- tasks = @tasks_interface.get({name: name.to_s})['tasks']
644
+ tasks = @tasks_interface.list({name: name.to_s})['tasks']
645
645
  if tasks.empty?
646
646
  print_red_alert "Task not found by name #{name}"
647
647
  return nil
@@ -87,9 +87,10 @@ class Morpheus::Cli::UserSettingsCommand
87
87
  print_h2 "API Access Tokens"
88
88
  cols = {
89
89
  #"ID" => lambda {|it| it['id'] },
90
- "Client ID" => lambda {|it| it['clientId'] },
91
- "Username" => lambda {|it| it['username'] },
92
- "Expiration" => lambda {|it| format_local_dt(it['expiration']) }
90
+ "CLIENT ID" => lambda {|it| it['clientId'] },
91
+ "USERNAME" => lambda {|it| it['username'] },
92
+ "EXPIRATION" => lambda {|it| format_local_dt(it['expiration']) },
93
+ "TTL" => lambda {|it| it['expiration'] ? (format_duration(it['expiration']) rescue '') : '' }
93
94
  }
94
95
  print cyan
95
96
  puts as_pretty_table(access_tokens, cols)
@@ -217,7 +218,7 @@ class Morpheus::Cli::UserSettingsCommand
217
218
  options = {}
218
219
  params = {}
219
220
  optparse = Morpheus::Cli::OptionParser.new do |opts|
220
- opts.banner = subcommand_usage("[file]")
221
+ opts.banner = subcommand_usage()
221
222
  opts.on("--user-id ID", String, "User ID") do |val|
222
223
  params['userId'] = val.to_s
223
224
  end
@@ -332,12 +333,15 @@ class Morpheus::Cli::UserSettingsCommand
332
333
  return
333
334
  end
334
335
  json_response = @user_settings_interface.regenerate_access_token(params, payload)
335
- new_access_token = json_response['token']
336
+ new_access_token = json_response['access_token'] || json_response['token']
336
337
  # update credentials if regenerating cli token
337
- if params['clientId'] == 'morph-cli'
338
- if new_access_token
339
- login_opts = {:remote_token => new_access_token}
340
- login_result = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).login(login_opts)
338
+ if params['clientId'] == Morpheus::APIClient::CLIENT_ID
339
+ if params['userId'].nil? # should check against current user id
340
+ if new_access_token
341
+ # this sux, need to save refresh_token too.. just save to wallet and refresh shell maybe?
342
+ login_opts = {:remote_token => new_access_token}
343
+ login_result = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).login(login_opts)
344
+ end
341
345
  end
342
346
  end
343
347
  if options[:quiet]
@@ -393,11 +397,11 @@ class Morpheus::Cli::UserSettingsCommand
393
397
  end
394
398
  new_access_token = json_response['token']
395
399
  # update credentials if regenerating cli token
396
- # if params['clientId'] == 'morph-cli'
400
+ # if params['clientId'] == Morpheus::APIClient::CLIENT_ID
397
401
  # logout_result = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).logout
398
402
  # end
399
403
  print_green_success "Cleared #{params['clientId']} access token"
400
- if params['clientId'] == 'morph-cli'
404
+ if params['clientId'] == Morpheus::APIClient::CLIENT_ID
401
405
  print yellow,"Your current access token is no longer valid, you will need to login again.",reset,"\n"
402
406
  end
403
407
  # get_args = [] + (options[:remote] ? ["-r",options[:remote]] : []) + (params['userId'] ? ['--user-id', params['userId'].to_s] : [])
@@ -451,7 +455,11 @@ class Morpheus::Cli::UserSettingsCommand
451
455
  clients = json_response['clients'] || json_response['apiClients']
452
456
  print_h1 "Morpheus API Clients"
453
457
  columns = {
454
- "Client ID" => lambda {|it| it['clientId'] }
458
+ "CLIENT ID" => lambda {|it| it['clientId'] },
459
+ "NAME" => lambda {|it| it['name'] },
460
+ "TTL" => lambda {|it| it['accessTokenValiditySeconds'] ? "#{it['accessTokenValiditySeconds']}" : '' },
461
+ "DURATION" => lambda {|it| it['accessTokenValiditySeconds'] ? (format_duration_seconds(it['accessTokenValiditySeconds']) rescue '') : '' },
462
+ # "USABLE" => lambda {|it| format_boolean(it['usable']) }
455
463
  }
456
464
  print cyan
457
465
  puts as_pretty_table(clients, columns)
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "4.1.4"
4
+ VERSION = "4.1.5"
5
5
  end
6
6
  end
@@ -649,7 +649,7 @@ class Morpheus::Cli::VirtualImages
649
649
  end
650
650
 
651
651
  def find_virtual_image_by_name(name)
652
- json_results = @virtual_images_interface.get({name: name.to_s})
652
+ json_results = @virtual_images_interface.list({name: name.to_s})
653
653
  if json_results['virtualImages'].empty?
654
654
  print_red_alert "Virtual Image not found by name #{name}"
655
655
  return nil
@@ -0,0 +1,546 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::WhitelabelSettingsCommand
4
+ include Morpheus::Cli::CliCommand
5
+ # include Morpheus::Cli::AccountsHelper
6
+
7
+ set_command_name :'whitelabel-settings'
8
+
9
+ register_subcommands :get, :update
10
+ register_subcommands :update_images, :reset_image, :download_image, :view_image
11
+ set_default_subcommand :get
12
+
13
+ set_command_hidden # hiding until 4.2 release
14
+
15
+ def initialize()
16
+ @image_types = {'header-logo' => 'headerLogo', 'footer-logo' => 'footerLogo', 'login-logo' => 'loginLogo', 'favicon' => 'favicon'}
17
+ end
18
+
19
+ def connect(opts)
20
+ @api_client = establish_remote_appliance_connection(opts)
21
+ @whitelabel_settings_interface = @api_client.whitelabel_settings
22
+ end
23
+
24
+ def handle(args)
25
+ handle_subcommand(args)
26
+ end
27
+
28
+ def get(args)
29
+ options = {}
30
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
31
+ opts.banner = subcommand_usage()
32
+ opts.on('--details', "Show full (not truncated) contents of Terms of Use, Privacy Policy, Override CSS" ) do
33
+ options[:details] = true
34
+ end
35
+ build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
36
+ opts.footer = "Get whitelabel settings."
37
+ end
38
+
39
+ optparse.parse!(args)
40
+ connect(options)
41
+
42
+ if args.count != 0
43
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
44
+ return 1
45
+ end
46
+
47
+ begin
48
+ params = parse_list_options(options)
49
+ @whitelabel_settings_interface.setopts(options)
50
+ if options[:dry_run]
51
+ print_dry_run @whitelabel_settings_interface.dry.get()
52
+ return
53
+ end
54
+ json_response = @whitelabel_settings_interface.get()
55
+ if options[:json]
56
+ puts as_json(json_response, options, "whitelabelSettings")
57
+ return 0
58
+ elsif options[:yaml]
59
+ puts as_yaml(json_response, options, "whitelabelSettings")
60
+ return 0
61
+ elsif options[:csv]
62
+ puts records_as_csv([json_response['whitelabelSettings']], options)
63
+ return 0
64
+ end
65
+
66
+ whitelabel_settings = json_response['whitelabelSettings']
67
+
68
+ print_h1 "Whitelabel Settings"
69
+ print cyan
70
+ description_cols = {
71
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
72
+ "Appliance Name" => lambda {|it| it['applianceName'] },
73
+ "Disable Support Menu" => lambda {|it| format_boolean(it['disableSupportMenu'])},
74
+ "Header Logo" => lambda {|it| it['headerLogo'] ? it['headerLogo'].split('/').last : '' },
75
+ "Footer Logo" => lambda {|it| it['footerLogo'] ? it['footerLogo'].split('/').last : '' },
76
+ "Login Logo" => lambda {|it| it['loginLogo'] ? it['loginLogo'].split('/').last : '' },
77
+ "Favicon" => lambda {|it| it['favicon'] ? it['favicon'].split('/').last : '' },
78
+ "Header Background" => lambda {|it| it['headerBgColor']},
79
+ "Header Foreground" => lambda {|it| it['headerFgColor']},
80
+ "Nav Background" => lambda {|it| it['navBgColor']},
81
+ "Nav Foreground" => lambda {|it| it['navFgColor']},
82
+ "Nav Hover" => lambda {|it| it['navHoverColor']},
83
+ "Primary Button Background" => lambda {|it| it['primaryButtonBgColor']},
84
+ "Primary Button Foreground" => lambda {|it| it['primaryButtonFgColor']},
85
+ "Primary Button Hover Background" => lambda {|it| it['primaryButtonHoverBgColor']},
86
+ "Primary Button Hover Foreground" => lambda {|it| it['primaryButtonHoverFgColor']},
87
+ "Footer Background" => lambda {|it| it['footerBgColor']},
88
+ "Footer Foreground" => lambda {|it| it['footerFgColor']},
89
+ "Login Background" => lambda {|it| it['loginBgColor']},
90
+ "Copyright String" => lambda {|it| it['copyrightString']}
91
+ }
92
+
93
+ print_description_list(description_cols, whitelabel_settings)
94
+
95
+ # Support Menu Links
96
+ if !whitelabel_settings['supportMenuLinks'].empty?
97
+ print_h2 "Support Menu Links"
98
+ print cyan
99
+ print as_pretty_table(whitelabel_settings['supportMenuLinks'], [:url, :label, :labelCode])
100
+ end
101
+
102
+ trunc_len = 80
103
+ if !(content = whitelabel_settings['overrideCss']).nil? && content.length
104
+ title = "Override CSS"
105
+ title = title + ' (truncated, use --details for all content)' if content && content.length > trunc_len && !options[:details]
106
+ print_h2 title
107
+ print cyan
108
+ print options[:details] ? content : truncate_string(content, trunc_len), "\n"
109
+ end
110
+ if !(content = whitelabel_settings['termsOfUse']).nil? && content.length
111
+ title = "Terms of Use"
112
+ title = title + ' (truncated, use --details for all content)' if content && content.length > trunc_len && !options[:details]
113
+ print_h2 title
114
+ print cyan
115
+ print options[:details] ? content : truncate_string(content, trunc_len), "\n"
116
+ end
117
+ if !(content = whitelabel_settings['privacyPolicy']).nil? && content.length
118
+ title = "Privacy Policy"
119
+ title = title + ' (truncated, use --details for all content)' if content && content.length > trunc_len && !options[:details]
120
+ print_h2 title
121
+ print cyan
122
+ print options[:details] ? content : truncate_string(content, trunc_len), "\n"
123
+ end
124
+ print reset "\n"
125
+ return 0
126
+ rescue RestClient::Exception => e
127
+ print_rest_exception(e, options)
128
+ return 1
129
+ end
130
+ end
131
+
132
+ def update(args)
133
+ options = {}
134
+ params = {}
135
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
136
+ opts.banner = opts.banner = subcommand_usage()
137
+ opts.on('--active [on|off]', String, "Can be used to enable / disable whitelabel feature") do |val|
138
+ params['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
139
+ end
140
+ opts.on("--appliance-name NAME", String, "Appliance name. Only available to master account") do |val|
141
+ params['applianceName'] = val == 'null' ? nil : val
142
+ end
143
+ opts.on("--disable-support-menu [on|off]", ['on','off'], "Can be used to disable support menu") do |val|
144
+ params['disableSupportMenu'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
145
+ end
146
+ opts.on("--reset-header-logo", String, "Resets header logo to default header logo") do |val|
147
+ params['resetHeaderLogo'] = true
148
+ end
149
+ opts.on("--reset-footer-logo", String, "Resets footer logo to default footer logo") do |val|
150
+ params['resetFooterLogo'] = true
151
+ end
152
+ opts.on("--reset-login-logo", String, "Resets login logo to default login logo") do |val|
153
+ params['resetLoginLogo'] = true
154
+ end
155
+ opts.on("--reset-favicon", String, "Resets favicon default favicon") do |val|
156
+ params['resetFavicon'] = true
157
+ end
158
+ opts.on("--header-bg-color VALUE", String, "Header background color") do |val|
159
+ params['headerBgColor'] = val
160
+ end
161
+ opts.on("--header-fg-color VALUE", String, "Header foreground color") do |val|
162
+ params['headerFgColor'] = val
163
+ end
164
+ opts.on("--nav-bg-color VALUE", String, "Nav background color") do |val|
165
+ params['navBgColor'] = val
166
+ end
167
+ opts.on("--nav-fg-color VALUE", String, "Nav foreground color") do |val|
168
+ params['navFgColor'] = val
169
+ end
170
+ opts.on("--nav-hover-color VALUE", String, "Nav hover color") do |val|
171
+ params['navHoverColor'] = val
172
+ end
173
+ opts.on("--primary-button-bg-color VALUE", String, "Primary button background color") do |val|
174
+ params['primaryButtonBgColor'] = val
175
+ end
176
+ opts.on("--primary-button-fg-color VALUE", String, "Primary button foreground color") do |val|
177
+ params['primaryButtonFgColor'] = val
178
+ end
179
+ opts.on("--primary-button-hover-bg-color VALUE", String, "Primary button hover background color") do |val|
180
+ params['primaryButtonHoverBgColor'] = val
181
+ end
182
+ opts.on("--primary-button-hover-fg-color VALUE", String, "Primary button hover foreground color") do |val|
183
+ params['primaryButtonHoverFgColor'] = val
184
+ end
185
+ opts.on("--footer-bg-color VALUE", String, "Footer background color") do |val|
186
+ params['footerBgColor'] = val
187
+ end
188
+ opts.on("--footer-fg-color VALUE", String, "Footer foreground color") do |val|
189
+ params['footerFgColor'] = val
190
+ end
191
+ opts.on("--login-bg-color VALUE", String, "Login background color") do |val|
192
+ params['loginBgColor'] = val
193
+ end
194
+ opts.on("--copyright TEXT", String, "Copyright String") do |val|
195
+ params['copyrightString'] = val
196
+ end
197
+ opts.on("--css TEXT", String, "Override CSS") do |val|
198
+ params['overrideCss'] = val
199
+ end
200
+ opts.on("--css-file FILE", String, "Override CSS from local file") do |val|
201
+ options[:overrideCssFile] = val
202
+ end
203
+ opts.on("--terms TEXT", String, "Terms of use content") do |val|
204
+ params['termsOfUse'] = val
205
+ end
206
+ opts.on("--terms-file FILE", String, "Terms of use content from local file") do |val|
207
+ options[:termsOfUseFile] = val
208
+ end
209
+ opts.on("--privacy-policy TEXT", String, "Privacy policy content") do |val|
210
+ params['privacyPolicy'] = val
211
+ end
212
+ opts.on("--privacy-policy-file FILE", String, "Privacy policy content from local file") do |val|
213
+ options[:privacyPolicyFile] = val
214
+ end
215
+ opts.on('--support-menu-links LIST', Array, "Support menu links. Comma delimited list of menu links. Each menu link is pipe delimited url1|label1|code1,url2|label2|code2") do |val|
216
+ options[:supportMenuLinks] = val
217
+ end
218
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
219
+ end
220
+
221
+ optparse.parse!(args)
222
+ connect(options)
223
+
224
+ if args.count != 0
225
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
226
+ return 1
227
+ end
228
+
229
+ begin
230
+ payload = parse_payload(options)
231
+ image_files = {}
232
+
233
+ if !payload
234
+ [:overrideCssFile, :termsOfUseFile, :privacyPolicyFile].each do |sym|
235
+ if options[sym]
236
+ filename = File.expand_path(options[sym])
237
+
238
+ if filename && File.file?(filename)
239
+ params[sym.to_s.delete_suffix('File')] = File.read(filename)
240
+ else
241
+ print_red_alert("File not found: #{filename}")
242
+ exit 1
243
+ end
244
+ end
245
+ end
246
+ if options[:supportMenuLinks]
247
+ params['supportMenuLinks'] = options[:supportMenuLinks].collect { |link|
248
+ parts = link.split('|')
249
+ {'url' => parts[0].strip, 'label' => (parts.count > 1 ? parts[1].strip : ''), 'labelCode' => (parts.count > 2 ? parts[2].strip : '')}
250
+ }
251
+ end
252
+ payload = {'whitelabelSettings' => params}
253
+ end
254
+
255
+ @whitelabel_settings_interface.setopts(options)
256
+ if options[:dry_run]
257
+ print_dry_run @whitelabel_settings_interface.dry.update(payload, image_files)
258
+ return
259
+ end
260
+ json_response = @whitelabel_settings_interface.update(payload, image_files)
261
+
262
+ if options[:json]
263
+ puts as_json(json_response, options)
264
+ elsif !options[:quiet]
265
+ if json_response['success']
266
+ print_green_success "Updated whitelabel settings"
267
+ get([] + (options[:remote] ? ["-r",options[:remote]] : []))
268
+ else
269
+ print_red_alert "Error updating whitelabel settings: #{json_response['msg'] || json_response['errors']}"
270
+ end
271
+ end
272
+ return 0
273
+ rescue RestClient::Exception => e
274
+ print_rest_exception(e, options)
275
+ exit 1
276
+ end
277
+ end
278
+
279
+ def update_images(args)
280
+ options = {}
281
+ params = {}
282
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
283
+ opts.banner = opts.banner = subcommand_usage()
284
+ opts.on("--header-logo FILE", String, "Header logo image. Local path of a file to upload (png|jpg|svg)") do |val|
285
+ options[:headerLogo] = val
286
+ end
287
+ opts.on("--reset-header-logo", String, "Resets header logo to default header logo") do |val|
288
+ params['resetHeaderLogo'] = true
289
+ end
290
+ opts.on("--footer-logo FILE", String, "Footer logo image. Local path of a file to upload (png|jpg|svg)") do |val|
291
+ options[:footerLogo] = val
292
+ end
293
+ opts.on("--reset-footer-logo", String, "Resets footer logo to default footer logo") do |val|
294
+ params['resetFooterLogo'] = true
295
+ end
296
+ opts.on("--login-logo FILE", String, "Login logo image. Local path of a file to upload (png|jpg|svg)") do |val|
297
+ options[:loginLogo] = val
298
+ end
299
+ opts.on("--reset-login-logo", String, "Resets login logo to default login logo") do |val|
300
+ params['resetLoginLogo'] = true
301
+ end
302
+ opts.on("--favicon FILE", String, "Favicon icon image. Local path of a file to upload") do |val|
303
+ options[:favicon] = val
304
+ end
305
+ opts.on("--reset-favicon", String, "Resets favicon default favicon") do |val|
306
+ params['resetFavicon'] = true
307
+ end
308
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
309
+ opts.footer = "Update your whitelabel images."
310
+ end
311
+
312
+ optparse.parse!(args)
313
+ connect(options)
314
+
315
+ if args.count != 0
316
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
317
+ return 1
318
+ end
319
+
320
+ begin
321
+ payload = parse_payload(options)
322
+
323
+ if !payload
324
+ payload = params
325
+
326
+ [:headerLogo, :footerLogo, :loginLogo, :favicon].each do |sym|
327
+ if options[sym]
328
+ filename = File.expand_path(options[sym])
329
+
330
+ if filename && File.file?(filename)
331
+ payload["#{sym.to_s}.file"] = File.new(filename, 'rb')
332
+ else
333
+ print_red_alert("File not found: #{filename}")
334
+ exit 1
335
+ end
336
+ end
337
+ end
338
+ end
339
+
340
+ if payload.empty?
341
+ print_green_success "Nothing to update"
342
+ exit 1
343
+ end
344
+
345
+ @whitelabel_settings_interface.setopts(options)
346
+ if options[:dry_run]
347
+ print_dry_run @whitelabel_settings_interface.dry.update_images(payload)
348
+ return
349
+ end
350
+
351
+ json_response = @whitelabel_settings_interface.update_images(payload)
352
+
353
+ if options[:json]
354
+ puts as_json(json_response, options)
355
+ elsif !options[:quiet]
356
+ print_red_alert "Error updating whitelabel image: #{json_response['msg'] || json_response['errors']}" if json_response['success'] == false
357
+ print_green_success "Updated whitelabel image" if json_response['success'] == true
358
+ end
359
+ rescue RestClient::Exception => e
360
+ print_rest_exception(e, options)
361
+ exit 1
362
+ end
363
+ end
364
+
365
+ def reset_image(args)
366
+ options = {}
367
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
368
+ opts.banner = opts.banner = subcommand_usage("[image-type]")
369
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
370
+ opts.footer = "Reset your whitelabel image.\n" +
371
+ "[image-type] is required. This is the whitelabel image type (#{@image_types.collect {|k,v| k}.join('|')})"
372
+ end
373
+
374
+ optparse.parse!(args)
375
+ connect(options)
376
+
377
+ if args.count != 1
378
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
379
+ return 1
380
+ end
381
+ if !@image_types[args[0]]
382
+ raise_command_error "Invalid image type specified: #{args[0]}. Must be one of the following (#{@image_types.collect {|k,v| k}.join('|')})"
383
+ return 1
384
+ end
385
+
386
+ begin
387
+ image_type = @image_types[args[0]]
388
+ @whitelabel_settings_interface.setopts(options)
389
+ if options[:dry_run]
390
+ print_dry_run @whitelabel_settings_interface.dry.reset_image(image_type)
391
+ return
392
+ end
393
+
394
+ json_response = @whitelabel_settings_interface.reset_image(image_type)
395
+
396
+ if options[:json]
397
+ puts as_json(json_response, options)
398
+ elsif !options[:quiet]
399
+ print_red_alert "Error resetting whitelabel image: #{json_response['msg'] || json_response['errors']}" if json_response['success'] == false
400
+ print_green_success "Reset whitelabel image" if json_response['success'] == true
401
+ end
402
+ rescue RestClient::Exception => e
403
+ print_rest_exception(e, options)
404
+ exit 1
405
+ end
406
+ end
407
+
408
+ def view_image(args)
409
+ options = {}
410
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
411
+ opts.banner = opts.banner = subcommand_usage("[image-type]")
412
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
413
+ opts.footer = "View your image of specified [image-type].\n" +
414
+ "[image-type] is required. This is the whitelabel image type (#{@image_types.collect {|k,v| k}.join('|')})\n" +
415
+ "This opens the image url with a web browser."
416
+ end
417
+
418
+ optparse.parse!(args)
419
+ connect(options)
420
+
421
+ if args.count != 1
422
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
423
+ return 1
424
+ end
425
+ if !@image_types[args[0]]
426
+ raise_command_error "Invalid image type specified: #{args[0]}. Must be one of the following (#{@image_types.collect {|k,v| k}.join('|')})"
427
+ return 1
428
+ end
429
+
430
+ begin
431
+ image_type = @image_types[args[0]]
432
+ @whitelabel_settings_interface.setopts(options)
433
+ if options[:dry_run]
434
+ print_dry_run @whitelabel_settings_interface.dry.get()
435
+ return
436
+ end
437
+
438
+ whitelabel_settings = @whitelabel_settings_interface.get()['whitelabelSettings']
439
+
440
+ if link = whitelabel_settings[image_type]
441
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
442
+ system "start #{link}"
443
+ elsif RbConfig::CONFIG['host_os'] =~ /darwin/
444
+ system "open #{link}"
445
+ elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
446
+ system "xdg-open #{link}"
447
+ end
448
+ return 0, nil
449
+ else
450
+ print_error red,"No image found for #{image_type}.",reset,"\n"
451
+ return 1
452
+ end
453
+ rescue RestClient::Exception => e
454
+ print_rest_exception(e, options)
455
+ return 1
456
+ end
457
+ end
458
+
459
+ def download_image(args)
460
+ options = {}
461
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
462
+ opts.banner = opts.banner = subcommand_usage("[image-type] [local-file]")
463
+ opts.on( '-f', '--force', "Overwrite existing [local-file] if it exists." ) do
464
+ options[:overwrite] = true
465
+ end
466
+ opts.on( '-p', '--mkdir', "Create missing directories for [local-file] if they do not exist." ) do
467
+ options[:mkdir] = true
468
+ end
469
+ build_common_options(opts, options, [:dry_run, :quiet, :remote])
470
+ opts.footer = "Download an image file.\n" +
471
+ "[image-type] is required. This is the whitelabel image type (#{@image_types.collect {|k,v| k}.join('|')}) to be downloaded.\n" +
472
+ "[local-file] is required. This is the full local filepath for the downloaded file."
473
+ end
474
+
475
+ optparse.parse!(args)
476
+ connect(options)
477
+
478
+ if args.count != 2
479
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
480
+ return 1
481
+ end
482
+ if !@image_types[args[0]]
483
+ raise_command_error "Invalid image type specified: #{args[0]}. Must be one of the following (#{@image_types.collect {|k,v| k}.join('|')})"
484
+ return 1
485
+ end
486
+
487
+ begin
488
+ image_type = @image_types[args[0]]
489
+ outfile = File.expand_path(args[1])
490
+ outdir = File.dirname(outfile)
491
+
492
+ if Dir.exists?(outfile)
493
+ print_red_alert "[local-file] is invalid. It is the name of an existing directory: #{outfile}"
494
+ return 1
495
+ end
496
+ if !Dir.exists?(outdir)
497
+ if options[:mkdir]
498
+ print cyan,"Creating local directory #{outdir}",reset,"\n"
499
+ FileUtils.mkdir_p(outdir)
500
+ else
501
+ print_red_alert "[local-file] is invalid. Directory not found: #{outdir}"
502
+ return 1
503
+ end
504
+ end
505
+ if File.exists?(outfile) && !options[:overwrite]
506
+ print_red_alert "[local-file] is invalid. File already exists: #{outfile}\nUse -f to overwrite the existing file."
507
+ return 1
508
+ end
509
+
510
+ @whitelabel_settings_interface.setopts(options)
511
+ if options[:dry_run]
512
+ print_dry_run @whitelabel_settings_interface.dry.download_image(image_type, outfile)
513
+ return
514
+ end
515
+
516
+ if !options[:quite]
517
+ print cyan + "Downloading #{args[0]} to #{outfile} ... "
518
+ end
519
+
520
+ http_response = @whitelabel_settings_interface.download_image(image_type, outfile)
521
+
522
+ success = http_response.code.to_i == 200
523
+ if success
524
+ if !options[:quiet]
525
+ print green + "SUCCESS" + reset + "\n"
526
+ end
527
+ return 0
528
+ else
529
+ if !options[:quiet]
530
+ print red + "ERROR" + reset + " HTTP #{http_response.code}" + "\n"
531
+ end
532
+ if File.exists?(outfile) && File.file?(outfile)
533
+ Morpheus::Logging::DarkPrinter.puts "Deleting bad file download: #{outfile}" if Morpheus::Logging.debug?
534
+ File.delete(outfile)
535
+ end
536
+ if options[:debug]
537
+ puts_error http_response.inspect
538
+ end
539
+ return 1
540
+ end
541
+ rescue RestClient::Exception => e
542
+ print_rest_exception(e, options)
543
+ return 1
544
+ end
545
+ end
546
+ end