morpheus-cli 5.5.2.2 → 5.5.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|