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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Dockerfile +1 -1
- data/README.md +57 -4
- data/Rakefile +9 -0
- data/bin/morpheus +4 -4
- data/lib/morpheus/api/api_client.rb +20 -2
- data/lib/morpheus/api/appliance_settings_interface.rb +15 -0
- data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
- data/lib/morpheus/api/archive_files_interface.rb +3 -3
- data/lib/morpheus/api/clients_interface.rb +2 -2
- data/lib/morpheus/api/clusters_interface.rb +8 -1
- data/lib/morpheus/api/containers_interface.rb +29 -16
- data/lib/morpheus/api/custom_instance_types_interface.rb +0 -2
- data/lib/morpheus/api/cypher_interface.rb +1 -2
- data/lib/morpheus/api/doc_interface.rb +8 -6
- data/lib/morpheus/api/file_copy_request_interface.rb +1 -1
- data/lib/morpheus/api/guidance_settings_interface.rb +17 -0
- data/lib/morpheus/api/health_interface.rb +1 -1
- data/lib/morpheus/api/image_builder_interface.rb +3 -3
- data/lib/morpheus/api/instances_interface.rb +25 -0
- data/lib/morpheus/api/logs_interface.rb +2 -4
- data/lib/morpheus/api/monitoring_interface.rb +6 -6
- data/lib/morpheus/api/monitoring_settings_interface.rb +25 -0
- data/lib/morpheus/api/network_server_groups_interface.rb +7 -0
- data/lib/morpheus/api/packages_interface.rb +1 -1
- data/lib/morpheus/api/reports_interface.rb +1 -1
- data/lib/morpheus/api/servers_interface.rb +9 -1
- data/lib/morpheus/api/storage_providers_interface.rb +2 -2
- data/lib/morpheus/api/virtual_images_interface.rb +1 -1
- data/lib/morpheus/api.rb +2 -0
- data/lib/morpheus/benchmarking.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +79 -37
- data/lib/morpheus/cli/cli_registry.rb +19 -10
- data/lib/morpheus/cli/commands/access_token_command.rb +1 -1
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +57 -2
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/archives_command.rb +25 -33
- data/lib/morpheus/cli/commands/backup_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/blueprints_command.rb +10 -21
- data/lib/morpheus/cli/commands/boot_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/cat_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +18 -13
- data/lib/morpheus/cli/commands/clouds.rb +3 -3
- data/lib/morpheus/cli/commands/clusters.rb +154 -3
- data/lib/morpheus/cli/commands/containers_command.rb +398 -253
- data/lib/morpheus/cli/commands/cypher_command.rb +3 -0
- data/lib/morpheus/cli/commands/deployments.rb +1 -1
- data/lib/morpheus/cli/commands/deploys.rb +9 -9
- data/lib/morpheus/cli/commands/doc.rb +15 -16
- data/lib/morpheus/cli/commands/execution_request_command.rb +2 -2
- data/lib/morpheus/cli/commands/file_copy_request_command.rb +5 -5
- data/lib/morpheus/cli/commands/groups.rb +2 -2
- data/lib/morpheus/cli/commands/guidance_command.rb +2 -2
- data/lib/morpheus/cli/commands/guidance_settings.rb +148 -0
- data/lib/morpheus/cli/commands/health_command.rb +4 -4
- data/lib/morpheus/cli/commands/hosts.rb +43 -5
- data/lib/morpheus/cli/commands/image_builder_command.rb +1 -1
- data/lib/morpheus/cli/commands/instances.rb +419 -148
- data/lib/morpheus/cli/commands/integrations_command.rb +22 -20
- data/lib/morpheus/cli/commands/key_pairs.rb +2 -2
- data/lib/morpheus/cli/commands/library_container_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/library_container_templates_command.rb +2 -2
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -3
- data/lib/morpheus/cli/commands/library_spec_templates_command.rb +2 -2
- data/lib/morpheus/cli/commands/log_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/login.rb +1 -1
- data/lib/morpheus/cli/commands/man_command.rb +32 -18
- data/lib/morpheus/cli/commands/monitoring_settings.rb +228 -0
- data/lib/morpheus/cli/commands/network_server_groups_command.rb +222 -0
- data/lib/morpheus/cli/commands/packages_command.rb +11 -11
- data/lib/morpheus/cli/commands/plugins.rb +1 -1
- data/lib/morpheus/cli/commands/policies_command.rb +4 -4
- data/lib/morpheus/cli/commands/preseed_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/remote.rb +1 -1
- data/lib/morpheus/cli/commands/reports_command.rb +13 -3
- data/lib/morpheus/cli/commands/security_groups.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +40 -62
- data/lib/morpheus/cli/commands/snapshots.rb +3 -5
- data/lib/morpheus/cli/commands/source_command.rb +8 -16
- data/lib/morpheus/cli/commands/storage_providers_command.rb +7 -7
- data/lib/morpheus/cli/commands/tasks.rb +2 -2
- data/lib/morpheus/cli/commands/vdi_pools_command.rb +6 -6
- data/lib/morpheus/cli/commands/view.rb +5 -1
- data/lib/morpheus/cli/commands/whitelabel_settings_command.rb +5 -5
- data/lib/morpheus/cli/commands/whoami.rb +2 -2
- data/lib/morpheus/cli/credentials.rb +30 -8
- data/lib/morpheus/cli/dot_file.rb +8 -15
- data/lib/morpheus/cli/error_handler.rb +16 -0
- data/lib/morpheus/cli/errors.rb +8 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +17 -13
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +14 -12
- data/lib/morpheus/cli/mixins/rest_command.rb +23 -19
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +47 -24
- data/lib/morpheus/cli/option_parser.rb +5 -1
- data/lib/morpheus/cli/option_types.rb +59 -12
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli.rb +26 -16
- data/lib/morpheus/ext/rest_client.rb +3 -2
- data/lib/morpheus/ext/string.rb +6 -4
- data/lib/morpheus/formatters.rb +1 -1
- data/lib/morpheus/logging.rb +4 -4
- data/lib/morpheus/morpkg.rb +4 -4
- data/lib/morpheus/rest_client.rb +2 -2
- data/lib/morpheus/routes.rb +41 -9
- data/lib/morpheus/terminal.rb +65 -16
- data/lib/morpheus.rb +1 -1
- data/morpheus-cli.gemspec +1 -0
- data/test/api/containers_interface_test.rb +68 -0
- data/test/api/doc_interface_test.rb +35 -0
- data/test/api/instances_interface_test.rb +22 -0
- data/test/api/whoami_interface_test.rb +14 -0
- data/test/cli/access_token_test.rb +36 -0
- data/test/cli/auth_test.rb +82 -0
- data/test/cli/cli_test.rb +48 -0
- data/test/cli/containers_test.rb +92 -0
- data/test/cli/doc_test.rb +35 -0
- data/test/cli/help_test.rb +25 -0
- data/test/cli/instances_test.rb +36 -0
- data/test/cli/man_test.rb +14 -0
- data/test/cli/remote_test.rb +89 -0
- data/test/cli/roles_test.rb +34 -0
- data/test/cli/shell_test.rb +81 -0
- data/test/cli/version_test.rb +23 -0
- data/test/cli/view_test.rb +55 -0
- data/test/cli/whoami_test.rb +17 -0
- data/test/morpheus_test.rb +16 -0
- data/test/test_case.rb +338 -0
- data/test/test_config.rb +137 -0
- data/test/test_data_helper.rb +97 -0
- 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.
|
|
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.
|
|
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.
|
|
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
|