morpheus-cli 4.2.22 → 5.0.0
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/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +14 -0
- data/lib/morpheus/api/billing_interface.rb +33 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
- data/lib/morpheus/api/rest_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +14 -0
- data/lib/morpheus/cli.rb +2 -2
- data/lib/morpheus/cli/apps.rb +3 -4
- data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
- data/lib/morpheus/cli/backups_command.rb +3 -0
- data/lib/morpheus/cli/catalog_command.rb +507 -0
- data/lib/morpheus/cli/cli_command.rb +19 -11
- data/lib/morpheus/cli/commands/standard/source_command.rb +1 -1
- data/lib/morpheus/cli/commands/standard/update_command.rb +76 -0
- data/lib/morpheus/cli/containers_command.rb +14 -0
- data/lib/morpheus/cli/hosts.rb +30 -2
- data/lib/morpheus/cli/instances.rb +19 -1
- data/lib/morpheus/cli/library_option_lists_command.rb +14 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -6
- data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
- data/lib/morpheus/cli/mixins/catalog_helper.rb +66 -0
- data/lib/morpheus/cli/mixins/deployments_helper.rb +0 -1
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +46 -0
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/remote.rb +0 -2
- data/lib/morpheus/cli/roles.rb +305 -3
- data/lib/morpheus/cli/storage_providers_command.rb +40 -56
- data/lib/morpheus/cli/usage_command.rb +150 -0
- data/lib/morpheus/cli/user_settings_command.rb +1 -0
- data/lib/morpheus/cli/users.rb +12 -1
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +26 -5
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7e5399fa687da8ee714dc1bfe80cd72c2f01bf15cb465f1e6e576df53aa0a84
|
4
|
+
data.tar.gz: d5fe9c71d49308c5f7f92e47b134647712c302f833d7e77a55431bcec2e3036f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0904e36c4240d638d87862cefffd681241868a8cd06730eef6ddac921d4fb288a27043d365b4ba94b3223fa6be41b783f2b9aaa570e490b731528c6b282b5ff
|
7
|
+
data.tar.gz: b05b484d490e4829e20bba8d942acef387346cc03e214cd1c04d96a2cfca603d971d20054cb3bb9f9024d5bf977864b543d3c6d599089765f55426aa317a4f0e
|
data/Dockerfile
CHANGED
@@ -764,6 +764,20 @@ class Morpheus::APIClient
|
|
764
764
|
Morpheus::BackupJobsInterface.new(common_interface_options).setopts(@options)
|
765
765
|
end
|
766
766
|
|
767
|
+
def catalog_item_types
|
768
|
+
Morpheus::CatalogItemTypesInterface.new(common_interface_options).setopts(@options)
|
769
|
+
end
|
770
|
+
|
771
|
+
def billing
|
772
|
+
Morpheus::BillingInterface.new(common_interface_options).setopts(@options)
|
773
|
+
end
|
774
|
+
|
767
775
|
# add new interfaces here
|
768
776
|
|
777
|
+
protected
|
778
|
+
|
779
|
+
def validate_id!(id)
|
780
|
+
raise "#{self.class} passed a blank id!" if id.to_s.strip.empty?
|
781
|
+
end
|
782
|
+
|
769
783
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::BillingInterface < Morpheus::APIClient
|
4
|
+
|
5
|
+
def base_path
|
6
|
+
"/api/billing"
|
7
|
+
end
|
8
|
+
|
9
|
+
def list(params={})
|
10
|
+
execute(method: :get, url: "#{base_path}", params: params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def list_account(params={})
|
14
|
+
execute(method: :get, url: "#{base_path}/account", params: params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def list_zones(params={})
|
18
|
+
execute(method: :get, url: "#{base_path}/zones", params: params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def list_instances(params={})
|
22
|
+
execute(method: :get, url: "#{base_path}/instances", params: params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def list_servers(params={})
|
26
|
+
execute(method: :get, url: "#{base_path}/servers", params: params)
|
27
|
+
end
|
28
|
+
|
29
|
+
def list_discovered_servers(params={})
|
30
|
+
execute(method: :get, url: "#{base_path}/discoveredServers", params: params)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -31,10 +31,4 @@ class Morpheus::RestInterface < Morpheus::APIClient
|
|
31
31
|
execute(method: :delete, url: "#{base_path}/#{id}", params: params)
|
32
32
|
end
|
33
33
|
|
34
|
-
protected
|
35
|
-
|
36
|
-
def validate_id!(id)
|
37
|
-
raise "#{self.class} passed a blank id!" if id.to_s.strip.empty?
|
38
|
-
end
|
39
|
-
|
40
34
|
end
|
@@ -77,6 +77,20 @@ class Morpheus::RolesInterface < Morpheus::APIClient
|
|
77
77
|
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
78
78
|
end
|
79
79
|
|
80
|
+
def update_catalog_item_type(account_id, id, options)
|
81
|
+
url = build_url(account_id, id) + "/update-catalog-item-type"
|
82
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
83
|
+
payload = options
|
84
|
+
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
85
|
+
end
|
86
|
+
|
87
|
+
def update_persona(account_id, id, options)
|
88
|
+
url = build_url(account_id, id) + "/update-persona"
|
89
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
90
|
+
payload = options
|
91
|
+
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
92
|
+
end
|
93
|
+
|
80
94
|
private
|
81
95
|
|
82
96
|
def build_url(account_id=nil, role_id=nil)
|
data/lib/morpheus/cli.rb
CHANGED
@@ -67,8 +67,6 @@ module Morpheus
|
|
67
67
|
# all standard commands
|
68
68
|
Dir[File.dirname(__FILE__) + "/cli/commands/standard/**/*.rb"].each {|file| load file }
|
69
69
|
|
70
|
-
# shell scripting commands
|
71
|
-
|
72
70
|
# all the known commands
|
73
71
|
load 'morpheus/cli/remote.rb'
|
74
72
|
load 'morpheus/cli/doc.rb'
|
@@ -174,6 +172,8 @@ module Morpheus
|
|
174
172
|
load 'morpheus/cli/projects_command.rb'
|
175
173
|
load 'morpheus/cli/backups_command.rb'
|
176
174
|
load 'morpheus/cli/backup_jobs_command.rb'
|
175
|
+
load 'morpheus/cli/catalog_command.rb'
|
176
|
+
load 'morpheus/cli/usage_command.rb'
|
177
177
|
# add new commands here...
|
178
178
|
|
179
179
|
end
|
data/lib/morpheus/cli/apps.rb
CHANGED
@@ -92,10 +92,9 @@ class Morpheus::Cli::Apps
|
|
92
92
|
opts.footer = "List apps."
|
93
93
|
end
|
94
94
|
optparse.parse!(args)
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
return 1
|
95
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
96
|
+
if args.count > 0
|
97
|
+
options[:phrase] = args.join(" ")
|
99
98
|
end
|
100
99
|
connect(options)
|
101
100
|
begin
|
@@ -225,6 +225,9 @@ EOT
|
|
225
225
|
print_dry_run @backup_jobs_interface.dry.destroy(backup_job['id'], params)
|
226
226
|
return
|
227
227
|
end
|
228
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the backup #{backup['name']}?")
|
229
|
+
return 9, "aborted command"
|
230
|
+
end
|
228
231
|
json_response = @backup_jobs_interface.destroy(backup_job['id'], params)
|
229
232
|
render_response(json_response, options) do
|
230
233
|
print_green_success "Removed backup job #{backup_job['name']}"
|
@@ -215,6 +215,9 @@ EOT
|
|
215
215
|
print_dry_run @backups_interface.dry.destroy(backup['id'], params)
|
216
216
|
return
|
217
217
|
end
|
218
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the backup #{backup['name']}?")
|
219
|
+
return 9, "aborted command"
|
220
|
+
end
|
218
221
|
json_response = @backups_interface.destroy(backup['id'], params)
|
219
222
|
render_response(json_response, options) do
|
220
223
|
print_green_success "Removed backup #{backup['name']}"
|
@@ -0,0 +1,507 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
# CLI command self service
|
4
|
+
# UI is Tools: Self Service - Catalog Items
|
5
|
+
# API is /catalog-item-types and returns catalogItemTypes
|
6
|
+
class Morpheus::Cli::CatalogCommand
|
7
|
+
include Morpheus::Cli::CliCommand
|
8
|
+
include Morpheus::Cli::CatalogHelper
|
9
|
+
include Morpheus::Cli::LibraryHelper
|
10
|
+
include Morpheus::Cli::OptionSourceHelper
|
11
|
+
|
12
|
+
# hide until 5.1 when update api is fixed and service-catalog endpoints are available
|
13
|
+
set_command_hidden
|
14
|
+
set_command_name :'catalog'
|
15
|
+
|
16
|
+
register_subcommands :list, :get, :add, :update, :remove
|
17
|
+
|
18
|
+
def connect(opts)
|
19
|
+
@api_client = establish_remote_appliance_connection(opts)
|
20
|
+
@catalog_item_types_interface = @api_client.catalog_item_types
|
21
|
+
@option_types_interface = @api_client.option_types
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle(args)
|
25
|
+
handle_subcommand(args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def list(args)
|
29
|
+
options = {}
|
30
|
+
params = {}
|
31
|
+
ref_ids = []
|
32
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
33
|
+
opts.banner = subcommand_usage("[search]")
|
34
|
+
opts.on( '--enabled [on|off]', String, "Filter by enabled" ) do |val|
|
35
|
+
params['enabled'] = (val.to_s != 'false' && val.to_s != 'off')
|
36
|
+
end
|
37
|
+
opts.on( '--featured [on|off]', String, "Filter by featured" ) do |val|
|
38
|
+
params['featured'] = (val.to_s != 'false' && val.to_s != 'off')
|
39
|
+
end
|
40
|
+
build_standard_list_options(opts, options)
|
41
|
+
opts.footer = "List catalog items."
|
42
|
+
end
|
43
|
+
optparse.parse!(args)
|
44
|
+
connect(options)
|
45
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
46
|
+
if args.count > 0
|
47
|
+
options[:phrase] = args.join(" ")
|
48
|
+
end
|
49
|
+
params.merge!(parse_list_options(options))
|
50
|
+
@catalog_item_types_interface.setopts(options)
|
51
|
+
if options[:dry_run]
|
52
|
+
print_dry_run @catalog_item_types_interface.dry.list(params)
|
53
|
+
return
|
54
|
+
end
|
55
|
+
json_response = @catalog_item_types_interface.list(params)
|
56
|
+
catalog_item_types = json_response[catalog_item_type_list_key]
|
57
|
+
render_response(json_response, options, catalog_item_type_list_key) do
|
58
|
+
print_h1 "Morpheus Catalog Items", parse_list_subtitles(options), options
|
59
|
+
if catalog_item_types.empty?
|
60
|
+
print cyan,"No catalog items found.",reset,"\n"
|
61
|
+
else
|
62
|
+
list_columns = catalog_item_type_column_definitions.upcase_keys!
|
63
|
+
#list_columns["Config"] = lambda {|it| truncate_string(it['config'], 100) }
|
64
|
+
print as_pretty_table(catalog_item_types, list_columns.upcase_keys!, options)
|
65
|
+
print_results_pagination(json_response)
|
66
|
+
end
|
67
|
+
print reset,"\n"
|
68
|
+
end
|
69
|
+
if catalog_item_types.empty?
|
70
|
+
return 1, "no catalog items found"
|
71
|
+
else
|
72
|
+
return 0, nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get(args)
|
77
|
+
params = {}
|
78
|
+
options = {}
|
79
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
80
|
+
opts.banner = subcommand_usage("[catalog item type]")
|
81
|
+
opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
|
82
|
+
options[:show_config] = true
|
83
|
+
end
|
84
|
+
# opts.on('--no-config', "Do not display config content." ) do
|
85
|
+
# options[:no_config] = true
|
86
|
+
# end
|
87
|
+
build_standard_get_options(opts, options)
|
88
|
+
opts.footer = <<-EOT
|
89
|
+
Get details about a specific catalog item type.
|
90
|
+
[catalog item type] is required. This is the name or id of a catalog item type.
|
91
|
+
EOT
|
92
|
+
end
|
93
|
+
optparse.parse!(args)
|
94
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
95
|
+
connect(options)
|
96
|
+
id_list = parse_id_list(args)
|
97
|
+
return run_command_for_each_arg(id_list) do |arg|
|
98
|
+
_get(arg, params, options)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def _get(id, params, options)
|
103
|
+
catalog_item_type = nil
|
104
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
105
|
+
catalog_item_type = find_catalog_item_type_by_name(id)
|
106
|
+
return 1, "catalog item type not found for #{id}" if catalog_item_type.nil?
|
107
|
+
id = catalog_item_type['id']
|
108
|
+
end
|
109
|
+
@catalog_item_types_interface.setopts(options)
|
110
|
+
if options[:dry_run]
|
111
|
+
print_dry_run @catalog_item_types_interface.dry.get(id, params)
|
112
|
+
return
|
113
|
+
end
|
114
|
+
# skip extra query, list has same data as show right now
|
115
|
+
if catalog_item_type
|
116
|
+
json_response = {catalog_item_type_object_key => catalog_item_type}
|
117
|
+
else
|
118
|
+
json_response = @catalog_item_types_interface.get(id, params)
|
119
|
+
end
|
120
|
+
catalog_item_type = json_response[catalog_item_type_object_key]
|
121
|
+
config = catalog_item_type['config'] || {}
|
122
|
+
# export just the config as json or yaml (default)
|
123
|
+
if options[:show_config]
|
124
|
+
unless options[:json] || options[:yaml] || options[:csv]
|
125
|
+
options[:yaml] = true
|
126
|
+
end
|
127
|
+
return render_with_format(config, options)
|
128
|
+
end
|
129
|
+
render_response(json_response, options, catalog_item_type_object_key) do
|
130
|
+
print_h1 "Catalog Item Type Details", [], options
|
131
|
+
print cyan
|
132
|
+
show_columns = catalog_item_type_column_definitions
|
133
|
+
show_columns.delete("Blueprint") unless catalog_item_type['blueprint']
|
134
|
+
print_description_list(show_columns, catalog_item_type)
|
135
|
+
|
136
|
+
if catalog_item_type['optionTypes'] && catalog_item_type['optionTypes'].size > 0
|
137
|
+
print_h2 "Option Types"
|
138
|
+
opt_columns = [
|
139
|
+
{"ID" => lambda {|it| it['id'] } },
|
140
|
+
{"NAME" => lambda {|it| it['name'] } },
|
141
|
+
{"TYPE" => lambda {|it| it['type'] } },
|
142
|
+
{"FIELD NAME" => lambda {|it| it['fieldName'] } },
|
143
|
+
{"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
|
144
|
+
{"DEFAULT" => lambda {|it| it['defaultValue'] } },
|
145
|
+
{"REQUIRED" => lambda {|it| format_boolean it['required'] } },
|
146
|
+
]
|
147
|
+
print as_pretty_table(catalog_item_type['optionTypes'], opt_columns)
|
148
|
+
else
|
149
|
+
# print cyan,"No option types found for this catalog item.","\n",reset
|
150
|
+
end
|
151
|
+
|
152
|
+
if config && options[:no_config] != true
|
153
|
+
print_h2 "Config YAML"
|
154
|
+
#print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
|
155
|
+
#print reset,(as_yaml(config, options) rescue config),"\n",reset
|
156
|
+
config_string = as_yaml(config, options) rescue config
|
157
|
+
config_lines = config_string.split("\n")
|
158
|
+
config_line_count = config_lines.size
|
159
|
+
max_lines = 10
|
160
|
+
if config_lines.size > max_lines
|
161
|
+
config_string = config_lines.first(max_lines).join("\n")
|
162
|
+
config_string << "\n\n"
|
163
|
+
config_string << "(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)"
|
164
|
+
#config_string << "\n"
|
165
|
+
end
|
166
|
+
# strip --- yaml header
|
167
|
+
if config_string[0..3] == "---\n"
|
168
|
+
config_string = config_string[4..-1]
|
169
|
+
end
|
170
|
+
print reset,config_string.chomp("\n"),"\n",reset
|
171
|
+
end
|
172
|
+
|
173
|
+
print reset,"\n"
|
174
|
+
end
|
175
|
+
return 0, nil
|
176
|
+
end
|
177
|
+
|
178
|
+
def add(args)
|
179
|
+
options = {}
|
180
|
+
params = {}
|
181
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
182
|
+
opts.banner = subcommand_usage("[name] [options]")
|
183
|
+
build_option_type_options(opts, options, add_catalog_item_type_option_types)
|
184
|
+
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
185
|
+
options[:config_file] = val.to_s
|
186
|
+
file_content = nil
|
187
|
+
full_filename = File.expand_path(options[:config_file])
|
188
|
+
if File.exists?(full_filename)
|
189
|
+
file_content = File.read(full_filename)
|
190
|
+
else
|
191
|
+
print_red_alert "File not found: #{full_filename}"
|
192
|
+
return 1
|
193
|
+
end
|
194
|
+
parse_result = parse_json_or_yaml(file_content)
|
195
|
+
config_map = parse_result[:data]
|
196
|
+
if config_map.nil?
|
197
|
+
# todo: bubble up JSON.parse error message
|
198
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
199
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
200
|
+
else
|
201
|
+
params['config'] = config_map
|
202
|
+
options[:options]['config'] = params['config'] # or file_content
|
203
|
+
end
|
204
|
+
end
|
205
|
+
opts.on('--option-types [x,y,z]', Array, "List of Option Type IDs") do |list|
|
206
|
+
if list.nil?
|
207
|
+
params['optionTypes'] = []
|
208
|
+
else
|
209
|
+
params['optionTypes'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
210
|
+
end
|
211
|
+
end
|
212
|
+
opts.on('--optionTypes [x,y,z]', Array, "List of Option Type IDs") do |list|
|
213
|
+
if list.nil?
|
214
|
+
params['optionTypes'] = []
|
215
|
+
else
|
216
|
+
params['optionTypes'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
217
|
+
end
|
218
|
+
end
|
219
|
+
opts.add_hidden_option('--optionTypes')
|
220
|
+
build_option_type_options(opts, options, add_catalog_item_type_advanced_option_types)
|
221
|
+
build_standard_add_options(opts, options)
|
222
|
+
opts.footer = <<-EOT
|
223
|
+
Create a new catalog item type.
|
224
|
+
EOT
|
225
|
+
end
|
226
|
+
optparse.parse!(args)
|
227
|
+
verify_args!(args:args, optparse:optparse, min:0, max:1)
|
228
|
+
options[:options]['name'] = args[0] if args[0]
|
229
|
+
connect(options)
|
230
|
+
payload = {}
|
231
|
+
if options[:payload]
|
232
|
+
payload = options[:payload]
|
233
|
+
payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
|
234
|
+
else
|
235
|
+
payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
|
236
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(add_catalog_item_type_option_types(), options[:options], @api_client, options[:params])
|
237
|
+
params.deep_merge!(v_prompt)
|
238
|
+
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_catalog_item_type_advanced_option_types, options[:options], @api_client, options[:params])
|
239
|
+
advanced_config.deep_compact!
|
240
|
+
params.deep_merge!(advanced_config)
|
241
|
+
# convert checkbox "on" and "off" to true and false
|
242
|
+
params.booleanize!
|
243
|
+
# convert type to refType until api accepts type
|
244
|
+
if params['type'] && !params['refType']
|
245
|
+
if params['type'].to_s.downcase == 'blueprint'
|
246
|
+
params['refType'] = 'AppTemplate'
|
247
|
+
else
|
248
|
+
params['refType'] = 'InstanceType'
|
249
|
+
end
|
250
|
+
end
|
251
|
+
# convert config string to a map
|
252
|
+
config = params['config']
|
253
|
+
if config && config.is_a?(String)
|
254
|
+
parse_result = parse_json_or_yaml(config)
|
255
|
+
config_map = parse_result[:data]
|
256
|
+
if config_map.nil?
|
257
|
+
# todo: bubble up JSON.parse error message
|
258
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
259
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
260
|
+
else
|
261
|
+
params['config'] = config_map
|
262
|
+
end
|
263
|
+
end
|
264
|
+
if params['optionTypes']
|
265
|
+
# todo: move to optionSource, so it will be /api/options/optionTypes lol
|
266
|
+
prompt_results = prompt_for_option_types(params, options, @api_client)
|
267
|
+
if prompt_results[:success]
|
268
|
+
params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
|
269
|
+
else
|
270
|
+
return 1
|
271
|
+
end
|
272
|
+
end
|
273
|
+
payload[catalog_item_type_object_key].deep_merge!(params)
|
274
|
+
end
|
275
|
+
@catalog_item_types_interface.setopts(options)
|
276
|
+
if options[:dry_run]
|
277
|
+
print_dry_run @catalog_item_types_interface.dry.create(payload)
|
278
|
+
return 0, nil
|
279
|
+
end
|
280
|
+
json_response = @catalog_item_types_interface.create(payload)
|
281
|
+
catalog_item_type = json_response[catalog_item_type_object_key]
|
282
|
+
render_response(json_response, options, catalog_item_type_object_key) do
|
283
|
+
print_green_success "Added catalog item #{catalog_item_type['name']}"
|
284
|
+
return _get(catalog_item_type["id"], {}, options)
|
285
|
+
end
|
286
|
+
return 0, nil
|
287
|
+
end
|
288
|
+
|
289
|
+
def update(args)
|
290
|
+
options = {}
|
291
|
+
params = {}
|
292
|
+
payload = {}
|
293
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
294
|
+
opts.banner = subcommand_usage("[catalog item type] [options]")
|
295
|
+
build_option_type_options(opts, options, update_catalog_item_type_option_types)
|
296
|
+
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
297
|
+
options[:config_file] = val.to_s
|
298
|
+
file_content = nil
|
299
|
+
full_filename = File.expand_path(options[:config_file])
|
300
|
+
if File.exists?(full_filename)
|
301
|
+
file_content = File.read(full_filename)
|
302
|
+
else
|
303
|
+
print_red_alert "File not found: #{full_filename}"
|
304
|
+
return 1
|
305
|
+
end
|
306
|
+
parse_result = parse_json_or_yaml(file_content)
|
307
|
+
config_map = parse_result[:data]
|
308
|
+
if config_map.nil?
|
309
|
+
# todo: bubble up JSON.parse error message
|
310
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
311
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
312
|
+
else
|
313
|
+
params['config'] = config_map
|
314
|
+
options[:options]['config'] = params['config'] # or file_content
|
315
|
+
end
|
316
|
+
end
|
317
|
+
opts.on('--option-types [x,y,z]', Array, "List of Option Type IDs") do |list|
|
318
|
+
if list.nil?
|
319
|
+
params['optionTypes'] = []
|
320
|
+
else
|
321
|
+
params['optionTypes'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
322
|
+
end
|
323
|
+
end
|
324
|
+
opts.on('--optionTypes [x,y,z]', Array, "List of Option Type IDs") do |list|
|
325
|
+
if list.nil?
|
326
|
+
params['optionTypes'] = []
|
327
|
+
else
|
328
|
+
params['optionTypes'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
329
|
+
end
|
330
|
+
end
|
331
|
+
opts.add_hidden_option('--optionTypes')
|
332
|
+
build_option_type_options(opts, options, update_catalog_item_type_advanced_option_types)
|
333
|
+
build_standard_update_options(opts, options)
|
334
|
+
opts.footer = <<-EOT
|
335
|
+
Update a catalog item type.
|
336
|
+
[catalog item type] is required. This is the name or id of a catalog item type.
|
337
|
+
EOT
|
338
|
+
end
|
339
|
+
optparse.parse!(args)
|
340
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
341
|
+
connect(options)
|
342
|
+
catalog_item_type = find_catalog_item_type_by_name_or_id(args[0])
|
343
|
+
return 1 if catalog_item_type.nil?
|
344
|
+
payload = {}
|
345
|
+
if options[:payload]
|
346
|
+
payload = options[:payload]
|
347
|
+
payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
|
348
|
+
else
|
349
|
+
payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
|
350
|
+
# do not prompt on update
|
351
|
+
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_catalog_item_type_option_types, options[:options], @api_client, options[:params])
|
352
|
+
v_prompt.deep_compact!
|
353
|
+
params.deep_merge!(v_prompt)
|
354
|
+
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_catalog_item_type_advanced_option_types, options[:options], @api_client, options[:params])
|
355
|
+
advanced_config.deep_compact!
|
356
|
+
params.deep_merge!(advanced_config)
|
357
|
+
# convert checkbox "on" and "off" to true and false
|
358
|
+
params.booleanize!
|
359
|
+
# convert type to refType until api accepts type
|
360
|
+
if params['type'] && !params['refType']
|
361
|
+
if params['type'].to_s.downcase == 'blueprint'
|
362
|
+
params['refType'] = 'AppTemplate'
|
363
|
+
else
|
364
|
+
params['refType'] = 'InstanceType'
|
365
|
+
end
|
366
|
+
end
|
367
|
+
# convert config string to a map
|
368
|
+
config = params['config']
|
369
|
+
if config && config.is_a?(String)
|
370
|
+
parse_result = parse_json_or_yaml(config)
|
371
|
+
config_map = parse_result[:data]
|
372
|
+
if config_map.nil?
|
373
|
+
# todo: bubble up JSON.parse error message
|
374
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
375
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
376
|
+
else
|
377
|
+
params['config'] = config_map
|
378
|
+
end
|
379
|
+
end
|
380
|
+
payload.deep_merge!({catalog_item_type_object_key => params})
|
381
|
+
if payload[catalog_item_type_object_key].empty? # || options[:no_prompt]
|
382
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
383
|
+
end
|
384
|
+
end
|
385
|
+
@catalog_item_types_interface.setopts(options)
|
386
|
+
if options[:dry_run]
|
387
|
+
print_dry_run @catalog_item_types_interface.dry.update(catalog_item_type['id'], payload)
|
388
|
+
return
|
389
|
+
end
|
390
|
+
json_response = @catalog_item_types_interface.update(catalog_item_type['id'], payload)
|
391
|
+
catalog_item_type = json_response[catalog_item_type_object_key]
|
392
|
+
render_response(json_response, options, catalog_item_type_object_key) do
|
393
|
+
print_green_success "Updated catalog item #{catalog_item_type['name']}"
|
394
|
+
return _get(catalog_item_type["id"], {}, options)
|
395
|
+
end
|
396
|
+
return 0, nil
|
397
|
+
end
|
398
|
+
|
399
|
+
def remove(args)
|
400
|
+
options = {}
|
401
|
+
params = {}
|
402
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
403
|
+
opts.banner = subcommand_usage("[catalog item type] [options]")
|
404
|
+
build_standard_remove_options(opts, options)
|
405
|
+
opts.footer = <<-EOT
|
406
|
+
Delete a catalog_item_type.
|
407
|
+
[catalog item type] is required. This is the name or id of a catalog item type.
|
408
|
+
EOT
|
409
|
+
end
|
410
|
+
optparse.parse!(args)
|
411
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
412
|
+
connect(options)
|
413
|
+
catalog_item_type = find_catalog_item_type_by_name_or_id(args[0])
|
414
|
+
return 1 if catalog_item_type.nil?
|
415
|
+
@catalog_item_types_interface.setopts(options)
|
416
|
+
if options[:dry_run]
|
417
|
+
print_dry_run @catalog_item_types_interface.dry.destroy(catalog_item_type['id'], params)
|
418
|
+
return
|
419
|
+
end
|
420
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item #{catalog_item_type['name']}?")
|
421
|
+
return 9, "aborted command"
|
422
|
+
end
|
423
|
+
json_response = @catalog_item_types_interface.destroy(catalog_item_type['id'], params)
|
424
|
+
render_response(json_response, options) do
|
425
|
+
print_green_success "Removed catalog item #{catalog_item_type['name']}"
|
426
|
+
end
|
427
|
+
return 0, nil
|
428
|
+
end
|
429
|
+
|
430
|
+
private
|
431
|
+
|
432
|
+
def catalog_item_type_column_definitions()
|
433
|
+
{
|
434
|
+
"ID" => 'id',
|
435
|
+
"Name" => 'name',
|
436
|
+
"Description" => 'description',
|
437
|
+
"Type" => lambda {|it| format_catalog_type(it) },
|
438
|
+
"Blueprint" => lambda {|it| it['blueprint'] ? it['blueprint']['name'] : nil },
|
439
|
+
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
440
|
+
"Featured" => lambda {|it| format_boolean(it['featured']) },
|
441
|
+
#"Config" => lambda {|it| it['config'] },
|
442
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
443
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
444
|
+
}
|
445
|
+
end
|
446
|
+
|
447
|
+
def format_catalog_type(catalog_item_type)
|
448
|
+
out = ""
|
449
|
+
# api "blueprint": {"name":my blueprint"} }
|
450
|
+
# instead of cryptic refType
|
451
|
+
if catalog_item_type['type']
|
452
|
+
if catalog_item_type['type'].is_a?(String)
|
453
|
+
out << catalog_item_type['type'].to_s.capitalize
|
454
|
+
else
|
455
|
+
out << (catalog_item_type['type']['name'] || catalog_item_type['type']['code']) rescue catalog_item_type['type'].to_s
|
456
|
+
end
|
457
|
+
else
|
458
|
+
ref_type = catalog_item_type['refType']
|
459
|
+
if ref_type == 'InstanceType'
|
460
|
+
out << "Instance"
|
461
|
+
elsif ref_type == 'AppTemplate'
|
462
|
+
out << "Blueprint"
|
463
|
+
elsif ref_type
|
464
|
+
out << ref_type
|
465
|
+
else
|
466
|
+
"(none)"
|
467
|
+
end
|
468
|
+
end
|
469
|
+
out
|
470
|
+
end
|
471
|
+
|
472
|
+
# this is not so simple, need to first choose select instance, host or provider
|
473
|
+
def add_catalog_item_type_option_types
|
474
|
+
[
|
475
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
|
476
|
+
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
|
477
|
+
{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}], 'defaultValue' => 'instance'},
|
478
|
+
{'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
|
479
|
+
{'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false},
|
480
|
+
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true},
|
481
|
+
{'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList'},
|
482
|
+
#{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.'},
|
483
|
+
{'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'required' => true, 'description' => 'JSON or YAML'}
|
484
|
+
]
|
485
|
+
end
|
486
|
+
|
487
|
+
def add_catalog_item_type_advanced_option_types
|
488
|
+
[]
|
489
|
+
end
|
490
|
+
|
491
|
+
def update_catalog_item_type_option_types
|
492
|
+
add_catalog_item_type_option_types.collect {|it|
|
493
|
+
it.delete('required')
|
494
|
+
it.delete('defaultValue')
|
495
|
+
it
|
496
|
+
}
|
497
|
+
end
|
498
|
+
|
499
|
+
def update_catalog_item_type_advanced_option_types
|
500
|
+
add_catalog_item_type_advanced_option_types.collect {|it|
|
501
|
+
it.delete('required')
|
502
|
+
it.delete('defaultValue')
|
503
|
+
it
|
504
|
+
}
|
505
|
+
end
|
506
|
+
|
507
|
+
end
|