morpheus-cli 5.0.0 → 5.2.2
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 +1 -0
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +16 -0
- data/lib/morpheus/api/billing_interface.rb +1 -0
- data/lib/morpheus/api/deploy_interface.rb +1 -1
- data/lib/morpheus/api/deployments_interface.rb +20 -1
- data/lib/morpheus/api/forgot_password_interface.rb +17 -0
- data/lib/morpheus/api/instances_interface.rb +16 -2
- data/lib/morpheus/api/invoices_interface.rb +12 -3
- data/lib/morpheus/api/search_interface.rb +13 -0
- data/lib/morpheus/api/servers_interface.rb +14 -0
- data/lib/morpheus/api/service_catalog_interface.rb +89 -0
- data/lib/morpheus/api/usage_interface.rb +18 -0
- data/lib/morpheus/cli.rb +6 -2
- data/lib/morpheus/cli/apps.rb +3 -23
- data/lib/morpheus/cli/budgets_command.rb +389 -319
- data/lib/morpheus/cli/{catalog_command.rb → catalog_item_types_command.rb} +182 -67
- data/lib/morpheus/cli/cli_command.rb +51 -10
- data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -13
- data/lib/morpheus/cli/commands/standard/history_command.rb +9 -3
- data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
- data/lib/morpheus/cli/containers_command.rb +0 -24
- data/lib/morpheus/cli/cypher_command.rb +6 -2
- data/lib/morpheus/cli/dashboard_command.rb +260 -20
- data/lib/morpheus/cli/deploy.rb +199 -90
- data/lib/morpheus/cli/deployments.rb +341 -28
- data/lib/morpheus/cli/deploys.rb +206 -41
- data/lib/morpheus/cli/error_handler.rb +7 -0
- data/lib/morpheus/cli/forgot_password.rb +133 -0
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/health_command.rb +59 -2
- data/lib/morpheus/cli/hosts.rb +271 -39
- data/lib/morpheus/cli/instances.rb +228 -129
- data/lib/morpheus/cli/invoices_command.rb +100 -20
- data/lib/morpheus/cli/jobs_command.rb +94 -92
- data/lib/morpheus/cli/library_option_lists_command.rb +1 -1
- data/lib/morpheus/cli/library_option_types_command.rb +10 -5
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -1
- data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -2
- data/lib/morpheus/cli/mixins/print_helper.rb +13 -27
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +108 -5
- data/lib/morpheus/cli/option_types.rb +271 -22
- data/lib/morpheus/cli/remote.rb +35 -10
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/roles.rb +193 -155
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +33 -11
- data/lib/morpheus/cli/tasks.rb +29 -32
- data/lib/morpheus/cli/usage_command.rb +64 -11
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +429 -254
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +33 -40
- data/lib/morpheus/formatters.rb +75 -18
- data/lib/morpheus/terminal.rb +6 -2
- metadata +10 -4
- data/lib/morpheus/cli/mixins/catalog_helper.rb +0 -66
@@ -1,17 +1,16 @@
|
|
1
1
|
require 'morpheus/cli/cli_command'
|
2
2
|
|
3
3
|
# CLI command self service
|
4
|
-
# UI is Tools: Self Service - Catalog
|
4
|
+
# UI is Tools: Self Service - Catalog
|
5
5
|
# API is /catalog-item-types and returns catalogItemTypes
|
6
|
-
class Morpheus::Cli::
|
6
|
+
class Morpheus::Cli::CatalogItemTypesCommand
|
7
7
|
include Morpheus::Cli::CliCommand
|
8
|
-
include Morpheus::Cli::CatalogHelper
|
9
8
|
include Morpheus::Cli::LibraryHelper
|
10
9
|
include Morpheus::Cli::OptionSourceHelper
|
11
10
|
|
12
|
-
#
|
13
|
-
|
14
|
-
|
11
|
+
# set_command_name :'catalog-types'
|
12
|
+
set_command_name :'self-service'
|
13
|
+
set_command_description "Self Service: View and manage catalog item types"
|
15
14
|
|
16
15
|
register_subcommands :list, :get, :add, :update, :remove
|
17
16
|
|
@@ -38,7 +37,7 @@ class Morpheus::Cli::CatalogCommand
|
|
38
37
|
params['featured'] = (val.to_s != 'false' && val.to_s != 'off')
|
39
38
|
end
|
40
39
|
build_standard_list_options(opts, options)
|
41
|
-
opts.footer = "List catalog
|
40
|
+
opts.footer = "List catalog item types."
|
42
41
|
end
|
43
42
|
optparse.parse!(args)
|
44
43
|
connect(options)
|
@@ -55,11 +54,14 @@ class Morpheus::Cli::CatalogCommand
|
|
55
54
|
json_response = @catalog_item_types_interface.list(params)
|
56
55
|
catalog_item_types = json_response[catalog_item_type_list_key]
|
57
56
|
render_response(json_response, options, catalog_item_type_list_key) do
|
58
|
-
print_h1 "Morpheus Catalog
|
57
|
+
print_h1 "Morpheus Catalog Item Types", parse_list_subtitles(options), options
|
59
58
|
if catalog_item_types.empty?
|
60
|
-
print cyan,"No catalog
|
59
|
+
print cyan,"No catalog item types found.",reset,"\n"
|
61
60
|
else
|
62
61
|
list_columns = catalog_item_type_column_definitions.upcase_keys!
|
62
|
+
list_columns.delete("Blueprint")
|
63
|
+
list_columns.delete("Workflow")
|
64
|
+
list_columns.delete("Context")
|
63
65
|
#list_columns["Config"] = lambda {|it| truncate_string(it['config'], 100) }
|
64
66
|
print as_pretty_table(catalog_item_types, list_columns.upcase_keys!, options)
|
65
67
|
print_results_pagination(json_response)
|
@@ -67,7 +69,7 @@ class Morpheus::Cli::CatalogCommand
|
|
67
69
|
print reset,"\n"
|
68
70
|
end
|
69
71
|
if catalog_item_types.empty?
|
70
|
-
return 1, "no catalog
|
72
|
+
return 1, "no catalog item types found"
|
71
73
|
else
|
72
74
|
return 0, nil
|
73
75
|
end
|
@@ -77,17 +79,20 @@ class Morpheus::Cli::CatalogCommand
|
|
77
79
|
params = {}
|
78
80
|
options = {}
|
79
81
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
80
|
-
opts.banner = subcommand_usage("[
|
82
|
+
opts.banner = subcommand_usage("[type]")
|
81
83
|
opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
|
82
84
|
options[:show_config] = true
|
83
85
|
end
|
84
|
-
# opts.on('--no-config', "Do not display
|
86
|
+
# opts.on('--no-config', "Do not display Config YAML." ) do
|
85
87
|
# options[:no_config] = true
|
86
88
|
# end
|
89
|
+
opts.on('--no-content', "Do not display Content." ) do
|
90
|
+
options[:no_content] = true
|
91
|
+
end
|
87
92
|
build_standard_get_options(opts, options)
|
88
93
|
opts.footer = <<-EOT
|
89
94
|
Get details about a specific catalog item type.
|
90
|
-
[
|
95
|
+
[type] is required. This is the name or id of a catalog item type.
|
91
96
|
EOT
|
92
97
|
end
|
93
98
|
optparse.parse!(args)
|
@@ -131,6 +136,8 @@ EOT
|
|
131
136
|
print cyan
|
132
137
|
show_columns = catalog_item_type_column_definitions
|
133
138
|
show_columns.delete("Blueprint") unless catalog_item_type['blueprint']
|
139
|
+
show_columns.delete("Workflow") unless catalog_item_type['workflow']
|
140
|
+
show_columns.delete("Context") unless catalog_item_type['context'] # workflow context
|
134
141
|
print_description_list(show_columns, catalog_item_type)
|
135
142
|
|
136
143
|
if catalog_item_type['optionTypes'] && catalog_item_type['optionTypes'].size > 0
|
@@ -149,25 +156,62 @@ EOT
|
|
149
156
|
# print cyan,"No option types found for this catalog item.","\n",reset
|
150
157
|
end
|
151
158
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
159
|
+
item_type_code = catalog_item_type['type'].to_s.downcase
|
160
|
+
if options[:no_config] != true
|
161
|
+
if item_type_code == 'instance'
|
162
|
+
print_h2 "Config YAML"
|
163
|
+
if config
|
164
|
+
#print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
|
165
|
+
#print reset,(as_yaml(config, options) rescue config),"\n",reset
|
166
|
+
config_string = as_yaml(config, options) rescue config
|
167
|
+
config_lines = config_string.split("\n")
|
168
|
+
config_line_count = config_lines.size
|
169
|
+
max_lines = 10
|
170
|
+
if config_lines.size > max_lines
|
171
|
+
config_string = config_lines.first(max_lines).join("\n")
|
172
|
+
config_string << "\n\n"
|
173
|
+
config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
|
174
|
+
#config_string << "\n"
|
175
|
+
end
|
176
|
+
# strip --- yaml header
|
177
|
+
if config_string[0..3] == "---\n"
|
178
|
+
config_string = config_string[4..-1]
|
179
|
+
end
|
180
|
+
print reset,config_string.chomp("\n"),"\n",reset
|
181
|
+
else
|
182
|
+
print reset,"(blank)","\n",reset
|
183
|
+
end
|
184
|
+
elsif item_type_code == 'blueprint' || item_type_code == 'apptemplate' || item_type_code == 'app'
|
185
|
+
print_h2 "App Spec"
|
186
|
+
if catalog_item_type['appSpec']
|
187
|
+
#print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
|
188
|
+
#print reset,(as_yaml(config, options) rescue config),"\n",reset
|
189
|
+
config_string = catalog_item_type['appSpec'] || ""
|
190
|
+
config_lines = config_string.split("\n")
|
191
|
+
config_line_count = config_lines.size
|
192
|
+
max_lines = 10
|
193
|
+
if config_lines.size > max_lines
|
194
|
+
config_string = config_lines.first(max_lines).join("\n")
|
195
|
+
config_string << "\n\n"
|
196
|
+
config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
|
197
|
+
#config_string << "\n"
|
198
|
+
end
|
199
|
+
# strip --- yaml header
|
200
|
+
if config_string[0..3] == "---\n"
|
201
|
+
config_string = config_string[4..-1]
|
202
|
+
end
|
203
|
+
print reset,config_string.chomp("\n"),"\n",reset
|
204
|
+
else
|
205
|
+
print reset,"(blank)","\n",reset
|
206
|
+
end
|
207
|
+
elsif item_type_code == 'workflow' || item_type_code == 'operationalworkflow' || item_type_code == 'taskset'
|
169
208
|
end
|
170
|
-
|
209
|
+
end
|
210
|
+
|
211
|
+
# Content (Wiki Page)
|
212
|
+
if !catalog_item_type["content"].to_s.empty? && options[:no_content] != true
|
213
|
+
print_h2 "Content"
|
214
|
+
print reset,catalog_item_type["content"].chomp("\n"),"\n",reset
|
171
215
|
end
|
172
216
|
|
173
217
|
print reset,"\n"
|
@@ -180,6 +224,10 @@ EOT
|
|
180
224
|
params = {}
|
181
225
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
182
226
|
opts.banner = subcommand_usage("[name] [options]")
|
227
|
+
# opts.on('-t', '--type [instance|blueprint|workflow]', "Item Type, default is instance.") do |val|
|
228
|
+
# # params['type'] = val.to_s.downcase
|
229
|
+
# options[:options]['type'] = val.to_s.downcase
|
230
|
+
# end
|
183
231
|
build_option_type_options(opts, options, add_catalog_item_type_option_types)
|
184
232
|
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
185
233
|
options[:config_file] = val.to_s
|
@@ -233,6 +281,8 @@ EOT
|
|
233
281
|
payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
|
234
282
|
else
|
235
283
|
payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
|
284
|
+
# Type prompt first
|
285
|
+
#params['type'] = Morpheus::Cli::OptionTypes.no_prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true}], options[:options], @api_client, options[:params])['type']
|
236
286
|
v_prompt = Morpheus::Cli::OptionTypes.prompt(add_catalog_item_type_option_types(), options[:options], @api_client, options[:params])
|
237
287
|
params.deep_merge!(v_prompt)
|
238
288
|
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_catalog_item_type_advanced_option_types, options[:options], @api_client, options[:params])
|
@@ -241,13 +291,15 @@ EOT
|
|
241
291
|
# convert checkbox "on" and "off" to true and false
|
242
292
|
params.booleanize!
|
243
293
|
# convert type to refType until api accepts type
|
244
|
-
if params['type'] && !params['refType']
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
294
|
+
# if params['type'] && !params['refType']
|
295
|
+
# if params['type'].to_s.downcase == 'instance'
|
296
|
+
# params['refType'] = 'InstanceType'
|
297
|
+
# elsif params['type'].to_s.downcase == 'blueprint'
|
298
|
+
# params['refType'] = 'AppTemplate'
|
299
|
+
# elsif params['type'].to_s.downcase == 'workflow'
|
300
|
+
# params['refType'] = 'OperationalWorkflow'
|
301
|
+
# end
|
302
|
+
# end
|
251
303
|
# convert config string to a map
|
252
304
|
config = params['config']
|
253
305
|
if config && config.is_a?(String)
|
@@ -261,14 +313,14 @@ EOT
|
|
261
313
|
params['config'] = config_map
|
262
314
|
end
|
263
315
|
end
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
316
|
+
# massage association params a bit
|
317
|
+
params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
|
318
|
+
params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
|
319
|
+
prompt_results = prompt_for_option_types(params, options, @api_client)
|
320
|
+
if prompt_results[:success]
|
321
|
+
params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
|
322
|
+
else
|
323
|
+
return 1, "failed to parse optionTypes"
|
272
324
|
end
|
273
325
|
payload[catalog_item_type_object_key].deep_merge!(params)
|
274
326
|
end
|
@@ -280,7 +332,7 @@ EOT
|
|
280
332
|
json_response = @catalog_item_types_interface.create(payload)
|
281
333
|
catalog_item_type = json_response[catalog_item_type_object_key]
|
282
334
|
render_response(json_response, options, catalog_item_type_object_key) do
|
283
|
-
print_green_success "Added catalog item #{catalog_item_type['name']}"
|
335
|
+
print_green_success "Added catalog item type #{catalog_item_type['name']}"
|
284
336
|
return _get(catalog_item_type["id"], {}, options)
|
285
337
|
end
|
286
338
|
return 0, nil
|
@@ -291,7 +343,7 @@ EOT
|
|
291
343
|
params = {}
|
292
344
|
payload = {}
|
293
345
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
294
|
-
opts.banner = subcommand_usage("[
|
346
|
+
opts.banner = subcommand_usage("[type] [options]")
|
295
347
|
build_option_type_options(opts, options, update_catalog_item_type_option_types)
|
296
348
|
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
297
349
|
options[:config_file] = val.to_s
|
@@ -333,7 +385,7 @@ EOT
|
|
333
385
|
build_standard_update_options(opts, options)
|
334
386
|
opts.footer = <<-EOT
|
335
387
|
Update a catalog item type.
|
336
|
-
[
|
388
|
+
[type] is required. This is the name or id of a catalog item type.
|
337
389
|
EOT
|
338
390
|
end
|
339
391
|
optparse.parse!(args)
|
@@ -356,14 +408,7 @@ EOT
|
|
356
408
|
params.deep_merge!(advanced_config)
|
357
409
|
# convert checkbox "on" and "off" to true and false
|
358
410
|
params.booleanize!
|
359
|
-
|
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
|
411
|
+
|
367
412
|
# convert config string to a map
|
368
413
|
config = params['config']
|
369
414
|
if config && config.is_a?(String)
|
@@ -377,6 +422,18 @@ EOT
|
|
377
422
|
params['config'] = config_map
|
378
423
|
end
|
379
424
|
end
|
425
|
+
if params['optionTypes']
|
426
|
+
# todo: move to optionSource, so it will be /api/options/optionTypes lol
|
427
|
+
prompt_results = prompt_for_option_types(params, options, @api_client)
|
428
|
+
if prompt_results[:success]
|
429
|
+
params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
|
430
|
+
else
|
431
|
+
return 1, "failed to parse optionTypes"
|
432
|
+
end
|
433
|
+
end
|
434
|
+
# massage association params a bit
|
435
|
+
params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
|
436
|
+
params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
|
380
437
|
payload.deep_merge!({catalog_item_type_object_key => params})
|
381
438
|
if payload[catalog_item_type_object_key].empty? # || options[:no_prompt]
|
382
439
|
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
@@ -390,7 +447,7 @@ EOT
|
|
390
447
|
json_response = @catalog_item_types_interface.update(catalog_item_type['id'], payload)
|
391
448
|
catalog_item_type = json_response[catalog_item_type_object_key]
|
392
449
|
render_response(json_response, options, catalog_item_type_object_key) do
|
393
|
-
print_green_success "Updated catalog item #{catalog_item_type['name']}"
|
450
|
+
print_green_success "Updated catalog item type #{catalog_item_type['name']}"
|
394
451
|
return _get(catalog_item_type["id"], {}, options)
|
395
452
|
end
|
396
453
|
return 0, nil
|
@@ -400,11 +457,11 @@ EOT
|
|
400
457
|
options = {}
|
401
458
|
params = {}
|
402
459
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
403
|
-
opts.banner = subcommand_usage("[
|
460
|
+
opts.banner = subcommand_usage("[type] [options]")
|
404
461
|
build_standard_remove_options(opts, options)
|
405
462
|
opts.footer = <<-EOT
|
406
|
-
Delete a
|
407
|
-
[
|
463
|
+
Delete a catalog item type.
|
464
|
+
[type] is required. This is the name or id of a catalog item type.
|
408
465
|
EOT
|
409
466
|
end
|
410
467
|
optparse.parse!(args)
|
@@ -417,12 +474,12 @@ EOT
|
|
417
474
|
print_dry_run @catalog_item_types_interface.dry.destroy(catalog_item_type['id'], params)
|
418
475
|
return
|
419
476
|
end
|
420
|
-
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item #{catalog_item_type['name']}?")
|
477
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item type #{catalog_item_type['name']}?")
|
421
478
|
return 9, "aborted command"
|
422
479
|
end
|
423
480
|
json_response = @catalog_item_types_interface.destroy(catalog_item_type['id'], params)
|
424
481
|
render_response(json_response, options) do
|
425
|
-
print_green_success "Removed catalog item #{catalog_item_type['name']}"
|
482
|
+
print_green_success "Removed catalog item type #{catalog_item_type['name']}"
|
426
483
|
end
|
427
484
|
return 0, nil
|
428
485
|
end
|
@@ -436,6 +493,9 @@ EOT
|
|
436
493
|
"Description" => 'description',
|
437
494
|
"Type" => lambda {|it| format_catalog_type(it) },
|
438
495
|
"Blueprint" => lambda {|it| it['blueprint'] ? it['blueprint']['name'] : nil },
|
496
|
+
"Workflow" => lambda {|it| it['workflow'] ? it['workflow']['name'] : nil },
|
497
|
+
"Context" => lambda {|it| it['context'] },
|
498
|
+
# "Content" => lambda {|it| it['content'] },
|
439
499
|
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
440
500
|
"Featured" => lambda {|it| format_boolean(it['featured']) },
|
441
501
|
#"Config" => lambda {|it| it['config'] },
|
@@ -455,6 +515,7 @@ EOT
|
|
455
515
|
out << (catalog_item_type['type']['name'] || catalog_item_type['type']['code']) rescue catalog_item_type['type'].to_s
|
456
516
|
end
|
457
517
|
else
|
518
|
+
# refType is not returned
|
458
519
|
ref_type = catalog_item_type['refType']
|
459
520
|
if ref_type == 'InstanceType'
|
460
521
|
out << "Instance"
|
@@ -469,18 +530,24 @@ EOT
|
|
469
530
|
out
|
470
531
|
end
|
471
532
|
|
472
|
-
# this is not so simple, need to first choose select instance, host or provider
|
473
533
|
def add_catalog_item_type_option_types
|
474
534
|
[
|
535
|
+
{'code' => 'catalogItemType.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true},
|
475
536
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
|
476
537
|
{'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
538
|
{'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
|
479
539
|
{'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false},
|
480
540
|
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true},
|
481
541
|
{'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList'},
|
482
542
|
#{'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', '
|
543
|
+
{'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true},
|
544
|
+
{'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true},
|
545
|
+
{'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true},
|
546
|
+
{'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'noParams' => true},
|
547
|
+
{'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
|
548
|
+
[{'name' => "Select", 'value' => ""}, {'name' => "None", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
|
549
|
+
}, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'Select', 'required' => false},
|
550
|
+
{'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item'}
|
484
551
|
]
|
485
552
|
end
|
486
553
|
|
@@ -489,11 +556,13 @@ EOT
|
|
489
556
|
end
|
490
557
|
|
491
558
|
def update_catalog_item_type_option_types
|
492
|
-
add_catalog_item_type_option_types.collect {|it|
|
559
|
+
list = add_catalog_item_type_option_types.collect {|it|
|
493
560
|
it.delete('required')
|
494
561
|
it.delete('defaultValue')
|
495
562
|
it
|
496
563
|
}
|
564
|
+
list = list.reject {|it| ["type"].include? it['fieldName'] }
|
565
|
+
list
|
497
566
|
end
|
498
567
|
|
499
568
|
def update_catalog_item_type_advanced_option_types
|
@@ -504,4 +573,50 @@ EOT
|
|
504
573
|
}
|
505
574
|
end
|
506
575
|
|
576
|
+
def catalog_item_type_object_key
|
577
|
+
'catalogItemType'
|
578
|
+
end
|
579
|
+
|
580
|
+
def catalog_item_type_list_key
|
581
|
+
'catalogItemTypes'
|
582
|
+
end
|
583
|
+
|
584
|
+
def find_catalog_item_type_by_name_or_id(val)
|
585
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
586
|
+
return find_catalog_item_type_by_id(val)
|
587
|
+
else
|
588
|
+
return find_catalog_item_type_by_name(val)
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
def find_catalog_item_type_by_id(id)
|
593
|
+
begin
|
594
|
+
json_response = @catalog_item_types_interface.get(id.to_i)
|
595
|
+
return json_response[catalog_item_type_object_key]
|
596
|
+
rescue RestClient::Exception => e
|
597
|
+
if e.response && e.response.code == 404
|
598
|
+
print_red_alert "catalog item type not found by id '#{id}'"
|
599
|
+
else
|
600
|
+
raise e
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
def find_catalog_item_type_by_name(name)
|
606
|
+
json_response = @catalog_item_types_interface.list({name: name.to_s})
|
607
|
+
catalog_item_types = json_response[catalog_item_type_list_key]
|
608
|
+
if catalog_item_types.empty?
|
609
|
+
print_red_alert "catalog item type not found by name '#{name}'"
|
610
|
+
return nil
|
611
|
+
elsif catalog_item_types.size > 1
|
612
|
+
print_red_alert "#{catalog_item_types.size} catalog item types found by name '#{name}'"
|
613
|
+
puts_error as_pretty_table(catalog_item_types, [:id, :name], {color:red})
|
614
|
+
print_red_alert "Try using ID instead"
|
615
|
+
print reset,"\n"
|
616
|
+
return nil
|
617
|
+
else
|
618
|
+
return catalog_item_types[0]
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
507
622
|
end
|
@@ -203,7 +203,13 @@ module Morpheus
|
|
203
203
|
# value_label = 'SELECT'
|
204
204
|
# elsif option['type'] == 'select'
|
205
205
|
end
|
206
|
-
|
206
|
+
full_option = "--#{full_field_name} #{value_label}"
|
207
|
+
shorthand_option = option_type['shorthand']
|
208
|
+
arg1, arg2 = full_option, String
|
209
|
+
if option_type['shorthand']
|
210
|
+
arg1, arg2 = full_option, option_type['shorthand']
|
211
|
+
end
|
212
|
+
opts.on(arg1, arg2, description) do |val|
|
207
213
|
if option_type['type'] == 'checkbox'
|
208
214
|
val = (val.to_s != 'false' && val.to_s != 'off')
|
209
215
|
else
|
@@ -269,6 +275,11 @@ module Morpheus
|
|
269
275
|
build_standard_delete_options(opts, options, includes, excludes)
|
270
276
|
end
|
271
277
|
|
278
|
+
# number of decimal places to show with curreny
|
279
|
+
def default_sigdig
|
280
|
+
2
|
281
|
+
end
|
282
|
+
|
272
283
|
# appends to the passed OptionParser all the generic options
|
273
284
|
# @param opts [OptionParser] the option parser object being constructed
|
274
285
|
# @param options [Hash] the output Hash that is to being modified
|
@@ -309,6 +320,20 @@ module Morpheus
|
|
309
320
|
opts.add_hidden_option('-a, --account') if opts.is_a?(Morpheus::Cli::OptionParser)
|
310
321
|
opts.add_hidden_option('-A, --account-id') if opts.is_a?(Morpheus::Cli::OptionParser)
|
311
322
|
|
323
|
+
when :details
|
324
|
+
opts.on('-a', '--all', "Show all details." ) do
|
325
|
+
options[:details] = true
|
326
|
+
end
|
327
|
+
opts.on('--details', '--details', "Show more details" ) do
|
328
|
+
options[:details] = true
|
329
|
+
end
|
330
|
+
opts.add_hidden_option('--details')
|
331
|
+
|
332
|
+
when :sigdig
|
333
|
+
opts.on('--sigdig DIGITS', "Significant digits to display for prices (currency). Default is #{default_sigdig}.") do |val|
|
334
|
+
options[:sigdig] = val.to_i
|
335
|
+
end
|
336
|
+
|
312
337
|
when :options
|
313
338
|
options[:options] ||= {}
|
314
339
|
opts.on( '-O', '--option OPTION', "Option in the format -O field=\"value\"" ) do |option|
|
@@ -602,13 +627,13 @@ module Morpheus
|
|
602
627
|
end
|
603
628
|
# opts.add_hidden_option('-H') if opts.is_a?(Morpheus::Cli::OptionParser)
|
604
629
|
# opts.add_hidden_option('--header') if opts.is_a?(Morpheus::Cli::OptionParser)
|
605
|
-
opts.add_hidden_option('--
|
630
|
+
opts.add_hidden_option('-H, --header') if opts.is_a?(Morpheus::Cli::OptionParser)
|
606
631
|
|
607
632
|
#when :timeout
|
608
633
|
opts.on( '--timeout SECONDS', "Timeout for api requests. Default is typically 30 seconds." ) do |val|
|
609
634
|
options[:timeout] = val ? val.to_f : nil
|
610
635
|
end
|
611
|
-
|
636
|
+
opts.add_hidden_option('--timeout') if opts.is_a?(Morpheus::Cli::OptionParser)
|
612
637
|
|
613
638
|
when :auto_confirm
|
614
639
|
opts.on( '-y', '--yes', "Auto Confirm" ) do
|
@@ -715,7 +740,7 @@ module Morpheus
|
|
715
740
|
|
716
741
|
|
717
742
|
when :dry_run
|
718
|
-
opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it") do
|
743
|
+
opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it.") do
|
719
744
|
# todo: this should print after parsing obv..
|
720
745
|
# need a hook after parse! or a standard_handle(options) { ... } paradigm
|
721
746
|
# either that or hook it up in every command somehow, maybe a hook on connect()
|
@@ -727,7 +752,7 @@ module Morpheus
|
|
727
752
|
end
|
728
753
|
options[:dry_run] = true
|
729
754
|
end
|
730
|
-
opts.on(nil,'--curl', "
|
755
|
+
opts.on(nil,'--curl', "Curl, print the API request as a curl command instead of executing it.") do
|
731
756
|
# print once and dont munge json
|
732
757
|
if !options[:dry_run] && !options[:json]
|
733
758
|
puts "#{cyan}#{bold}#{dark}DRY RUN#{reset}"
|
@@ -830,10 +855,18 @@ module Morpheus
|
|
830
855
|
opts
|
831
856
|
end
|
832
857
|
|
858
|
+
def prog_name
|
859
|
+
self.class.prog_name
|
860
|
+
end
|
861
|
+
|
833
862
|
def command_name
|
834
863
|
self.class.command_name
|
835
864
|
end
|
836
865
|
|
866
|
+
def command_description
|
867
|
+
self.class.command_description
|
868
|
+
end
|
869
|
+
|
837
870
|
def subcommands
|
838
871
|
self.class.subcommands
|
839
872
|
end
|
@@ -870,14 +903,14 @@ module Morpheus
|
|
870
903
|
|
871
904
|
def usage
|
872
905
|
if !subcommands.empty?
|
873
|
-
"Usage:
|
906
|
+
"Usage: #{prog_name} #{command_name} [command] [options]"
|
874
907
|
else
|
875
|
-
"Usage:
|
908
|
+
"Usage: #{prog_name} #{command_name} [options]"
|
876
909
|
end
|
877
910
|
end
|
878
911
|
|
879
912
|
def my_help_command
|
880
|
-
"
|
913
|
+
"#{prog_name} #{command_name} --help"
|
881
914
|
end
|
882
915
|
|
883
916
|
def subcommand_usage(*extra)
|
@@ -888,7 +921,7 @@ module Morpheus
|
|
888
921
|
extra.shift
|
889
922
|
end
|
890
923
|
#extra = ["[options]"] if extra.empty?
|
891
|
-
"Usage:
|
924
|
+
"Usage: #{prog_name} #{command_name} #{subcommand_name} #{extra.join(' ')}".squeeze(' ').strip
|
892
925
|
end
|
893
926
|
|
894
927
|
# a string to describe the usage of your command
|
@@ -908,6 +941,10 @@ module Morpheus
|
|
908
941
|
out << "\n"
|
909
942
|
}
|
910
943
|
end
|
944
|
+
if command_description
|
945
|
+
out << "\n"
|
946
|
+
out << "#{command_description}\n"
|
947
|
+
end
|
911
948
|
# out << "\n"
|
912
949
|
out
|
913
950
|
end
|
@@ -939,7 +976,7 @@ module Morpheus
|
|
939
976
|
end
|
940
977
|
cmd_method = subcommands[subcommand_name]
|
941
978
|
if !cmd_method
|
942
|
-
error_msg = "'#{command_name} #{subcommand_name}' is not a
|
979
|
+
error_msg = "'#{command_name} #{subcommand_name}' is not a #{prog_name} command.\n#{full_command_usage}"
|
943
980
|
raise CommandNotFoundError.new(error_msg)
|
944
981
|
end
|
945
982
|
self.send(cmd_method, args[1..-1])
|
@@ -1295,6 +1332,10 @@ module Morpheus
|
|
1295
1332
|
|
1296
1333
|
module ClassMethods
|
1297
1334
|
|
1335
|
+
def prog_name
|
1336
|
+
"morpheus"
|
1337
|
+
end
|
1338
|
+
|
1298
1339
|
def set_command_name(cmd_name)
|
1299
1340
|
@command_name = cmd_name
|
1300
1341
|
Morpheus::Cli::CliRegistry.add(self, self.command_name)
|