morpheus-cli 6.2.3 → 6.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/README.md +4 -1
- data/lib/morpheus/api/api_client.rb +8 -0
- data/lib/morpheus/api/library_cluster_packages_interface.rb +41 -0
- data/lib/morpheus/api/option_type_forms_interface.rb +9 -0
- data/lib/morpheus/cli/cli_command.rb +3 -1
- data/lib/morpheus/cli/cli_registry.rb +2 -4
- data/lib/morpheus/cli/commands/backups_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +54 -12
- data/lib/morpheus/cli/commands/certificates_command.rb +1 -1
- data/lib/morpheus/cli/commands/clusters.rb +1 -2
- data/lib/morpheus/cli/commands/library_cluster_packages_command.rb +485 -0
- data/lib/morpheus/cli/commands/library_forms_command.rb +625 -0
- data/lib/morpheus/cli/commands/network_servers_command.rb +19 -9
- data/lib/morpheus/cli/commands/policies_command.rb +112 -128
- data/lib/morpheus/cli/commands/roles.rb +3 -0
- data/lib/morpheus/cli/commands/self_service_command.rb +17 -0
- data/lib/morpheus/cli/commands/service_catalog_command.rb +70 -30
- data/lib/morpheus/cli/commands/virtual_images.rb +1 -1
- data/lib/morpheus/cli/error_handler.rb +18 -3
- data/lib/morpheus/cli/mixins/accounts_helper.rb +2 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +20 -6
- data/lib/morpheus/cli/mixins/prompt_helper.rb +132 -11
- data/lib/morpheus/cli/option_types.rb +104 -7
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/routes.rb +9 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8acef874a37276edc6d53f64e243ca01c0e0d30e49dea166502058da2f01350d
|
4
|
+
data.tar.gz: f0f9022abbb5b04c526cf992c95cacee2927ce5fb2e27027b19dc624abe454be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab4f224e431ff217ea24591b385d76f1a6370626770e8eb9f8ae8291c6d6681e3a29c58c6c220fea85510819da0df901e3816e37f4937ad2b04c4322a5eae0b2
|
7
|
+
data.tar.gz: 27976146b5f086f41968860c7eb210fdbc7cf8ac6667b55e1318e88f9fae938c33699b05a14a1cdba91bfcde0635b01113bc61c3c1e21ade5e2a7bea719cee66
|
data/Dockerfile
CHANGED
data/README.md
CHANGED
@@ -55,7 +55,7 @@ New CLI commands get added under the library directory: `lib/morpheus/cli/comman
|
|
55
55
|
While developing, you can quickly reload your code changes in a morpheus shell while developing:
|
56
56
|
|
57
57
|
```shell
|
58
|
-
morpheus shell
|
58
|
+
bundle exec morpheus shell —debug
|
59
59
|
```
|
60
60
|
|
61
61
|
Then to reload changes without restarting the morpheus shell (and the ruby process), use:
|
@@ -66,6 +66,9 @@ reload
|
|
66
66
|
|
67
67
|
Don't forget to add unit tests for your new commands under the directory: `test/`.
|
68
68
|
|
69
|
+
|
70
|
+
|
71
|
+
|
69
72
|
## Testing
|
70
73
|
|
71
74
|
To run the CLI unit tests, first create a `test_config.yaml` and then run `rake test`.
|
@@ -600,6 +600,10 @@ class Morpheus::APIClient
|
|
600
600
|
Morpheus::OptionTypeListsInterface.new(common_interface_options).setopts(@options)
|
601
601
|
end
|
602
602
|
|
603
|
+
def option_type_forms
|
604
|
+
Morpheus::OptionTypeFormsInterface.new(common_interface_options).setopts(@options)
|
605
|
+
end
|
606
|
+
|
603
607
|
def scale_thresholds
|
604
608
|
Morpheus::ScaleThresholdsInterface.new(common_interface_options).setopts(@options)
|
605
609
|
end
|
@@ -766,6 +770,10 @@ class Morpheus::APIClient
|
|
766
770
|
Morpheus::LibraryClusterLayoutsInterface.new(common_interface_options).setopts(@options)
|
767
771
|
end
|
768
772
|
|
773
|
+
def library_cluster_packages
|
774
|
+
Morpheus::LibraryClusterPackagesInterface.new(common_interface_options).setopts(@options)
|
775
|
+
end
|
776
|
+
|
769
777
|
def library_spec_templates
|
770
778
|
Morpheus::LibrarySpecTemplatesInterface.new(common_interface_options).setopts(@options)
|
771
779
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::LibraryClusterPackagesInterface < Morpheus::APIClient
|
4
|
+
|
5
|
+
def list(params={})
|
6
|
+
url = "#{@base_url}/api/library/cluster-packages"
|
7
|
+
params['sort'] = 'name'
|
8
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
9
|
+
opts = {method: :get, url: url, headers: headers}
|
10
|
+
execute(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(id, params={})
|
14
|
+
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
15
|
+
url = "#{@base_url}/api/library/cluster-packages/#{id}"
|
16
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
17
|
+
opts = {method: :get, url: url, headers: headers}
|
18
|
+
execute(opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
def create(payload)
|
22
|
+
url = "#{@base_url}/api/library/cluster-packages"
|
23
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
24
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
25
|
+
execute(opts)
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(id, payload)
|
29
|
+
url = "#{@base_url}/api/library/cluster-packages/#{id}"
|
30
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
31
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
32
|
+
execute(opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy(id, payload={})
|
36
|
+
url = "#{@base_url}/api/library/cluster-packages/#{id}"
|
37
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
38
|
+
opts = {method: :delete, url: url, headers: headers, payload: payload.to_json}
|
39
|
+
execute(opts)
|
40
|
+
end
|
41
|
+
end
|
@@ -268,7 +268,6 @@ module Morpheus
|
|
268
268
|
build_standard_post_options(opts, options, includes, excludes)
|
269
269
|
end
|
270
270
|
|
271
|
-
# todo: this can go away once every command is using execute_api()
|
272
271
|
def build_standard_add_many_options(opts, options, includes=[], excludes=[])
|
273
272
|
build_standard_post_options(opts, options, includes + [:payloads], excludes)
|
274
273
|
end
|
@@ -1579,6 +1578,9 @@ module Morpheus
|
|
1579
1578
|
# could use parse_passed_options() here to support exclusion of certain options
|
1580
1579
|
#passed_options = parse_passed_options(options, options[:apply_options] || {})
|
1581
1580
|
passed_options = options[:options].reject {|k,v| k.is_a?(Symbol)}
|
1581
|
+
if options[:apply_options_exclude]
|
1582
|
+
passed_options = options[:options].reject {|k,v| options[:skip_apply_options].include?(k.to_s) || options[:skip_apply_options].include?(k.to_sym) }
|
1583
|
+
end
|
1582
1584
|
if object_key
|
1583
1585
|
payload.deep_merge!({object_key => passed_options})
|
1584
1586
|
else
|
@@ -95,12 +95,10 @@ module Morpheus
|
|
95
95
|
suggestions = find_command_suggestions(command_name)
|
96
96
|
if suggestions && suggestions.size == 1
|
97
97
|
msg += "\nThe most similar command is:\n"
|
98
|
-
suggestions.first
|
99
|
-
msg += "\t" + suggestion + "\n"
|
100
|
-
end
|
98
|
+
msg += "\t" + suggestions.first + "\n"
|
101
99
|
elsif suggestions && suggestions.size > 1
|
102
100
|
msg += "\nThe most similar commands are:\n"
|
103
|
-
suggestions.first(
|
101
|
+
suggestions.first(50).each do |suggestion|
|
104
102
|
msg += "\t" + suggestion + "\n"
|
105
103
|
end
|
106
104
|
end
|
@@ -283,7 +283,7 @@ EOT
|
|
283
283
|
return 1 if backup.nil?
|
284
284
|
parse_options(options, params)
|
285
285
|
confirm!("Are you sure you want to delete the backup #{backup['name']}?", options)
|
286
|
-
execute_api(@backups_interface, :destroy, [backup['id']], options
|
286
|
+
execute_api(@backups_interface, :destroy, [backup['id']], options) do |json_response|
|
287
287
|
print_green_success "Removed backup #{backup['name']}"
|
288
288
|
end
|
289
289
|
end
|
@@ -1,16 +1,15 @@
|
|
1
1
|
require 'morpheus/cli/cli_command'
|
2
2
|
|
3
|
-
# CLI command
|
4
|
-
# UI is
|
5
|
-
# API is /catalog-item-types and returns catalogItemTypes
|
3
|
+
# CLI command Catalog Item Types
|
4
|
+
# UI is Library > Blueprints > Catalog Items
|
5
|
+
# API is /api/catalog-item-types and returns catalogItemTypes
|
6
6
|
class Morpheus::Cli::CatalogItemTypesCommand
|
7
7
|
include Morpheus::Cli::CliCommand
|
8
8
|
include Morpheus::Cli::LibraryHelper
|
9
9
|
include Morpheus::Cli::OptionSourceHelper
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
set_command_description "Self Service: View and manage catalog item types"
|
11
|
+
set_command_name :'catalog-item-types'
|
12
|
+
set_command_description "View and manage catalog item types"
|
14
13
|
|
15
14
|
register_subcommands :list, :get, :add, :update, :remove
|
16
15
|
register_subcommands({:'update-logo' => :update_logo, :'update-dark-logo' => :update_dark_logo})
|
@@ -152,13 +151,28 @@ EOT
|
|
152
151
|
print_h1 "Catalog Item Type Details", [], options
|
153
152
|
print cyan
|
154
153
|
show_columns = catalog_item_type_column_definitions
|
154
|
+
show_columns.delete("Form") unless catalog_item_type['form']
|
155
155
|
show_columns.delete("Blueprint") unless catalog_item_type['blueprint']
|
156
156
|
show_columns.delete("Workflow") unless catalog_item_type['workflow']
|
157
157
|
show_columns.delete("Context") unless catalog_item_type['context'] # workflow context
|
158
158
|
print_description_list(show_columns, catalog_item_type)
|
159
159
|
|
160
|
+
option_type_form = catalog_item_type['form']
|
161
|
+
if option_type_form
|
162
|
+
print_h2 "Form Inputs"
|
163
|
+
form_inputs = (option_type_form['options'] || [])
|
164
|
+
if option_type_form['fieldGroups']
|
165
|
+
option_type_form['fieldGroups'].each { |field_group| form_inputs += (field_group['options'] || []) }
|
166
|
+
end
|
167
|
+
# print format_simple_option_types_table(form_inputs, options)
|
168
|
+
print format_option_types_table(form_inputs, options, 'config.customOptions')
|
169
|
+
print reset,"\n"
|
170
|
+
else
|
171
|
+
# print cyan,"No form inputs found for this catalog item.","\n",reset
|
172
|
+
end
|
173
|
+
|
160
174
|
if catalog_item_type['optionTypes'] && catalog_item_type['optionTypes'].size > 0
|
161
|
-
print_h2 "
|
175
|
+
print_h2 "Inputs"
|
162
176
|
opt_columns = [
|
163
177
|
{"ID" => lambda {|it| it['id'] } },
|
164
178
|
{"NAME" => lambda {|it| it['name'] } },
|
@@ -313,7 +327,13 @@ EOT
|
|
313
327
|
options[:options]['config'] = params['config'] # or file_content
|
314
328
|
end
|
315
329
|
end
|
316
|
-
opts.on('--
|
330
|
+
opts.on('--form-type form|optionTypes', String, "Form Type determines if input comes from a Form or list of Option Types") do |val|
|
331
|
+
params['formType'] = val
|
332
|
+
end
|
333
|
+
opts.on('--form FORM', String, "Form Name or ID") do |val|
|
334
|
+
params['form'] = val
|
335
|
+
end
|
336
|
+
opts.on('--option-types [x,y,z]', Array, "List of Option Type IDs") do |val|
|
317
337
|
if list.nil?
|
318
338
|
params['optionTypes'] = []
|
319
339
|
else
|
@@ -379,11 +399,24 @@ EOT
|
|
379
399
|
# massage association params a bit
|
380
400
|
params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
|
381
401
|
params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
|
382
|
-
|
383
|
-
|
384
|
-
|
402
|
+
if params['formType'].to_s.empty?
|
403
|
+
params['formType'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'formType', 'fieldLabel' => 'Form Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Form', 'value' => 'form'}, {'name' => 'Inputs', 'value' => 'optionTypes'}], 'defaultValue' => 'optionTypes', 'required' => true}], options[:options], @api_client, options[:params])['formType']
|
404
|
+
end
|
405
|
+
if params['formType'] == 'form'
|
406
|
+
# using formType = 'form'
|
407
|
+
# prompt for Form
|
408
|
+
options[:options]['form'] = params['form'] if params['form']
|
409
|
+
form_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'form', 'fieldLabel' => 'Form', 'type' => 'select', 'optionSource' => 'forms', 'required' => true}], options[:options], @api_client, options[:params])['form']
|
410
|
+
params['form'] = {'id' => form_id}
|
385
411
|
else
|
386
|
-
|
412
|
+
# using formType = 'optionTypes'
|
413
|
+
# prompt for Option Types
|
414
|
+
prompt_results = prompt_for_option_types(params, options, @api_client)
|
415
|
+
if prompt_results[:success]
|
416
|
+
params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
|
417
|
+
else
|
418
|
+
return 1, "failed to parse optionTypes"
|
419
|
+
end
|
387
420
|
end
|
388
421
|
payload[catalog_item_type_object_key].deep_merge!(params)
|
389
422
|
end
|
@@ -470,6 +503,12 @@ EOT
|
|
470
503
|
options[:options]['config'] = params['config'] # or file_content
|
471
504
|
end
|
472
505
|
end
|
506
|
+
opts.on('--form-type form|optionTypes', String, "Form Type determines if input comes from a Form or list of Option Types") do |val|
|
507
|
+
params['formType'] = val
|
508
|
+
end
|
509
|
+
opts.on('--form FORM', String, "Form Name or ID") do |val|
|
510
|
+
params['form'] = val
|
511
|
+
end
|
473
512
|
opts.on('--option-types [x,y,z]', Array, "List of Option Type IDs") do |list|
|
474
513
|
if list.nil?
|
475
514
|
params['optionTypes'] = []
|
@@ -693,6 +732,7 @@ EOT
|
|
693
732
|
"Workflow" => lambda {|it| it['workflow'] ? it['workflow']['name'] : nil },
|
694
733
|
"Context" => lambda {|it| it['context'] },
|
695
734
|
# "Content" => lambda {|it| it['content'] },
|
735
|
+
"Form Type" => lambda {|it| it['formType'] == 'form' ? "Form" : "Inputs" },
|
696
736
|
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
697
737
|
"Featured" => lambda {|it| format_boolean(it['featured']) },
|
698
738
|
#"Config" => lambda {|it| it['config'] },
|
@@ -716,6 +756,8 @@ EOT
|
|
716
756
|
"Workflow" => lambda {|it| it['workflow'] ? it['workflow']['name'] : nil },
|
717
757
|
"Context" => lambda {|it| it['context'] },
|
718
758
|
# "Content" => lambda {|it| it['content'] },
|
759
|
+
"Form Type" => lambda {|it| it['formType'] == 'form' ? "Form" : "Inputs" },
|
760
|
+
"Form" => lambda {|it| it['form'] ? it['form']['name'] : nil },
|
719
761
|
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
720
762
|
"Featured" => lambda {|it| format_boolean(it['featured']) },
|
721
763
|
"Allow Quantity" => lambda {|it| format_boolean(it['allowQuantity']) },
|
@@ -175,7 +175,7 @@ EOT
|
|
175
175
|
end
|
176
176
|
# reject hardcoded optionTypes
|
177
177
|
config_option_types = config_option_types.reject {|it| it['fieldName'] == 'name' || it['fieldName'] == 'description' || it['fieldName'] == 'domainName' }
|
178
|
-
config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client,
|
178
|
+
config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client, {certType: certificate_type['id']})
|
179
179
|
config_prompt.deep_compact!
|
180
180
|
params.deep_merge!(config_prompt)
|
181
181
|
end
|
@@ -730,14 +730,13 @@ class Morpheus::Cli::Clusters
|
|
730
730
|
server_payload['hostname'] = options[:hostname] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'hostname', 'fieldLabel' => 'Hostname', 'type' => 'text', 'required' => true, 'description' => 'Hostname', 'defaultValue' => resourceName}], options[:options], @api_client, api_params)['hostname']
|
731
731
|
|
732
732
|
# Kube Default Repo
|
733
|
-
if cluster_payload['type'] == 'kubernetes-cluster'
|
733
|
+
if cluster_payload['type'] == 'kubernetes-cluster'
|
734
734
|
default_repo = options[:default_repo] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'defaultRepoAccount', 'fieldLabel' => 'Cluster Repo Account', 'type' => 'select', 'required' => false, 'optionSource' => 'dockerHubRegistries'}], options[:options], @api_client, api_params)['defaultRepoAccount']
|
735
735
|
if default_repo != ""
|
736
736
|
server_payload['config']['defaultRepoAccount'] = default_repo
|
737
737
|
end
|
738
738
|
end
|
739
739
|
|
740
|
-
|
741
740
|
# Workflow / Automation
|
742
741
|
if provision_type['code'] != 'manual' && controller_type && controller_type['hasAutomation']
|
743
742
|
task_set_id = options[:taskSetId] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'taskSet', 'fieldLabel' => 'Workflow', 'type' => 'select', 'required' => false, 'optionSource' => 'taskSets'}], options[:options], @api_client, api_params.merge({'phase' => 'postProvision'}))['taskSet']
|