morpheus-cli 4.2.21 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +30 -0
- data/lib/morpheus/api/billing_interface.rb +34 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +9 -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/rest_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +14 -0
- 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 +7 -3
- data/lib/morpheus/cli/apps.rb +6 -27
- data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
- data/lib/morpheus/cli/backups_command.rb +3 -0
- data/lib/morpheus/cli/catalog_item_types_command.rb +622 -0
- data/lib/morpheus/cli/cli_command.rb +70 -21
- data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -12
- data/lib/morpheus/cli/commands/standard/history_command.rb +3 -1
- data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
- 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 -24
- data/lib/morpheus/cli/cypher_command.rb +6 -2
- 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 +265 -34
- data/lib/morpheus/cli/instances.rb +186 -100
- data/lib/morpheus/cli/invoices_command.rb +33 -16
- data/lib/morpheus/cli/jobs_command.rb +28 -6
- data/lib/morpheus/cli/library_option_lists_command.rb +15 -7
- data/lib/morpheus/cli/library_option_types_command.rb +5 -2
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +12 -7
- data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
- data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -3
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +46 -21
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +100 -4
- data/lib/morpheus/cli/network_pools_command.rb +14 -6
- data/lib/morpheus/cli/option_types.rb +271 -22
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/remote.rb +35 -12
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/roles.rb +453 -113
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
- data/lib/morpheus/cli/service_plans_command.rb +2 -2
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +33 -11
- data/lib/morpheus/cli/storage_providers_command.rb +40 -56
- data/lib/morpheus/cli/tasks.rb +29 -32
- data/lib/morpheus/cli/usage_command.rb +203 -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/cli/virtual_images.rb +429 -254
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +34 -41
- data/lib/morpheus/formatters.rb +75 -7
- data/lib/morpheus/terminal.rb +6 -2
- metadata +14 -2
@@ -102,15 +102,15 @@ class Morpheus::Cli::JobsCommand
|
|
102
102
|
if stats = json_response['stats']
|
103
103
|
label_width = 17
|
104
104
|
|
105
|
-
print_h2 "
|
105
|
+
print_h2 "Execution Stats - Last 7 Days"
|
106
106
|
print cyan
|
107
107
|
|
108
108
|
print "Jobs".rjust(label_width, ' ') + ": #{stats['jobCount']}\n"
|
109
109
|
print "Executions Today".rjust(label_width, ' ') + ": #{stats['todayCount']}\n"
|
110
110
|
print "Daily Executions".rjust(label_width, ' ') + ": " + stats['executionsPerDay'].join(' | ') + "\n"
|
111
111
|
print "Total Executions".rjust(label_width, ' ') + ": #{stats['execCount']}\n"
|
112
|
-
print "Completed".rjust(label_width, ' ') + ": " + generate_usage_bar(stats['execSuccessRate'].to_f, 100) + "#{stats['execSuccess']}".rjust(15, ' ') + " of " + "#{stats['execCount']}".ljust(15, ' ') + "\n#{cyan}"
|
113
|
-
print "Failed".rjust(label_width, ' ') + ": " + generate_usage_bar(stats['execFailedRate'].to_f, 100) + "#{stats['execFailed']}".rjust(15, ' ') + " of " + "#{stats['execCount']}".ljust(15, ' ') + "\n#{cyan}"
|
112
|
+
print "Completed".rjust(label_width, ' ') + ": " + generate_usage_bar(stats['execSuccessRate'].to_f, 100, {bar_color:green}) + "#{stats['execSuccess']}".rjust(15, ' ') + " of " + "#{stats['execCount']}".ljust(15, ' ') + "\n#{cyan}"
|
113
|
+
print "Failed".rjust(label_width, ' ') + ": " + generate_usage_bar(stats['execFailedRate'].to_f, 100, {bar_color:red}) + "#{stats['execFailed']}".rjust(15, ' ') + " of " + "#{stats['execCount']}".ljust(15, ' ') + "\n#{cyan}"
|
114
114
|
end
|
115
115
|
print reset,"\n"
|
116
116
|
end
|
@@ -304,7 +304,7 @@ class Morpheus::Cli::JobsCommand
|
|
304
304
|
job_options = @jobs_interface.options(job_type_id)
|
305
305
|
|
306
306
|
# prompt task / workflow
|
307
|
-
if
|
307
|
+
if ['morpheus.task.jobType', 'morpheus.task'].include?(job_type['code'])
|
308
308
|
params['task'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'task.id', 'fieldLabel' => 'Task', 'type' => 'select', 'required' => true, 'optionSource' => 'tasks'}], options[:options], @api_client, {})['task']
|
309
309
|
else
|
310
310
|
params['workflow'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'workflow.id', 'fieldLabel' => 'Workflow', 'type' => 'select', 'required' => true, 'optionSource' => 'operationTaskSets'}], options[:options], @api_client, {})['workflow']
|
@@ -320,10 +320,11 @@ class Morpheus::Cli::JobsCommand
|
|
320
320
|
exit 1
|
321
321
|
end
|
322
322
|
params['task'] = {'id' => task['id']}
|
323
|
-
job_type_id = load_job_type_id_by_code('morpheus.task')
|
323
|
+
job_type_id = load_job_type_id_by_code('morpheus.task.jobType') || load_job_type_id_by_code('morpheus.task')
|
324
324
|
end
|
325
325
|
|
326
326
|
# workflow
|
327
|
+
task_set = nil
|
327
328
|
if !options[:workflow].nil?
|
328
329
|
task_set = find_by_name_or_id('task_set', options[:workflow])
|
329
330
|
|
@@ -332,8 +333,29 @@ class Morpheus::Cli::JobsCommand
|
|
332
333
|
exit 1
|
333
334
|
end
|
334
335
|
params['workflow'] = {'id' => task_set['id']}
|
335
|
-
job_type_id = load_job_type_id_by_code('morpheus.workflow')
|
336
|
+
job_type_id = load_job_type_id_by_code('morpheus.workflow.jobType') || load_job_type_id_by_code('morpheus.workflow')
|
336
337
|
end
|
338
|
+
# load workflow if we havent yet
|
339
|
+
if (params['workflow'] && params['workflow']['id']) && task_set.nil?
|
340
|
+
task_set = find_by_name_or_id('task_set', params['workflow']['id'])
|
341
|
+
if task_set.nil?
|
342
|
+
print_red_alert "Workflow #{params['workflow']['id']} not found"
|
343
|
+
exit 1
|
344
|
+
end
|
345
|
+
end
|
346
|
+
# prompt for custom options for workflow
|
347
|
+
custom_option_types = task_set ? task_set['optionTypes'] : nil
|
348
|
+
if custom_option_types && custom_option_types.size() > 0
|
349
|
+
# they are all returned in a single array right now, so skip prompting for the jobType optionTypes
|
350
|
+
custom_option_types.reject! { |it| it['code'] && it['code'].include?('job.type') }
|
351
|
+
custom_option_types = custom_option_types.collect {|it|
|
352
|
+
it['fieldContext'] = 'customOptions'
|
353
|
+
it
|
354
|
+
}
|
355
|
+
custom_options = Morpheus::Cli::OptionTypes.prompt(custom_option_types, options[:options], @api_client, {})
|
356
|
+
params['customOptions'] = custom_options['customOptions']
|
357
|
+
end
|
358
|
+
|
337
359
|
|
338
360
|
# load options based upon job type + task / taskset
|
339
361
|
job_options = @jobs_interface.options(job_type_id, {'taskId' => params['task'] ? params['task']['id'] : nil, 'workflowId' => params['workflow'] ? params['workflow']['id'] : nil})
|
@@ -90,6 +90,9 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
90
90
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
91
91
|
opts.banner = subcommand_usage("[name]")
|
92
92
|
build_standard_get_options(opts, options)
|
93
|
+
opts.on(nil,'--no-items', "Do not display List Items") do |val|
|
94
|
+
options[:no_list_items] = true
|
95
|
+
end
|
93
96
|
opts.footer = "Get details about an option list.\n" +
|
94
97
|
"[name] is required. This is the name or id of an option list. Supports 1-N [name] arguments."
|
95
98
|
end
|
@@ -166,15 +169,20 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
166
169
|
print_h2 "Translation Script"
|
167
170
|
print reset,"#{option_type_list['translationScript']}","\n",reset
|
168
171
|
end
|
172
|
+
if !option_type_list['requestScript'].empty?
|
173
|
+
print_h2 "Request Script"
|
174
|
+
print reset,"#{option_type_list['requestScript']}","\n",reset
|
175
|
+
end
|
169
176
|
end
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
177
|
+
if options[:no_list_items] != true
|
178
|
+
list_items = option_type_list['listItems']
|
179
|
+
if list_items && list_items.size > 0
|
180
|
+
print_h2 "List Items"
|
181
|
+
print as_pretty_table(list_items, [:name, :value], options)
|
182
|
+
print_results_pagination({size: list_items.size, total: list_items.size})
|
183
|
+
end
|
175
184
|
end
|
176
185
|
print reset,"\n"
|
177
|
-
|
178
186
|
rescue RestClient::Exception => e
|
179
187
|
print_rest_exception(e, options)
|
180
188
|
exit 1
|
@@ -262,7 +270,7 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
262
270
|
else
|
263
271
|
payload = {}
|
264
272
|
payload.deep_merge!({'optionTypeList' => parse_passed_options(options)})
|
265
|
-
list_payload = Morpheus::Cli::OptionTypes.no_prompt(
|
273
|
+
list_payload = Morpheus::Cli::OptionTypes.no_prompt(update_option_type_list_option_types(), options[:options], @api_client)
|
266
274
|
if list_payload['type'] == 'rest'
|
267
275
|
# parse Source Headers
|
268
276
|
if !(payload['optionTypeList']['config'] && payload['optionTypeList']['config']['sourceHeaders'])
|
@@ -129,7 +129,7 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
129
129
|
|
130
130
|
print_h1 "Option Type Details"
|
131
131
|
print cyan
|
132
|
-
|
132
|
+
columns = {
|
133
133
|
"ID" => 'id',
|
134
134
|
"Name" => 'name',
|
135
135
|
"Description" => 'description',
|
@@ -138,11 +138,14 @@ class Morpheus::Cli::LibraryOptionTypesCommand
|
|
138
138
|
# "Field Name" => 'fieldName',
|
139
139
|
"Full Field Name" => lambda {|it| [it['fieldContext'], it['fieldName']].select {|it| !it.to_s.empty? }.join('.') },
|
140
140
|
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
141
|
+
"Option List" => lambda {|it| it['optionList'] ? it['optionList']['name'] : nil },
|
141
142
|
"Placeholder" => 'placeHolder',
|
142
143
|
"Default Value" => 'defaultValue',
|
143
144
|
"Required" => lambda {|it| format_boolean(it['required']) },
|
144
145
|
"Export As Tag" => lambda {|it| it['exportMeta'].nil? ? '' : format_boolean(it['exportMeta']) },
|
145
|
-
}
|
146
|
+
}
|
147
|
+
columns.delete("Option List") if option_type['optionList'].nil?
|
148
|
+
print as_description_list(option_type, columns, options)
|
146
149
|
print reset,"\n"
|
147
150
|
return 0
|
148
151
|
rescue RestClient::Exception => e
|
@@ -34,7 +34,7 @@ class Morpheus::Cli::LogsCommand
|
|
34
34
|
options = {}
|
35
35
|
params = {}
|
36
36
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
37
|
-
opts.banner = subcommand_usage("[
|
37
|
+
opts.banner = subcommand_usage("[search]")
|
38
38
|
opts.on('--hosts HOSTS', String, "Filter logs to specific Host ID(s)") do |val|
|
39
39
|
params['servers'] = val.to_s.split(",").collect {|it| it.to_s.strip }.select {|it| it }.compact
|
40
40
|
end
|
@@ -72,18 +72,21 @@ class Morpheus::Cli::LogsCommand
|
|
72
72
|
options[:details] = true
|
73
73
|
end
|
74
74
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
75
|
-
opts.footer = "List logs for
|
76
|
-
"[id] is required. This is the id of a container."
|
75
|
+
opts.footer = "List logs for all hosts and containers."
|
77
76
|
end
|
78
77
|
optparse.parse!(args)
|
79
|
-
if args.count
|
80
|
-
|
78
|
+
if args.count > 0
|
79
|
+
options[:phrase] = args.join(" ")
|
81
80
|
end
|
82
81
|
connect(options)
|
83
82
|
begin
|
84
83
|
params['level'] = params['level'].collect {|it| it.to_s.upcase }.join('|') if params['level'] # api works with INFO|WARN
|
85
84
|
params.merge!(parse_list_options(options))
|
86
|
-
|
85
|
+
if params['phrase']
|
86
|
+
options.delete(:phrase)
|
87
|
+
search_phrase = params.delete('phrase')
|
88
|
+
params['query'] = search_phrase
|
89
|
+
end
|
87
90
|
params['order'] = params['direction'] unless params['direction'].nil? # old api version expects order instead of direction
|
88
91
|
params['startMs'] = (options[:start].to_i * 1000) if options[:start]
|
89
92
|
params['endMs'] = (options[:end].to_i * 1000) if options[:end]
|
@@ -136,6 +136,7 @@ module Morpheus::Cli::AccountsHelper
|
|
136
136
|
"Multitenant" => lambda {|it|
|
137
137
|
format_boolean(it['multitenant']).to_s + (it['multitenantLocked'] ? " (LOCKED)" : "")
|
138
138
|
},
|
139
|
+
"Default Persona" => lambda {|it| it['defaultPersona'] ? it['defaultPersona']['name'] : '(standard)' },
|
139
140
|
"Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
|
140
141
|
#"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
141
142
|
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
@@ -196,7 +197,7 @@ module Morpheus::Cli::AccountsHelper
|
|
196
197
|
|
197
198
|
## Users
|
198
199
|
|
199
|
-
def user_column_definitions()
|
200
|
+
def user_column_definitions(opts={})
|
200
201
|
{
|
201
202
|
"ID" => 'id',
|
202
203
|
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
@@ -206,15 +207,15 @@ module Morpheus::Cli::AccountsHelper
|
|
206
207
|
"Email" => 'email',
|
207
208
|
"Role" => lambda {|it| format_user_role_names(it) },
|
208
209
|
"Notifications" => lambda {|it| it['receiveNotifications'].nil? ? '' : format_boolean(it['receiveNotifications']) },
|
209
|
-
"Status" => lambda {|it| format_user_status(it) },
|
210
|
+
"Status" => lambda {|it| format_user_status(it, opts[:color] || cyan) },
|
210
211
|
"Last Login" => lambda {|it| format_duration_ago(it['lastLoginDate']) },
|
211
212
|
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
212
213
|
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
213
214
|
}
|
214
215
|
end
|
215
216
|
|
216
|
-
def list_user_column_definitions()
|
217
|
-
columns = user_column_definitions
|
217
|
+
def list_user_column_definitions(opts={})
|
218
|
+
columns = user_column_definitions(opts)
|
218
219
|
columns.delete("Notifications")
|
219
220
|
return columns.upcase_keys!
|
220
221
|
end
|
@@ -261,8 +262,8 @@ module Morpheus::Cli::AccountsHelper
|
|
261
262
|
return nil
|
262
263
|
elsif users.size > 1
|
263
264
|
print_red_alert "Found #{users.size} users by username '#{username}'. Try using ID instead: #{format_list(users.collect {|it| it['id']}, 'or', 3)}"
|
264
|
-
|
265
|
-
|
265
|
+
print_error "\n"
|
266
|
+
print_error as_pretty_table(users, list_user_column_definitions({color: red}), {color: red, thin: true})
|
266
267
|
print reset,"\n"
|
267
268
|
return nil
|
268
269
|
else
|
@@ -400,7 +401,7 @@ module Morpheus::Cli::AccountsHelper
|
|
400
401
|
end
|
401
402
|
|
402
403
|
def get_access_string(access, return_color=cyan)
|
403
|
-
get_access_color(access) + access + return_color
|
404
|
+
get_access_color(access) + access.to_s + return_color.to_s
|
404
405
|
# access ||= 'none'
|
405
406
|
# if access == 'none'
|
406
407
|
# "#{white}#{access.to_s}#{return_color}"
|
@@ -425,10 +426,14 @@ module Morpheus::Cli::AccountsHelper
|
|
425
426
|
# Examples: format_permission_access("read")
|
426
427
|
# format_permission_access("custom", "full,custom,none")
|
427
428
|
def format_access_string(access, access_levels=nil, return_color=cyan)
|
429
|
+
# nevermind all this, just colorized access level
|
430
|
+
return get_access_string(access, return_color)
|
431
|
+
|
428
432
|
access = access.to_s.downcase.strip
|
429
433
|
if access.empty?
|
430
434
|
access = "none"
|
431
435
|
end
|
436
|
+
|
432
437
|
if access_levels.nil?
|
433
438
|
access_levels = ["none","read","user","full"]
|
434
439
|
elsif access_levels.is_a?(Array)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'morpheus/cli/mixins/print_helper'
|
2
2
|
# Mixin for Morpheus::Cli command classes
|
3
|
-
# Provides common methods for
|
3
|
+
# Provides common methods for backups management
|
4
4
|
module Morpheus::Cli::BackupsHelper
|
5
5
|
|
6
6
|
def self.included(klass)
|
@@ -8,13 +8,11 @@ module Morpheus::Cli::BackupsHelper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def backups_interface
|
11
|
-
# @api_client.groups
|
12
11
|
raise "#{self.class} has not defined @backups_interface" if @backups_interface.nil?
|
13
12
|
@backups_interface
|
14
13
|
end
|
15
14
|
|
16
|
-
def
|
17
|
-
# @api_client.groups
|
15
|
+
def backup_jobs_interfaces
|
18
16
|
raise "#{self.class} has not defined @backup_jobs_interface" if @backup_jobs_interface.nil?
|
19
17
|
@backup_jobs_interface
|
20
18
|
end
|
@@ -10,7 +10,6 @@ module Morpheus::Cli::DeploymentsHelper
|
|
10
10
|
## Deployments
|
11
11
|
|
12
12
|
def deployments_interface
|
13
|
-
# @api_client.groups
|
14
13
|
raise "#{self.class} has not defined @deployments_interface" if @deployments_interface.nil?
|
15
14
|
@deployments_interface
|
16
15
|
end
|
@@ -52,9 +51,10 @@ module Morpheus::Cli::DeploymentsHelper
|
|
52
51
|
return nil
|
53
52
|
elsif deployments.size > 1
|
54
53
|
print_red_alert "#{deployments.size} deployments found by name '#{name}'"
|
54
|
+
print_error "\n"
|
55
55
|
puts_error as_pretty_table(deployments, [:id, :name], {color:red})
|
56
56
|
print_red_alert "Try using ID instead"
|
57
|
-
|
57
|
+
print_error reset,"\n"
|
58
58
|
return nil
|
59
59
|
else
|
60
60
|
return deployments[0]
|
@@ -123,13 +123,41 @@ module Morpheus::Cli::DeploymentsHelper
|
|
123
123
|
return nil
|
124
124
|
elsif deployment_versions.size > 1
|
125
125
|
print_red_alert "#{deployment_versions.size} deployment versions found by version '#{name}'"
|
126
|
+
print_error "\n"
|
126
127
|
puts_error as_pretty_table(deployment_versions, {"ID" => 'id', "VERSION" => 'userVersion'}, {color:red})
|
127
128
|
print_red_alert "Try using ID instead"
|
128
|
-
|
129
|
+
print_error reset,"\n"
|
129
130
|
return nil
|
130
131
|
else
|
131
132
|
return deployment_versions[0]
|
132
133
|
end
|
133
134
|
end
|
134
135
|
|
136
|
+
def format_deployment_version_number(deployment_version)
|
137
|
+
if deployment_version
|
138
|
+
deployment_version['userVersion'] || deployment_version['version'] || ''
|
139
|
+
else
|
140
|
+
''
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def format_app_deploy_status(status, return_color=cyan)
|
145
|
+
out = ""
|
146
|
+
s = status.to_s.downcase
|
147
|
+
if s == 'deployed' || s == 'committed'
|
148
|
+
out << "#{green}#{s.upcase}#{return_color}"
|
149
|
+
elsif s == 'open' || s == 'archived'
|
150
|
+
out << "#{cyan}#{s.upcase}#{return_color}"
|
151
|
+
elsif s == 'failed'
|
152
|
+
out << "#{red}#{s.upcase}#{return_color}"
|
153
|
+
else
|
154
|
+
out << "#{yellow}#{s.upcase}#{return_color}"
|
155
|
+
end
|
156
|
+
out
|
157
|
+
end
|
158
|
+
|
159
|
+
def format_deploy_type(val)
|
160
|
+
return val
|
161
|
+
end
|
162
|
+
|
135
163
|
end
|
@@ -75,7 +75,7 @@ module Morpheus::Cli::OptionSourceHelper
|
|
75
75
|
|
76
76
|
def get_cloud_options(refresh=false, api_params={})
|
77
77
|
if !@available_cloud_options || refresh
|
78
|
-
option_results = options_interface.options_for_source('clouds', api_params.
|
78
|
+
option_results = options_interface.options_for_source('clouds', api_params.merge({'default' => 'false'}))
|
79
79
|
@available_cloud_options = option_results['data'].collect {|it|
|
80
80
|
{"name" => it["name"], "value" => it["value"], "id" => it["value"]}
|
81
81
|
}
|
@@ -1151,27 +1151,6 @@ module Morpheus::Cli::PrintHelper
|
|
1151
1151
|
out
|
1152
1152
|
end
|
1153
1153
|
|
1154
|
-
def format_list(items, conjunction="and", limit=nil)
|
1155
|
-
items = items ? items.clone : []
|
1156
|
-
if limit
|
1157
|
-
items = items.first(limit)
|
1158
|
-
end
|
1159
|
-
last_item = items.pop
|
1160
|
-
if items.empty?
|
1161
|
-
return "#{last_item}"
|
1162
|
-
else
|
1163
|
-
return items.join(", ") + (conjunction.to_s.empty? ? ", " : " #{conjunction} ") + "#{last_item}" + ((limit && limit < (items.size+1)) ? " ..." : "")
|
1164
|
-
end
|
1165
|
-
end
|
1166
|
-
|
1167
|
-
def anded_list(items, limit=nil)
|
1168
|
-
format_list(items, "and", limit)
|
1169
|
-
end
|
1170
|
-
|
1171
|
-
def ored_list(items, limit=nil)
|
1172
|
-
format_list(items, "or", limit)
|
1173
|
-
end
|
1174
|
-
|
1175
1154
|
def sleep_with_dots(sleep_seconds, dots=3, dot_chr=".")
|
1176
1155
|
dot_interval = (sleep_seconds.to_f / dots.to_i)
|
1177
1156
|
dots.to_i.times do |dot_index|
|
@@ -1285,4 +1264,50 @@ module Morpheus::Cli::PrintHelper
|
|
1285
1264
|
end
|
1286
1265
|
end
|
1287
1266
|
|
1267
|
+
# convert JSON or YAML string to a map
|
1268
|
+
def parse_json_or_yaml(config, parsers = [:json, :yaml])
|
1269
|
+
rtn = {success: false, data: nil, err: nil}
|
1270
|
+
err = nil
|
1271
|
+
config = config.strip
|
1272
|
+
if config[0..2] == "---"
|
1273
|
+
parsers = [:yaml]
|
1274
|
+
end
|
1275
|
+
# ok only parse json for strings that start with {, consolidated yaml can look like json and cause issues}
|
1276
|
+
if config[0] && config[0].chr == "{" && config[-1] && config[-1].chr == "}"
|
1277
|
+
parsers = [:json]
|
1278
|
+
end
|
1279
|
+
parsers.each do |parser|
|
1280
|
+
if parser == :yaml
|
1281
|
+
begin
|
1282
|
+
# todo: one method to parse and return Hash
|
1283
|
+
# load does not raise an exception, it just returns the bad string
|
1284
|
+
#YAML.parse(config)
|
1285
|
+
config_map = YAML.load(config)
|
1286
|
+
if !config_map.is_a?(Hash)
|
1287
|
+
raise "Failed to parse config as YAML"
|
1288
|
+
end
|
1289
|
+
rtn[:data] = config_map
|
1290
|
+
rtn[:success] = true
|
1291
|
+
break
|
1292
|
+
rescue => ex
|
1293
|
+
rtn[:err] = ex if rtn[:err].nil?
|
1294
|
+
end
|
1295
|
+
elsif parser == :json
|
1296
|
+
begin
|
1297
|
+
config_map = JSON.parse(config)
|
1298
|
+
rtn[:data] = config_map
|
1299
|
+
rtn[:success] = true
|
1300
|
+
break
|
1301
|
+
rescue => ex
|
1302
|
+
rtn[:err] = ex if rtn[:err].nil?
|
1303
|
+
end
|
1304
|
+
end
|
1305
|
+
end
|
1306
|
+
return rtn
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
def parse_yaml_or_json(config, parsers = [:yaml, :json])
|
1310
|
+
parse_json_or_yaml(config, parsers)
|
1311
|
+
end
|
1312
|
+
|
1288
1313
|
end
|
@@ -596,11 +596,13 @@ module Morpheus::Cli::ProvisioningHelper
|
|
596
596
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments()}], options[:options])
|
597
597
|
payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
|
598
598
|
|
599
|
-
# Labels (tags)
|
600
|
-
|
601
|
-
|
599
|
+
# Labels (Provisioning API still refers to these as tags)
|
600
|
+
# and tags (metadata tags) is called metadata.
|
601
|
+
# todo: switch this from 'tags' to labels' when the api changes
|
602
|
+
if options[:labels]
|
603
|
+
payload['instance']['tags'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
|
602
604
|
else
|
603
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => '
|
605
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false}], options[:options])
|
604
606
|
payload['instance']['tags'] = v_prompt['tags'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['tags'].empty?
|
605
607
|
end
|
606
608
|
|
@@ -976,6 +978,9 @@ module Morpheus::Cli::ProvisioningHelper
|
|
976
978
|
metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
|
977
979
|
metadata_list = metadata_list.collect do |it|
|
978
980
|
metadata_pair = it.split(":")
|
981
|
+
if metadata_pair.size < 2 && it.include?("=")
|
982
|
+
metadata_pair = it.split("=")
|
983
|
+
end
|
979
984
|
row = {}
|
980
985
|
row['name'] = metadata_pair[0].to_s.strip
|
981
986
|
row['value'] = metadata_pair[1].to_s.strip
|
@@ -2175,6 +2180,82 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2175
2180
|
return ports
|
2176
2181
|
end
|
2177
2182
|
|
2183
|
+
def format_instance_status(instance, return_color=cyan)
|
2184
|
+
out = ""
|
2185
|
+
status_string = instance['status'].to_s
|
2186
|
+
if status_string == 'running'
|
2187
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
2188
|
+
elsif status_string == 'provisioning'
|
2189
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
2190
|
+
elsif status_string == 'stopped' or status_string == 'failed'
|
2191
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
2192
|
+
else
|
2193
|
+
out << "#{yellow}#{status_string.upcase}#{return_color}"
|
2194
|
+
end
|
2195
|
+
out
|
2196
|
+
end
|
2197
|
+
|
2198
|
+
def format_instance_connection_string(instance)
|
2199
|
+
if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
|
2200
|
+
connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
|
2201
|
+
end
|
2202
|
+
end
|
2203
|
+
|
2204
|
+
def format_app_status(app, return_color=cyan)
|
2205
|
+
out = ""
|
2206
|
+
status_string = app['status'] || app['appStatus'] || ''
|
2207
|
+
if status_string == 'running'
|
2208
|
+
out = "#{green}#{status_string.upcase}#{return_color}"
|
2209
|
+
elsif status_string == 'provisioning'
|
2210
|
+
out = "#{cyan}#{status_string.upcase}#{cyan}"
|
2211
|
+
elsif status_string == 'stopped' or status_string == 'failed'
|
2212
|
+
out = "#{red}#{status_string.upcase}#{return_color}"
|
2213
|
+
elsif status_string == 'unknown'
|
2214
|
+
out = "#{yellow}#{status_string.upcase}#{return_color}"
|
2215
|
+
elsif status_string == 'warning' && app['instanceCount'].to_i == 0
|
2216
|
+
# show this instead of WARNING
|
2217
|
+
out = "#{cyan}EMPTY#{return_color}"
|
2218
|
+
else
|
2219
|
+
out = "#{yellow}#{status_string.upcase}#{return_color}"
|
2220
|
+
end
|
2221
|
+
out
|
2222
|
+
end
|
2223
|
+
|
2224
|
+
def format_container_status(container, return_color=cyan)
|
2225
|
+
out = ""
|
2226
|
+
status_string = container['status'].to_s
|
2227
|
+
if status_string == 'running'
|
2228
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
2229
|
+
elsif status_string == 'provisioning'
|
2230
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
2231
|
+
elsif status_string == 'stopped' or status_string == 'failed'
|
2232
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
2233
|
+
else
|
2234
|
+
out << "#{yellow}#{status_string.upcase}#{return_color}"
|
2235
|
+
end
|
2236
|
+
out
|
2237
|
+
end
|
2238
|
+
|
2239
|
+
def format_container_connection_string(container)
|
2240
|
+
if !container['ports'].nil? && container['ports'].empty? == false
|
2241
|
+
connection_string = "#{container['ip']}:#{container['ports'][0]['external']}"
|
2242
|
+
else
|
2243
|
+
# eh? more logic needed here i think, see taglib morph:containerLocationMenu
|
2244
|
+
connection_string = "#{container['ip']}"
|
2245
|
+
end
|
2246
|
+
end
|
2247
|
+
|
2248
|
+
def format_instance_container_display_name(instance, plural=false)
|
2249
|
+
#<span class="info-label">${[null,'docker'].contains(instance.layout?.provisionType?.code) ? 'Containers' : 'Virtual Machines'}:</span> <span class="info-value">${instance.containers?.size()}</span>
|
2250
|
+
v = plural ? "Containers" : "Container"
|
2251
|
+
if instance && instance['layout'] && instance['layout'].key?("provisionTypeCode")
|
2252
|
+
if [nil, 'docker'].include?(instance['layout']["provisionTypeCode"])
|
2253
|
+
v = plural ? "Virtual Machines" : "Virtual Machine"
|
2254
|
+
end
|
2255
|
+
end
|
2256
|
+
return v
|
2257
|
+
end
|
2258
|
+
|
2178
2259
|
def format_blueprint_type(type_code)
|
2179
2260
|
return type_code.to_s # just show it as is
|
2180
2261
|
if type_code.to_s.empty?
|
@@ -2200,4 +2281,19 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2200
2281
|
return type_code.to_s.downcase
|
2201
2282
|
end
|
2202
2283
|
end
|
2284
|
+
|
2285
|
+
def format_snapshot_status(snapshot, return_color=cyan)
|
2286
|
+
out = ""
|
2287
|
+
status_string = snapshot['status'].to_s
|
2288
|
+
if status_string == 'complete'
|
2289
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
2290
|
+
elsif status_string == 'creating'
|
2291
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
2292
|
+
elsif status_string == 'failed'
|
2293
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
2294
|
+
else
|
2295
|
+
out << "#{yellow}#{status_string.upcase}#{return_color}"
|
2296
|
+
end
|
2297
|
+
out
|
2298
|
+
end
|
2203
2299
|
end
|