morpheus-cli 2.12.5 → 3.1.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 +5 -0
- data/lib/morpheus/api/api_client.rb +15 -30
- data/lib/morpheus/api/app_templates_interface.rb +34 -7
- data/lib/morpheus/api/apps_interface.rb +20 -1
- data/lib/morpheus/api/archive_buckets_interface.rb +124 -0
- data/lib/morpheus/api/archive_files_interface.rb +182 -0
- data/lib/morpheus/api/{network_pools_interface.rb → image_builder_boot_scripts_interface.rb} +6 -6
- data/lib/morpheus/api/{policies_interface.rb → image_builder_image_builds_interface.rb} +20 -15
- data/lib/morpheus/api/image_builder_interface.rb +26 -0
- data/lib/morpheus/api/{network_proxies_interface.rb → image_builder_preseed_scripts_interface.rb} +6 -6
- data/lib/morpheus/cli.rb +10 -9
- data/lib/morpheus/cli/alias_command.rb +10 -9
- data/lib/morpheus/cli/app_templates.rb +1566 -457
- data/lib/morpheus/cli/apps.rb +284 -108
- data/lib/morpheus/cli/archives_command.rb +2184 -0
- data/lib/morpheus/cli/boot_scripts_command.rb +382 -0
- data/lib/morpheus/cli/cli_command.rb +9 -35
- data/lib/morpheus/cli/error_handler.rb +2 -0
- data/lib/morpheus/cli/hosts.rb +15 -3
- data/lib/morpheus/cli/image_builder_command.rb +1208 -0
- data/lib/morpheus/cli/instances.rb +118 -47
- data/lib/morpheus/cli/man_command.rb +27 -24
- data/lib/morpheus/cli/mixins/print_helper.rb +19 -5
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +20 -20
- data/lib/morpheus/cli/option_types.rb +45 -14
- data/lib/morpheus/cli/preseed_scripts_command.rb +381 -0
- data/lib/morpheus/cli/remote.rb +1 -0
- data/lib/morpheus/cli/roles.rb +2 -2
- data/lib/morpheus/cli/shell.rb +3 -2
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/ext/hash.rb +22 -0
- data/lib/morpheus/formatters.rb +33 -0
- data/lib/morpheus/terminal.rb +1 -1
- metadata +13 -21
- data/lib/morpheus/api/cloud_policies_interface.rb +0 -47
- data/lib/morpheus/api/group_policies_interface.rb +0 -47
- data/lib/morpheus/api/network_domains_interface.rb +0 -47
- data/lib/morpheus/api/network_groups_interface.rb +0 -47
- data/lib/morpheus/api/network_pool_servers_interface.rb +0 -47
- data/lib/morpheus/api/network_services_interface.rb +0 -47
- data/lib/morpheus/api/networks_interface.rb +0 -54
- data/lib/morpheus/cli/network_domains_command.rb +0 -571
- data/lib/morpheus/cli/network_groups_command.rb +0 -602
- data/lib/morpheus/cli/network_pool_servers_command.rb +0 -430
- data/lib/morpheus/cli/network_pools_command.rb +0 -495
- data/lib/morpheus/cli/network_proxies_command.rb +0 -594
- data/lib/morpheus/cli/network_services_command.rb +0 -148
- data/lib/morpheus/cli/networks_command.rb +0 -855
- data/lib/morpheus/cli/policies_command.rb +0 -847
- data/scripts/generate_morpheus_commands_help.morpheus +0 -1313
data/lib/morpheus/cli/apps.rb
CHANGED
@@ -36,11 +36,17 @@ class Morpheus::Cli::Apps
|
|
36
36
|
|
37
37
|
def list(args)
|
38
38
|
options = {}
|
39
|
-
optparse = OptionParser.new do|opts|
|
39
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
40
40
|
opts.banner = subcommand_usage()
|
41
41
|
build_common_options(opts, options, [:list, :json, :dry_run])
|
42
|
+
opts.footer = "List apps."
|
42
43
|
end
|
43
44
|
optparse.parse!(args)
|
45
|
+
if args.count != 0
|
46
|
+
print_error Morpheus::Terminal.angry_prompt
|
47
|
+
puts_error "#{command_name} list expects 0 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
48
|
+
return 1
|
49
|
+
end
|
44
50
|
connect(options)
|
45
51
|
begin
|
46
52
|
params = {}
|
@@ -87,51 +93,113 @@ class Morpheus::Cli::Apps
|
|
87
93
|
|
88
94
|
def add(args)
|
89
95
|
options = {}
|
90
|
-
optparse = OptionParser.new do|opts|
|
91
|
-
opts.banner = subcommand_usage("[name]")
|
92
|
-
|
96
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
97
|
+
opts.banner = subcommand_usage("[name] [options]")
|
93
98
|
build_option_type_options(opts, options, add_app_option_types(false))
|
94
|
-
opts.on( '-
|
95
|
-
|
99
|
+
# opts.on( '-t', '--template ID', "App Template ID. The app template to use. The default value is 'existing' which means no template, for creating a blank app and adding existing instances." ) do |val|
|
100
|
+
# options['template'] = val
|
101
|
+
# end
|
102
|
+
# opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
|
103
|
+
# options[:group] = val
|
104
|
+
# end
|
105
|
+
# opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID." ) do |val|
|
106
|
+
# options[:cloud] = val
|
107
|
+
# end
|
108
|
+
opts.on('--config JSON', String, "App Config JSON") do |val|
|
109
|
+
options['config'] = JSON.parse(val.to_s)
|
110
|
+
end
|
111
|
+
opts.on('--config-yaml YAML', String, "App Config YAML") do |val|
|
112
|
+
options['config'] = YAML.load(val.to_s)
|
113
|
+
end
|
114
|
+
opts.on('--config-file FILE', String, "App Config from a local JSON or YAML file") do |val|
|
115
|
+
options['configFile'] = val.to_s
|
96
116
|
end
|
97
117
|
build_common_options(opts, options, [:options, :json, :dry_run, :quiet])
|
118
|
+
opts.footer = "Create a new app.\n" +
|
119
|
+
"[name] is required. This is the name of the new app. It may also be passed as --name or inside your config."
|
98
120
|
end
|
99
121
|
optparse.parse!(args)
|
122
|
+
if args.count > 1
|
123
|
+
print_error Morpheus::Terminal.angry_prompt
|
124
|
+
puts_error "#{command_name} add expects 0-1 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
125
|
+
return 1
|
126
|
+
end
|
100
127
|
connect(options)
|
101
128
|
begin
|
102
129
|
options[:options] ||= {}
|
103
|
-
|
104
|
-
options[:options]['group'] ||= options[:group] || @active_group_id
|
105
|
-
# support [name] as first argument still
|
106
|
-
if args[0]
|
130
|
+
if args[0] && !options[:options]['name']
|
107
131
|
options[:options]['name'] = args[0]
|
108
132
|
end
|
133
|
+
# options[:options]['template'] ||= options['template']
|
134
|
+
if options[:group] # || @active_group_id
|
135
|
+
options[:options]['group'] ||= options[:group] # || @active_group_id
|
136
|
+
end
|
109
137
|
|
110
|
-
payload = {
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
138
|
+
payload = {}
|
139
|
+
config_payload = {}
|
140
|
+
if options['config']
|
141
|
+
config_payload = options['config']
|
142
|
+
payload = config_payload
|
143
|
+
elsif options['configFile']
|
144
|
+
config_file = File.expand_path(options['configFile'])
|
145
|
+
if !File.exists?(config_file) || !File.file?(config_file)
|
146
|
+
print_red_alert "File not found: #{config_file}"
|
147
|
+
return false
|
148
|
+
end
|
149
|
+
if config_file =~ /\.ya?ml\Z/
|
150
|
+
config_payload = YAML.load_file(config_file)
|
151
|
+
else
|
152
|
+
config_payload = JSON.parse(File.read(config_file))
|
153
|
+
end
|
154
|
+
payload = config_payload
|
155
|
+
else
|
156
|
+
# prompt for Name, Description, Group, Environment
|
157
|
+
payload = {}
|
158
|
+
params = Morpheus::Cli::OptionTypes.prompt(add_app_option_types, options[:options], @api_client, options[:params])
|
159
|
+
params = params.deep_compact! # remove nulls and blank strings
|
160
|
+
group = find_group_by_name_or_id_for_provisioning(params.delete('group'))
|
161
|
+
return if group.nil?
|
162
|
+
payload.merge!(params)
|
163
|
+
payload['group'] = {id: group['id'], name: group['name']}
|
164
|
+
end
|
165
|
+
|
166
|
+
# allow creating a blank app by default
|
167
|
+
# sux having go merge this into user passed config/configFile
|
168
|
+
# but it's better than making them know to enter it.
|
169
|
+
if !payload['id']
|
170
|
+
payload['id'] = 'existing'
|
171
|
+
payload['templateName'] = 'Existing Instances'
|
172
|
+
else
|
173
|
+
# maybe validate template id
|
174
|
+
# app_template = find_app_template_by_id(payload['id'])
|
175
|
+
end
|
119
176
|
|
120
177
|
if options[:dry_run]
|
121
178
|
print_dry_run @apps_interface.dry.create(payload)
|
122
179
|
return
|
123
180
|
end
|
181
|
+
|
124
182
|
json_response = @apps_interface.create(payload)
|
183
|
+
|
125
184
|
if options[:json]
|
126
|
-
|
185
|
+
puts as_json(json_response, options)
|
127
186
|
print "\n"
|
128
187
|
elsif !options[:quiet]
|
129
|
-
|
130
|
-
|
131
|
-
#
|
132
|
-
|
188
|
+
app = json_response["app"]
|
189
|
+
print_green_success "Added app #{app['name']}"
|
190
|
+
# add existing instances to blank app now?
|
191
|
+
if !options[:no_prompt] && !payload['tiers']
|
192
|
+
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to add an instance now?", options.merge({default: false}))
|
193
|
+
add_instance([app['id']])
|
194
|
+
while ::Morpheus::Cli::OptionTypes::confirm("Add another instance?", options.merge({default: false})) do
|
195
|
+
add_instance([app['id']])
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
# print details
|
200
|
+
get([app['id']])
|
133
201
|
end
|
134
|
-
|
202
|
+
return 0
|
135
203
|
rescue RestClient::Exception => e
|
136
204
|
print_rest_exception(e, options)
|
137
205
|
exit 1
|
@@ -140,14 +208,17 @@ class Morpheus::Cli::Apps
|
|
140
208
|
|
141
209
|
def get(args)
|
142
210
|
options = {}
|
143
|
-
optparse = OptionParser.new do|opts|
|
144
|
-
opts.banner = subcommand_usage("[
|
211
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
212
|
+
opts.banner = subcommand_usage("[app]")
|
145
213
|
build_common_options(opts, options, [:json, :dry_run])
|
214
|
+
opts.footer = "Get details about an app.\n" +
|
215
|
+
"[app] is required. This is the name or id of an app."
|
146
216
|
end
|
147
217
|
optparse.parse!(args)
|
148
|
-
if args.count
|
149
|
-
|
150
|
-
|
218
|
+
if args.count != 1
|
219
|
+
print_error Morpheus::Terminal.angry_prompt
|
220
|
+
puts_error "#{command_name} get expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
221
|
+
return 1
|
151
222
|
end
|
152
223
|
connect(options)
|
153
224
|
begin
|
@@ -225,15 +296,18 @@ class Morpheus::Cli::Apps
|
|
225
296
|
|
226
297
|
def update(args)
|
227
298
|
options = {}
|
228
|
-
optparse = OptionParser.new do|opts|
|
229
|
-
opts.banner = subcommand_usage("[
|
299
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
300
|
+
opts.banner = subcommand_usage("[app] [options]")
|
230
301
|
build_option_type_options(opts, options, update_app_option_types(false))
|
231
302
|
build_common_options(opts, options, [:options, :json, :dry_run])
|
303
|
+
opts.footer = "Update an app.\n" +
|
304
|
+
"[app] is required. This is the name or id of an app."
|
232
305
|
end
|
233
306
|
optparse.parse!(args)
|
234
|
-
if args.count
|
235
|
-
|
236
|
-
|
307
|
+
if args.count != 1
|
308
|
+
print_error Morpheus::Terminal.angry_prompt
|
309
|
+
puts_error "#{command_name} update expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
310
|
+
return 1
|
237
311
|
end
|
238
312
|
connect(options)
|
239
313
|
|
@@ -253,7 +327,7 @@ class Morpheus::Cli::Apps
|
|
253
327
|
end
|
254
328
|
|
255
329
|
#puts "parsed params is : #{params.inspect}"
|
256
|
-
app_keys = ['name', 'description']
|
330
|
+
app_keys = ['name', 'description', 'environment']
|
257
331
|
params = params.select {|k,v| app_keys.include?(k) }
|
258
332
|
payload['app'].merge!(params)
|
259
333
|
|
@@ -282,14 +356,19 @@ class Morpheus::Cli::Apps
|
|
282
356
|
|
283
357
|
def add_instance(args)
|
284
358
|
options = {}
|
285
|
-
optparse = OptionParser.new do|opts|
|
286
|
-
opts.banner = subcommand_usage("[
|
359
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
360
|
+
opts.banner = subcommand_usage("[app] [instance] [tier]")
|
287
361
|
build_common_options(opts, options, [:options, :json, :dry_run])
|
362
|
+
opts.footer = "Add an existing instance to an app.\n" +
|
363
|
+
"[app] is required. This is the name or id of an app." + "\n" +
|
364
|
+
"[instance] is required. This is the name or id of an instance." + "\n" +
|
365
|
+
"[tier] is required. This is the name of the tier."
|
288
366
|
end
|
289
367
|
optparse.parse!(args)
|
290
|
-
if args.count < 1
|
291
|
-
|
292
|
-
|
368
|
+
if args.count < 1 || args.count > 3
|
369
|
+
print_error Morpheus::Terminal.angry_prompt
|
370
|
+
puts_error "#{command_name} add-instance expects 1-3 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
371
|
+
return 1
|
293
372
|
end
|
294
373
|
# optional [tier] and [instance] arguments
|
295
374
|
if args[1] && args[1] !~ /\A\-/
|
@@ -331,11 +410,9 @@ class Morpheus::Cli::Apps
|
|
331
410
|
print "\n"
|
332
411
|
else
|
333
412
|
print_green_success "Added instance #{instance['name']} to app #{app['name']}"
|
334
|
-
|
335
|
-
# details_options = [app['name']]
|
336
|
-
# details(details_options)
|
413
|
+
#get(app['id'])
|
337
414
|
end
|
338
|
-
|
415
|
+
return 0
|
339
416
|
rescue RestClient::Exception => e
|
340
417
|
print_rest_exception(e, options)
|
341
418
|
exit 1
|
@@ -344,27 +421,46 @@ class Morpheus::Cli::Apps
|
|
344
421
|
|
345
422
|
def remove(args)
|
346
423
|
options = {}
|
347
|
-
|
348
|
-
|
424
|
+
query_params = {keepBackups: 'off', force: 'off'}
|
425
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
426
|
+
opts.banner = subcommand_usage("[app] [-fB]")
|
427
|
+
opts.on( '-f', '--force', "Force Delete" ) do
|
428
|
+
query_params[:force] = 'on'
|
429
|
+
end
|
430
|
+
opts.on( '-B', '--keep-backups', "Preserve copy of backups" ) do
|
431
|
+
query_params[:keepBackups] = 'on'
|
432
|
+
end
|
433
|
+
opts.on('--remove-instances [on|off]', ['on','off'], "Remove instances. Default is on.") do |val|
|
434
|
+
query_params[:removeInstances] = val
|
435
|
+
end
|
436
|
+
opts.on('--remove-volumes [on|off]', ['on','off'], "Remove Volumes. Default is on. Applies to certain types only.") do |val|
|
437
|
+
query_params[:removeVolumes] = val
|
438
|
+
end
|
439
|
+
opts.on('--releaseEIPs', ['on','off'], "Release EIPs. Default is false. Applies to Amazon only.") do |val|
|
440
|
+
query_params[:releaseEIPs] = val
|
441
|
+
end
|
349
442
|
build_common_options(opts, options, [:json, :dry_run, :quiet, :auto_confirm])
|
443
|
+
opts.footer = "Delete an app.\n" +
|
444
|
+
"[app] is required. This is the name or id of an app."
|
350
445
|
end
|
351
446
|
optparse.parse!(args)
|
352
|
-
if args.count
|
353
|
-
|
354
|
-
|
447
|
+
if args.count != 1
|
448
|
+
print_error Morpheus::Terminal.angry_prompt
|
449
|
+
puts_error "#{command_name} remove expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
450
|
+
return 1
|
355
451
|
end
|
356
452
|
connect(options)
|
357
453
|
|
358
454
|
begin
|
359
455
|
app = find_app_by_name_or_id(args[0])
|
360
456
|
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the app '#{app['name']}'?", options)
|
361
|
-
|
457
|
+
return 9
|
362
458
|
end
|
363
459
|
if options[:dry_run]
|
364
|
-
print_dry_run @apps_interface.dry.destroy(app['id'])
|
460
|
+
print_dry_run @apps_interface.dry.destroy(app['id'], query_params)
|
365
461
|
return
|
366
462
|
end
|
367
|
-
json_response = @apps_interface.destroy(app['id'])
|
463
|
+
json_response = @apps_interface.destroy(app['id'], query_params)
|
368
464
|
if options[:json]
|
369
465
|
print JSON.pretty_generate(json_response)
|
370
466
|
print "\n"
|
@@ -380,14 +476,18 @@ class Morpheus::Cli::Apps
|
|
380
476
|
|
381
477
|
def remove_instance(args)
|
382
478
|
options = {}
|
383
|
-
optparse = OptionParser.new do|opts|
|
384
|
-
opts.banner = subcommand_usage("[
|
479
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
480
|
+
opts.banner = subcommand_usage("[app] [instance]")
|
385
481
|
build_common_options(opts, options, [:options, :json, :dry_run])
|
482
|
+
opts.footer = "Remove an instance from an app.\n" +
|
483
|
+
"[app] is required. This is the name or id of an app." + "\n" +
|
484
|
+
"[instance] is required. This is the name or id of an instance."
|
386
485
|
end
|
387
486
|
optparse.parse!(args)
|
388
|
-
if args.count < 1
|
389
|
-
|
390
|
-
|
487
|
+
if args.count < 1 || args.count > 2
|
488
|
+
print_error Morpheus::Terminal.angry_prompt
|
489
|
+
puts_error "#{command_name} remove-instance expects 1-2 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
490
|
+
return 1
|
391
491
|
end
|
392
492
|
# optional [tier] and [instance] arguments
|
393
493
|
if args[1] && args[1] !~ /\A\-/
|
@@ -432,14 +532,17 @@ class Morpheus::Cli::Apps
|
|
432
532
|
|
433
533
|
def logs(args)
|
434
534
|
options = {}
|
435
|
-
optparse = OptionParser.new do|opts|
|
436
|
-
opts.banner = subcommand_usage("[
|
535
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
536
|
+
opts.banner = subcommand_usage("[app]")
|
437
537
|
build_common_options(opts, options, [:list, :json, :dry_run])
|
538
|
+
opts.footer = "List logs for an app.\n" +
|
539
|
+
"[app] is required. This is the name or id of an app."
|
438
540
|
end
|
439
541
|
optparse.parse!(args)
|
440
|
-
if args.count
|
441
|
-
|
442
|
-
|
542
|
+
if args.count !=1
|
543
|
+
print_error Morpheus::Terminal.angry_prompt
|
544
|
+
puts_error "#{command_name} logs expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
545
|
+
return 1
|
443
546
|
end
|
444
547
|
connect(options)
|
445
548
|
begin
|
@@ -454,15 +557,23 @@ class Morpheus::Cli::Apps
|
|
454
557
|
[:phrase, :offset, :max, :sort, :direction].each do |k|
|
455
558
|
params[k] = options[k] unless options[k].nil?
|
456
559
|
end
|
560
|
+
params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
457
561
|
if options[:dry_run]
|
458
562
|
print_dry_run @logs_interface.dry.container_logs(containers, params)
|
459
563
|
return
|
460
564
|
end
|
461
565
|
logs = @logs_interface.container_logs(containers, params)
|
462
566
|
if options[:json]
|
463
|
-
|
464
|
-
|
567
|
+
puts as_json(logs, options)
|
568
|
+
return 0
|
465
569
|
else
|
570
|
+
title = "App Logs: #{app['name']}"
|
571
|
+
subtitles = []
|
572
|
+
if params[:query]
|
573
|
+
subtitles << "Search: #{params[:query]}".strip
|
574
|
+
end
|
575
|
+
# todo: startMs, endMs, sorts insteaad of sort..etc
|
576
|
+
print_h1 title, subtitles
|
466
577
|
logs['data'].reverse.each do |log_entry|
|
467
578
|
log_level = ''
|
468
579
|
case log_entry['level']
|
@@ -477,9 +588,10 @@ class Morpheus::Cli::Apps
|
|
477
588
|
when 'FATAL'
|
478
589
|
log_level = "#{red}#{bold}FATAL#{reset}"
|
479
590
|
end
|
480
|
-
puts "[#{log_entry['ts']}] #{log_level} - #{log_entry['message']}"
|
591
|
+
puts "[#{log_entry['ts']}] #{log_level} - #{log_entry['message'].to_s.strip}"
|
481
592
|
end
|
482
593
|
print reset,"\n"
|
594
|
+
return 0
|
483
595
|
end
|
484
596
|
rescue RestClient::Exception => e
|
485
597
|
print_rest_exception(e, options)
|
@@ -490,14 +602,15 @@ class Morpheus::Cli::Apps
|
|
490
602
|
=begin
|
491
603
|
def stop(args)
|
492
604
|
options = {}
|
493
|
-
optparse = OptionParser.new do|opts|
|
494
|
-
opts.banner = subcommand_usage("[
|
605
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
606
|
+
opts.banner = subcommand_usage("[app]")
|
495
607
|
build_common_options(opts, options, [:json, :dry_run])
|
496
608
|
end
|
497
609
|
optparse.parse!(args)
|
498
|
-
if args.count
|
499
|
-
|
500
|
-
|
610
|
+
if args.count != 1
|
611
|
+
print_error Morpheus::Terminal.angry_prompt
|
612
|
+
puts_error "#{command_name} stop expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
613
|
+
return 1
|
501
614
|
end
|
502
615
|
connect(options)
|
503
616
|
begin
|
@@ -516,14 +629,15 @@ class Morpheus::Cli::Apps
|
|
516
629
|
|
517
630
|
def start(args)
|
518
631
|
options = {}
|
519
|
-
optparse = OptionParser.new do|opts|
|
520
|
-
opts.banner = subcommand_usage("[
|
632
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
633
|
+
opts.banner = subcommand_usage("[app]")
|
521
634
|
build_common_options(opts, options, [:json, :dry_run])
|
522
635
|
end
|
523
636
|
optparse.parse!(args)
|
524
|
-
if args.count
|
525
|
-
|
526
|
-
|
637
|
+
if args.count != 1
|
638
|
+
print_error Morpheus::Terminal.angry_prompt
|
639
|
+
puts_error "#{command_name} start expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
640
|
+
return 1
|
527
641
|
end
|
528
642
|
connect(options)
|
529
643
|
begin
|
@@ -542,14 +656,15 @@ class Morpheus::Cli::Apps
|
|
542
656
|
|
543
657
|
def restart(args)
|
544
658
|
options = {}
|
545
|
-
optparse = OptionParser.new do|opts|
|
546
|
-
opts.banner = subcommand_usage("[
|
659
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
660
|
+
opts.banner = subcommand_usage("[app]")
|
547
661
|
build_common_options(opts, options, [:json, :dry_run])
|
548
662
|
end
|
549
663
|
optparse.parse!(args)
|
550
|
-
if args.count
|
551
|
-
|
552
|
-
|
664
|
+
if args.count != 1
|
665
|
+
print_error Morpheus::Terminal.angry_prompt
|
666
|
+
puts_error "#{command_name} restart expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
667
|
+
return 1
|
553
668
|
end
|
554
669
|
connect(options)
|
555
670
|
begin
|
@@ -569,14 +684,15 @@ class Morpheus::Cli::Apps
|
|
569
684
|
|
570
685
|
def firewall_disable(args)
|
571
686
|
options = {}
|
572
|
-
optparse = OptionParser.new do|opts|
|
573
|
-
opts.banner = subcommand_usage("[
|
687
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
688
|
+
opts.banner = subcommand_usage("[app]")
|
574
689
|
build_common_options(opts, options, [:json, :dry_run])
|
575
690
|
end
|
576
691
|
optparse.parse!(args)
|
577
|
-
if args.count
|
578
|
-
|
579
|
-
|
692
|
+
if args.count != 1
|
693
|
+
print_error Morpheus::Terminal.angry_prompt
|
694
|
+
puts_error "#{command_name} firewall-disable expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
695
|
+
return 1
|
580
696
|
end
|
581
697
|
connect(options)
|
582
698
|
|
@@ -596,14 +712,15 @@ class Morpheus::Cli::Apps
|
|
596
712
|
|
597
713
|
def firewall_enable(args)
|
598
714
|
options = {}
|
599
|
-
optparse = OptionParser.new do|opts|
|
600
|
-
opts.banner = subcommand_usage("[
|
715
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
716
|
+
opts.banner = subcommand_usage("[app]")
|
601
717
|
build_common_options(opts, options, [:json, :dry_run])
|
602
718
|
end
|
603
719
|
optparse.parse!(args)
|
604
|
-
if args.count
|
605
|
-
|
606
|
-
|
720
|
+
if args.count != 1
|
721
|
+
print_error Morpheus::Terminal.angry_prompt
|
722
|
+
puts_error "#{command_name} firewall-enable expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
723
|
+
return 1
|
607
724
|
end
|
608
725
|
connect(options)
|
609
726
|
|
@@ -623,14 +740,15 @@ class Morpheus::Cli::Apps
|
|
623
740
|
|
624
741
|
def security_groups(args)
|
625
742
|
options = {}
|
626
|
-
optparse = OptionParser.new do|opts|
|
627
|
-
opts.banner = subcommand_usage("[
|
743
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
744
|
+
opts.banner = subcommand_usage("[app]")
|
628
745
|
build_common_options(opts, options, [:json, :dry_run])
|
629
746
|
end
|
630
747
|
optparse.parse!(args)
|
631
|
-
if args.count
|
632
|
-
|
633
|
-
|
748
|
+
if args.count != 1
|
749
|
+
print_error Morpheus::Terminal.angry_prompt
|
750
|
+
puts_error "#{command_name} security-groups expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
751
|
+
return 1
|
634
752
|
end
|
635
753
|
connect(options)
|
636
754
|
|
@@ -646,7 +764,7 @@ class Morpheus::Cli::Apps
|
|
646
764
|
print cyan
|
647
765
|
print_description_list({"Firewall Enabled" => lambda {|it| format_boolean it['firewallEnabled'] } }, json_response)
|
648
766
|
if securityGroups.empty?
|
649
|
-
print
|
767
|
+
print cyan,"\n","No security groups currently applied.",reset,"\n"
|
650
768
|
else
|
651
769
|
print "\n"
|
652
770
|
securityGroups.each do |securityGroup|
|
@@ -664,8 +782,8 @@ class Morpheus::Cli::Apps
|
|
664
782
|
def apply_security_groups(args)
|
665
783
|
options = {}
|
666
784
|
clear_or_secgroups_specified = false
|
667
|
-
optparse = OptionParser.new do|opts|
|
668
|
-
opts.banner = subcommand_usage("[
|
785
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
786
|
+
opts.banner = subcommand_usage("[app] [--clear] [-s]")
|
669
787
|
opts.on( '-c', '--clear', "Clear all security groups" ) do
|
670
788
|
options[:securityGroupIds] = []
|
671
789
|
clear_or_secgroups_specified = true
|
@@ -681,13 +799,15 @@ class Morpheus::Cli::Apps
|
|
681
799
|
build_common_options(opts, options, [:json, :dry_run])
|
682
800
|
end
|
683
801
|
optparse.parse!(args)
|
684
|
-
if args.count
|
685
|
-
|
686
|
-
|
802
|
+
if args.count != 1
|
803
|
+
print_error Morpheus::Terminal.angry_prompt
|
804
|
+
puts_error "#{command_name} apply-security-groups expects 1 argument and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
805
|
+
return 1
|
687
806
|
end
|
688
807
|
if !clear_or_secgroups_specified
|
689
|
-
|
690
|
-
|
808
|
+
print_error Morpheus::Terminal.angry_prompt
|
809
|
+
puts_error "#{command_name} apply-security-groups requires either --clear or --secgroups\n#{optparse}"
|
810
|
+
return 1
|
691
811
|
end
|
692
812
|
|
693
813
|
connect(options)
|
@@ -710,15 +830,17 @@ class Morpheus::Cli::Apps
|
|
710
830
|
|
711
831
|
def add_app_option_types(connected=true)
|
712
832
|
[
|
833
|
+
{'fieldName' => 'template', 'fieldLabel' => 'Template', 'type' => 'select', 'selectOptions' => (connected ? get_available_app_templates() : []), 'required' => true, 'defaultValue' => 'existing', 'description' => "The app template to use. The default value is 'existing' which means no template, for creating a blank app and adding existing instances."},
|
713
834
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this app'},
|
714
835
|
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
|
715
836
|
{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => (connected ? get_available_groups() : []), 'required' => true},
|
837
|
+
{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'text', 'required' => false},
|
716
838
|
]
|
717
839
|
end
|
718
840
|
|
719
841
|
def update_app_option_types(connected=true)
|
720
842
|
list = add_app_option_types(connected)
|
721
|
-
list = list.reject {|it| ["group"].include? it['fieldName'] }
|
843
|
+
list = list.reject {|it| ["template", "group"].include? it['fieldName'] }
|
722
844
|
list.each {|it| it['required'] = false }
|
723
845
|
list
|
724
846
|
end
|
@@ -750,11 +872,16 @@ class Morpheus::Cli::Apps
|
|
750
872
|
end
|
751
873
|
|
752
874
|
def print_apps_table(apps, opts={})
|
753
|
-
|
875
|
+
|
754
876
|
table_color = opts[:color] || cyan
|
755
877
|
rows = apps.collect do |app|
|
756
878
|
instances_str = (app['instanceCount'].to_i == 1) ? "1 Instance" : "#{app['instanceCount']} Instances"
|
757
879
|
containers_str = (app['containerCount'].to_i == 1) ? "1 Container" : "#{app['containerCount']} Containers"
|
880
|
+
stats = app['stats']
|
881
|
+
# app_stats = app['appStats']
|
882
|
+
cpu_usage_str = !stats ? "" : generate_usage_bar((stats['cpuUsage'] || stats['cpuUsagePeak']).to_f, 100, {max_bars: 10})
|
883
|
+
memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
|
884
|
+
storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
|
758
885
|
{
|
759
886
|
id: app['id'],
|
760
887
|
name: app['name'],
|
@@ -762,11 +889,14 @@ class Morpheus::Cli::Apps
|
|
762
889
|
containers: containers_str,
|
763
890
|
account: app['account'] ? app['account']['name'] : nil,
|
764
891
|
status: format_app_status(app, table_color),
|
892
|
+
cpu: cpu_usage_str + cyan,
|
893
|
+
memory: memory_usage_str + table_color,
|
894
|
+
storage: storage_usage_str + table_color
|
765
895
|
#dateCreated: format_local_dt(app['dateCreated'])
|
766
896
|
}
|
767
897
|
end
|
768
|
-
|
769
|
-
|
898
|
+
|
899
|
+
columns = [
|
770
900
|
:id,
|
771
901
|
:name,
|
772
902
|
:instances,
|
@@ -775,6 +905,20 @@ class Morpheus::Cli::Apps
|
|
775
905
|
:status,
|
776
906
|
#{:dateCreated => {:display_name => "Date Created"} }
|
777
907
|
]
|
908
|
+
term_width = current_terminal_width()
|
909
|
+
if term_width > 120
|
910
|
+
columns += [
|
911
|
+
{:cpu => {:display_name => "MAX CPU"} },
|
912
|
+
:memory,
|
913
|
+
:storage
|
914
|
+
]
|
915
|
+
end
|
916
|
+
# custom pretty table columns ...
|
917
|
+
# if options[:include_fields]
|
918
|
+
# columns = options[:include_fields]
|
919
|
+
# end
|
920
|
+
# print cyan
|
921
|
+
print as_pretty_table(rows, columns, opts) #{color: table_color}
|
778
922
|
print reset
|
779
923
|
end
|
780
924
|
|
@@ -795,4 +939,36 @@ class Morpheus::Cli::Apps
|
|
795
939
|
end
|
796
940
|
out
|
797
941
|
end
|
942
|
+
|
943
|
+
def get_available_app_templates(refresh=false)
|
944
|
+
if !@available_app_templates || refresh
|
945
|
+
results = @options_interface.options_for_source('appTemplates',{})
|
946
|
+
@available_app_templates = results['data'].collect {|it|
|
947
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"]}
|
948
|
+
}
|
949
|
+
default_option = {"id" => "existing", "name" => "Existing Instances", "value" => "existing"}
|
950
|
+
@available_app_templates.unshift(default_option)
|
951
|
+
end
|
952
|
+
#puts "get_available_app_templates() rtn: #{@available_app_templates.inspect}"
|
953
|
+
return @available_app_templates
|
954
|
+
end
|
955
|
+
|
956
|
+
def get_available_environments(refresh=false)
|
957
|
+
if !@available_environments || refresh
|
958
|
+
# results = @options_interface.options_for_source('environments',{})
|
959
|
+
# @available_environments = results['data'].collect {|it|
|
960
|
+
# {"id" => it["value"], "name" => it["name"], "value" => it["value"]}
|
961
|
+
# }
|
962
|
+
# todo: api call
|
963
|
+
@available_environments = [
|
964
|
+
{'name' => 'Dev', 'value' => 'Dev'},
|
965
|
+
{'name' => 'Test', 'value' => 'Test'},
|
966
|
+
{'name' => 'Staging', 'value' => 'Staging'},
|
967
|
+
{'name' => 'Production', 'value' => 'Production'}
|
968
|
+
]
|
969
|
+
end
|
970
|
+
#puts "get_available_environments() rtn: #{@available_environments.inspect}"
|
971
|
+
return @available_environments
|
972
|
+
end
|
973
|
+
|
798
974
|
end
|