morpheus-cli 5.5.2.2 → 5.5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Dockerfile +1 -1
  4. data/README.md +57 -4
  5. data/Rakefile +9 -0
  6. data/bin/morpheus +4 -4
  7. data/lib/morpheus/api/api_client.rb +20 -2
  8. data/lib/morpheus/api/appliance_settings_interface.rb +15 -0
  9. data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
  10. data/lib/morpheus/api/archive_files_interface.rb +3 -3
  11. data/lib/morpheus/api/clients_interface.rb +2 -2
  12. data/lib/morpheus/api/clusters_interface.rb +8 -1
  13. data/lib/morpheus/api/containers_interface.rb +29 -16
  14. data/lib/morpheus/api/custom_instance_types_interface.rb +0 -2
  15. data/lib/morpheus/api/cypher_interface.rb +1 -2
  16. data/lib/morpheus/api/doc_interface.rb +8 -6
  17. data/lib/morpheus/api/file_copy_request_interface.rb +1 -1
  18. data/lib/morpheus/api/guidance_settings_interface.rb +17 -0
  19. data/lib/morpheus/api/health_interface.rb +1 -1
  20. data/lib/morpheus/api/image_builder_interface.rb +3 -3
  21. data/lib/morpheus/api/instances_interface.rb +25 -0
  22. data/lib/morpheus/api/logs_interface.rb +2 -4
  23. data/lib/morpheus/api/monitoring_interface.rb +6 -6
  24. data/lib/morpheus/api/monitoring_settings_interface.rb +25 -0
  25. data/lib/morpheus/api/network_server_groups_interface.rb +7 -0
  26. data/lib/morpheus/api/packages_interface.rb +1 -1
  27. data/lib/morpheus/api/reports_interface.rb +1 -1
  28. data/lib/morpheus/api/servers_interface.rb +9 -1
  29. data/lib/morpheus/api/storage_providers_interface.rb +2 -2
  30. data/lib/morpheus/api/virtual_images_interface.rb +1 -1
  31. data/lib/morpheus/api.rb +2 -0
  32. data/lib/morpheus/benchmarking.rb +1 -1
  33. data/lib/morpheus/cli/cli_command.rb +79 -37
  34. data/lib/morpheus/cli/cli_registry.rb +19 -10
  35. data/lib/morpheus/cli/commands/access_token_command.rb +1 -1
  36. data/lib/morpheus/cli/commands/appliance_settings_command.rb +57 -2
  37. data/lib/morpheus/cli/commands/apps.rb +1 -1
  38. data/lib/morpheus/cli/commands/archives_command.rb +25 -33
  39. data/lib/morpheus/cli/commands/backup_settings_command.rb +1 -1
  40. data/lib/morpheus/cli/commands/blueprints_command.rb +10 -21
  41. data/lib/morpheus/cli/commands/boot_scripts_command.rb +2 -2
  42. data/lib/morpheus/cli/commands/cat_command.rb +1 -1
  43. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +18 -13
  44. data/lib/morpheus/cli/commands/clouds.rb +3 -3
  45. data/lib/morpheus/cli/commands/clusters.rb +154 -3
  46. data/lib/morpheus/cli/commands/containers_command.rb +398 -253
  47. data/lib/morpheus/cli/commands/cypher_command.rb +3 -0
  48. data/lib/morpheus/cli/commands/deployments.rb +1 -1
  49. data/lib/morpheus/cli/commands/deploys.rb +9 -9
  50. data/lib/morpheus/cli/commands/doc.rb +15 -16
  51. data/lib/morpheus/cli/commands/execution_request_command.rb +2 -2
  52. data/lib/morpheus/cli/commands/file_copy_request_command.rb +5 -5
  53. data/lib/morpheus/cli/commands/groups.rb +2 -2
  54. data/lib/morpheus/cli/commands/guidance_command.rb +2 -2
  55. data/lib/morpheus/cli/commands/guidance_settings.rb +148 -0
  56. data/lib/morpheus/cli/commands/health_command.rb +4 -4
  57. data/lib/morpheus/cli/commands/hosts.rb +43 -5
  58. data/lib/morpheus/cli/commands/image_builder_command.rb +1 -1
  59. data/lib/morpheus/cli/commands/instances.rb +419 -148
  60. data/lib/morpheus/cli/commands/integrations_command.rb +22 -20
  61. data/lib/morpheus/cli/commands/key_pairs.rb +2 -2
  62. data/lib/morpheus/cli/commands/library_container_scripts_command.rb +2 -2
  63. data/lib/morpheus/cli/commands/library_container_templates_command.rb +2 -2
  64. data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -3
  65. data/lib/morpheus/cli/commands/library_spec_templates_command.rb +2 -2
  66. data/lib/morpheus/cli/commands/log_settings_command.rb +1 -1
  67. data/lib/morpheus/cli/commands/login.rb +1 -1
  68. data/lib/morpheus/cli/commands/man_command.rb +32 -18
  69. data/lib/morpheus/cli/commands/monitoring_settings.rb +228 -0
  70. data/lib/morpheus/cli/commands/network_server_groups_command.rb +222 -0
  71. data/lib/morpheus/cli/commands/packages_command.rb +11 -11
  72. data/lib/morpheus/cli/commands/plugins.rb +1 -1
  73. data/lib/morpheus/cli/commands/policies_command.rb +4 -4
  74. data/lib/morpheus/cli/commands/preseed_scripts_command.rb +2 -2
  75. data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -1
  76. data/lib/morpheus/cli/commands/remote.rb +1 -1
  77. data/lib/morpheus/cli/commands/reports_command.rb +13 -3
  78. data/lib/morpheus/cli/commands/security_groups.rb +1 -1
  79. data/lib/morpheus/cli/commands/shell.rb +40 -62
  80. data/lib/morpheus/cli/commands/snapshots.rb +3 -5
  81. data/lib/morpheus/cli/commands/source_command.rb +8 -16
  82. data/lib/morpheus/cli/commands/storage_providers_command.rb +7 -7
  83. data/lib/morpheus/cli/commands/tasks.rb +2 -2
  84. data/lib/morpheus/cli/commands/vdi_pools_command.rb +6 -6
  85. data/lib/morpheus/cli/commands/view.rb +5 -1
  86. data/lib/morpheus/cli/commands/whitelabel_settings_command.rb +5 -5
  87. data/lib/morpheus/cli/commands/whoami.rb +2 -2
  88. data/lib/morpheus/cli/credentials.rb +30 -8
  89. data/lib/morpheus/cli/dot_file.rb +8 -15
  90. data/lib/morpheus/cli/error_handler.rb +16 -0
  91. data/lib/morpheus/cli/errors.rb +8 -1
  92. data/lib/morpheus/cli/mixins/print_helper.rb +17 -13
  93. data/lib/morpheus/cli/mixins/provisioning_helper.rb +14 -12
  94. data/lib/morpheus/cli/mixins/rest_command.rb +23 -19
  95. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +47 -24
  96. data/lib/morpheus/cli/option_parser.rb +5 -1
  97. data/lib/morpheus/cli/option_types.rb +59 -12
  98. data/lib/morpheus/cli/version.rb +1 -1
  99. data/lib/morpheus/cli.rb +26 -16
  100. data/lib/morpheus/ext/rest_client.rb +3 -2
  101. data/lib/morpheus/ext/string.rb +6 -4
  102. data/lib/morpheus/formatters.rb +1 -1
  103. data/lib/morpheus/logging.rb +4 -4
  104. data/lib/morpheus/morpkg.rb +4 -4
  105. data/lib/morpheus/rest_client.rb +2 -2
  106. data/lib/morpheus/routes.rb +41 -9
  107. data/lib/morpheus/terminal.rb +65 -16
  108. data/lib/morpheus.rb +1 -1
  109. data/morpheus-cli.gemspec +1 -0
  110. data/test/api/containers_interface_test.rb +68 -0
  111. data/test/api/doc_interface_test.rb +35 -0
  112. data/test/api/instances_interface_test.rb +22 -0
  113. data/test/api/whoami_interface_test.rb +14 -0
  114. data/test/cli/access_token_test.rb +36 -0
  115. data/test/cli/auth_test.rb +82 -0
  116. data/test/cli/cli_test.rb +48 -0
  117. data/test/cli/containers_test.rb +92 -0
  118. data/test/cli/doc_test.rb +35 -0
  119. data/test/cli/help_test.rb +25 -0
  120. data/test/cli/instances_test.rb +36 -0
  121. data/test/cli/man_test.rb +14 -0
  122. data/test/cli/remote_test.rb +89 -0
  123. data/test/cli/roles_test.rb +34 -0
  124. data/test/cli/shell_test.rb +81 -0
  125. data/test/cli/version_test.rb +23 -0
  126. data/test/cli/view_test.rb +55 -0
  127. data/test/cli/whoami_test.rb +17 -0
  128. data/test/morpheus_test.rb +16 -0
  129. data/test/test_case.rb +338 -0
  130. data/test/test_config.rb +137 -0
  131. data/test/test_data_helper.rb +97 -0
  132. metadata +67 -3
@@ -23,6 +23,7 @@ class Morpheus::Cli::Clusters
23
23
  register_subcommands :update_permissions
24
24
  register_subcommands :api_config, :view_api_token, :view_kube_config
25
25
  register_subcommands :wiki, :update_wiki
26
+ register_subcommands :apply_template
26
27
 
27
28
  def connect(opts)
28
29
  @api_client = establish_remote_appliance_connection(opts)
@@ -42,6 +43,7 @@ class Morpheus::Cli::Clusters
42
43
  @user_groups_interface = @api_client.user_groups
43
44
  @accounts_interface = @api_client.accounts
44
45
  @logs_interface = @api_client.logs
46
+ @execution_request_interface = @api_client.execution_request
45
47
  #@active_security_group = ::Morpheus::Cli::SecurityGroups.load_security_group_file
46
48
  end
47
49
 
@@ -3242,7 +3244,7 @@ class Morpheus::Cli::Clusters
3242
3244
  build_option_type_options(opts, options, update_wiki_page_option_types)
3243
3245
  opts.on('--file FILE', "File containing the wiki content. This can be used instead of --content") do |filename|
3244
3246
  full_filename = File.expand_path(filename)
3245
- if File.exists?(full_filename)
3247
+ if File.exist?(full_filename)
3246
3248
  params['content'] = File.read(full_filename)
3247
3249
  else
3248
3250
  print_red_alert "File not found: #{full_filename}"
@@ -3562,6 +3564,125 @@ class Morpheus::Cli::Clusters
3562
3564
  end
3563
3565
  end
3564
3566
 
3567
+ def apply_template(args)
3568
+ options = {}
3569
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
3570
+ opts.banner = subcommand_usage( "[cluster] --specTemplate --serviceUrl")
3571
+ opts.on("--specTemplate [TEXT]", String, "Name or ID of desired Spec Template to apply to cluster") do |val|
3572
+ options[:specTemplate] = val.to_s
3573
+ end
3574
+ opts.on("--serviceUrl [TEXT]", String, "Url of template to apply to Cluster") do |val|
3575
+ options[:serviceUrl] = val.to_s
3576
+ end
3577
+ opts.on("--specYaml [TEXT]", String, "Yaml to apply to Cluster") do |val|
3578
+ options[:specYaml] = val.to_s
3579
+ end
3580
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
3581
+ opts.footer = "Apply a Template to a Cluster.\n" +
3582
+ "[cluster] is required. This is the name or id of an existing cluster."
3583
+ end
3584
+
3585
+ optparse.parse!(args)
3586
+ if args.count != 1
3587
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
3588
+ end
3589
+ connect(options)
3590
+
3591
+ begin
3592
+ payload = nil
3593
+ cluster = nil
3594
+
3595
+ if options[:payload]
3596
+ payload = options[:payload]
3597
+ # support -O OPTION switch on top of --payload
3598
+ if options[:options]
3599
+ payload['cluster'] ||= {}
3600
+ payload['cluster'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
3601
+ end
3602
+
3603
+ if !payload['cluster'].empty?
3604
+ cluster = find_cluster_by_name_or_id(payload['cluster']['id'] || payload['cluster']['name'])
3605
+ end
3606
+ else
3607
+ cluster = find_cluster_by_name_or_id(args[0])
3608
+ cluster_payload = {}
3609
+ cluster_payload['specTemplate'] = options[:specTemplate] if !options[:specTemplate].empty?
3610
+ cluster_payload['serviceUrl'] = options[:serviceUrl] if !options[:serviceUrl].empty?
3611
+ cluster_payload['specYaml'] = options[:specYaml] if !options[:specYaml].empty?
3612
+ payload = cluster_payload
3613
+ end
3614
+
3615
+ if !cluster
3616
+ print_red_alert "No clusters available for update"
3617
+ exit 1
3618
+ end
3619
+
3620
+ if cluster_payload.empty?
3621
+ type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => "Type", 'selectOptions' => apply_temp_options, 'required' => true, 'description' => 'Choose type of template being used.'}])['type']
3622
+ if type == 'specTemplate'
3623
+ cluster_payload['specTemplate'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'specTemplate', 'type' => 'select', 'fieldLabel' => "Spec Template", 'selectOptions' => available_kube_templates, 'required' => true, 'description' => 'Choose a template.'}], options[:options])['specTemplate']
3624
+ elsif type == 'yaml'
3625
+ file_params = Morpheus::Cli::OptionTypes.file_content_prompt({'fieldName' => 'source', 'fieldLabel' => 'File Content', 'type' => 'file-content', 'required' => true}, {'source' => {'source' => 'local'}}, nil, {})
3626
+ cluster_payload['specYaml'] = file_params['content']
3627
+ else
3628
+ cluster_payload['specUrl'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'specUrl', 'type' => 'text', 'fieldLabel' => 'Spec Url', 'required' => true, 'description' => 'Url of template.'}])['specUrl']
3629
+ end
3630
+ end
3631
+
3632
+ if options[:dry_run]
3633
+ print_dry_run @clusters_interface.dry.apply_template(cluster['id'], cluster_payload)
3634
+ return
3635
+ end
3636
+
3637
+ json_response = @clusters_interface.apply_template(cluster['id'], cluster_payload)
3638
+ if options[:json]
3639
+ print JSON.pretty_generate(json_response)
3640
+ print "\n"
3641
+ elsif json_response['msg'] != nil
3642
+ print_red_alert "There was an error #{json_response['msg']}"
3643
+ else
3644
+ print_green_success 'Template applied to Cluster. Check Execution Request for results'
3645
+ json_response = @execution_request_interface.get(json_response['executionId'], {})
3646
+
3647
+ if json_response['executionRequest'] && json_response['executionRequest']['errorMessage']
3648
+ print_red_alert "There was an error: #{json_response['executionRequest']['errorMessage']}"
3649
+ print_red_alert "execution request id: #{json_response['executionRequest']['uniqueId']}"
3650
+ else
3651
+ execution_request = json_response['executionRequest']
3652
+ print_h1 "Execution Request Details"
3653
+ print cyan
3654
+ description_cols = {
3655
+ #"ID" => lambda {|it| it['id'] },
3656
+ "Unique ID" => lambda {|it| it['uniqueId'] },
3657
+ "Server ID" => lambda {|it| it['serverId'] },
3658
+ "Instance ID" => lambda {|it| it['instanceId'] },
3659
+ "Container ID" => lambda {|it| it['containerId'] },
3660
+ "Expires At" => lambda {|it| format_local_dt it['expiresAt'] },
3661
+ "Exit Code" => lambda {|it| it['exitCode'] },
3662
+ "Status" => lambda {|it| format_execution_request_status(it) },
3663
+ #"Created By" => lambda {|it| it['createdById'] },
3664
+ #"Subdomain" => lambda {|it| it['subdomain'] },
3665
+ }
3666
+ description_cols.delete("Server ID") if execution_request['serverId'].nil?
3667
+ description_cols.delete("Instance ID") if execution_request['instanceId'].nil?
3668
+ description_cols.delete("Container ID") if execution_request['containerId'].nil?
3669
+ description_cols.delete("Exit Code") if execution_request['exitCode'].nil?
3670
+ print_description_list(description_cols, execution_request)
3671
+
3672
+ if execution_request['stdErr'].to_s.strip != '' && execution_request['stdErr'] != "stdin: is not a tty\n"
3673
+ print_h2 "Error"
3674
+ puts execution_request['stdErr'].to_s.strip
3675
+ end
3676
+ if execution_request['stdOut']
3677
+ print_h2 "Output"
3678
+ puts execution_request['stdOut'].to_s.strip
3679
+ end
3680
+ print reset, "\n"
3681
+ end
3682
+ end
3683
+ end
3684
+ end
3685
+
3565
3686
  def history_event_details(args)
3566
3687
  options = {}
3567
3688
  process_event_id = nil
@@ -4057,7 +4178,7 @@ class Morpheus::Cli::Clusters
4057
4178
  end
4058
4179
  opts.on('--volumes-file FILE', String, "Volumes Config from a local JSON or YAML file") do |val|
4059
4180
  config_file = File.expand_path(val)
4060
- if !File.exists?(config_file) || !File.file?(config_file)
4181
+ if !File.exist?(config_file) || !File.file?(config_file)
4061
4182
  print_red_alert "Specified volumes file not found: #{config_file}"
4062
4183
  exit 1
4063
4184
  end
@@ -4093,7 +4214,7 @@ class Morpheus::Cli::Clusters
4093
4214
  end
4094
4215
  opts.on('--network-interfaces-file FILE', String, "Network Interfaces Config from a local JSON or YAML file") do |val|
4095
4216
  config_file = File.expand_path(val)
4096
- if !File.exists?(config_file) || !File.file?(config_file)
4217
+ if !File.exist?(config_file) || !File.file?(config_file)
4097
4218
  print_red_alert "Specified network interfaces file not found: #{config_file}"
4098
4219
  exit 1
4099
4220
  end
@@ -4235,4 +4356,34 @@ class Morpheus::Cli::Clusters
4235
4356
  it
4236
4357
  end
4237
4358
  end
4359
+
4360
+ def available_kube_templates
4361
+ option_results = options_interface.options_for_source('availableKubeTemplates')
4362
+ available_templates = option_results['data'].collect {|it|
4363
+ {"id" => it["value"], "name" => it["name"], "value" => it["value"]}
4364
+ }
4365
+
4366
+ return available_templates
4367
+ end
4368
+
4369
+ def apply_temp_options
4370
+ [
4371
+ {"id" => "specYaml", "name" => "YAML", "value" => "yaml"},
4372
+ {"id" => 'specTemplate', "name" => "Spec Template", "value" => 'specTemplate'},
4373
+ {"id" => 'url', "name" => 'Url of Template', "value" => 'url'}
4374
+ ]
4375
+ end
4376
+
4377
+ def format_execution_request_status(execution_request, return_color=cyan)
4378
+ out = ""
4379
+ status_str = execution_request['status']
4380
+ if status_str == 'complete'
4381
+ out << "#{green}#{status_str.upcase}#{return_color}"
4382
+ elsif status_str == 'failed' || status_str == 'expired'
4383
+ out << "#{red}#{status_str.upcase}#{return_color}"
4384
+ else
4385
+ out << "#{cyan}#{status_str.upcase}#{return_color}"
4386
+ end
4387
+ out
4388
+ end
4238
4389
  end