morpheus-cli 4.2.21 → 5.2.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 +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
|