morpheus-cli 4.2.18 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +14 -0
- data/lib/morpheus/api/billing_interface.rb +33 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
- data/lib/morpheus/api/rest_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +14 -0
- data/lib/morpheus/cli.rb +2 -2
- data/lib/morpheus/cli/apps.rb +3 -4
- data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
- data/lib/morpheus/cli/backups_command.rb +3 -0
- data/lib/morpheus/cli/blueprints_command.rb +27 -61
- data/lib/morpheus/cli/budgets_command.rb +4 -4
- data/lib/morpheus/cli/catalog_command.rb +507 -0
- data/lib/morpheus/cli/cli_command.rb +30 -15
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
- data/lib/morpheus/cli/clouds.rb +7 -10
- data/lib/morpheus/cli/commands/standard/curl_command.rb +23 -7
- data/lib/morpheus/cli/commands/standard/source_command.rb +1 -1
- data/lib/morpheus/cli/commands/standard/update_command.rb +76 -0
- data/lib/morpheus/cli/containers_command.rb +14 -0
- data/lib/morpheus/cli/deployments.rb +1 -1
- data/lib/morpheus/cli/hosts.rb +30 -2
- data/lib/morpheus/cli/instances.rb +19 -1
- data/lib/morpheus/cli/invoices_command.rb +8 -9
- data/lib/morpheus/cli/jobs_command.rb +30 -8
- data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
- data/lib/morpheus/cli/library_option_lists_command.rb +14 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -6
- data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
- data/lib/morpheus/cli/mixins/catalog_helper.rb +66 -0
- data/lib/morpheus/cli/mixins/deployments_helper.rb +0 -1
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +46 -0
- data/lib/morpheus/cli/network_pools_command.rb +14 -6
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/projects_command.rb +7 -7
- data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
- data/lib/morpheus/cli/remote.rb +0 -2
- data/lib/morpheus/cli/roles.rb +305 -3
- data/lib/morpheus/cli/service_plans_command.rb +2 -2
- data/lib/morpheus/cli/storage_providers_command.rb +40 -56
- data/lib/morpheus/cli/tasks.rb +24 -10
- data/lib/morpheus/cli/tenants_command.rb +1 -1
- data/lib/morpheus/cli/usage_command.rb +150 -0
- data/lib/morpheus/cli/user_settings_command.rb +1 -0
- data/lib/morpheus/cli/users.rb +12 -1
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/workflows.rb +12 -9
- data/lib/morpheus/formatters.rb +26 -5
- metadata +8 -2
@@ -44,7 +44,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
44
44
|
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network, Extra" ) do
|
45
45
|
options[:show_prices] = true
|
46
46
|
end
|
47
|
-
opts.on('--type TYPE',
|
47
|
+
opts.on('-t', '--type TYPE', "Filter by Ref Type eg. ComputeSite (Group), ComputeZone (Cloud), ComputeServer (Host), Instance, Container, User") do |val|
|
48
48
|
params['refType'] ||= []
|
49
49
|
values = val.split(",").collect {|it| it.strip }.select {|it| it != "" }
|
50
50
|
values.each { |it| params['refType'] << parse_invoice_ref_type(it) }
|
@@ -193,9 +193,8 @@ class Morpheus::Cli::InvoicesCommand
|
|
193
193
|
subtitles += parse_list_subtitles(options)
|
194
194
|
print_h1 title, subtitles
|
195
195
|
if invoices.empty?
|
196
|
-
|
197
|
-
|
198
|
-
end
|
196
|
+
print cyan,"No invoices found.",reset,"\n"
|
197
|
+
print reset,"\n"
|
199
198
|
else
|
200
199
|
# current_date = Time.now
|
201
200
|
# current_period = "#{current_date.year}#{current_date.month.to_s.rjust(2, '0')}"
|
@@ -300,8 +299,8 @@ class Morpheus::Cli::InvoicesCommand
|
|
300
299
|
end
|
301
300
|
if options[:show_estimates]
|
302
301
|
cost_rows += [
|
303
|
-
{label: '
|
304
|
-
{label: '
|
302
|
+
{label: 'Metered Cost'.upcase, compute: invoice_totals['estimatedComputeCost'], memory: invoice_totals['estimatedMemoryCost'], storage: invoice_totals['estimatedStorageCost'], network: invoice_totals['estimatedNetworkCost'], license: invoice_totals['estimatedLicenseCost'], extra: invoice_totals['estimatedExtraCost'], running: invoice_totals['estimatedRunningCost'], total: invoice_totals['estimatedTotalCost']},
|
303
|
+
{label: 'Metered Price'.upcase, compute: invoice_totals['estimatedComputePrice'], memory: invoice_totals['estimatedMemoryPrice'], storage: invoice_totals['estimatedStoragePrice'], network: invoice_totals['estimatedNetworkPrice'], license: invoice_totals['estimatedLicensePrice'], extra: invoice_totals['estimatedExtraPrice'], running: invoice_totals['estimatedRunningPrice'], total: invoice_totals['estimatedTotalPrice']},
|
305
304
|
]
|
306
305
|
end
|
307
306
|
cost_columns = {
|
@@ -534,8 +533,8 @@ EOT
|
|
534
533
|
end
|
535
534
|
if options[:show_estimates]
|
536
535
|
cost_rows += [
|
537
|
-
{label: '
|
538
|
-
{label: '
|
536
|
+
{label: 'Metered Cost'.upcase, compute: invoice['estimatedComputeCost'], memory: invoice['estimatedMemoryCost'], storage: invoice['estimatedStorageCost'], network: invoice['estimatedNetworkCost'], license: invoice['estimatedLicenseCost'], extra: invoice['estimatedExtraCost'], running: invoice['estimatedRunningCost'], total: invoice['estimatedTotalCost']},
|
537
|
+
{label: 'Metered Price'.upcase, compute: invoice['estimatedComputePrice'], memory: invoice['estimatedMemoryPrice'], storage: invoice['estimatedStoragePrice'], network: invoice['estimatedNetworkPrice'], license: invoice['estimatedLicensePrice'], extra: invoice['estimatedExtraPrice'], running: invoice['estimatedRunningPrice'], total: invoice['estimatedTotalPrice']},
|
539
538
|
]
|
540
539
|
end
|
541
540
|
cost_columns = {
|
@@ -683,7 +682,7 @@ EOT
|
|
683
682
|
params['externalId'] ||= []
|
684
683
|
params['externalId'] << val
|
685
684
|
end
|
686
|
-
opts.on('--type TYPE',
|
685
|
+
opts.on('-t', '--type TYPE', "Filter by Ref Type eg. ComputeSite (Group), ComputeZone (Cloud), ComputeServer (Host), Instance, Container, User") do |val|
|
687
686
|
params['refType'] ||= []
|
688
687
|
values = val.split(",").collect {|it| it.strip }.select {|it| it != "" }
|
689
688
|
values.each { |it| params['refType'] << parse_invoice_ref_type(it) }
|
@@ -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})
|
@@ -768,7 +790,7 @@ class Morpheus::Cli::JobsCommand
|
|
768
790
|
params = {}
|
769
791
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
770
792
|
opts.banner = subcommand_usage("[id]")
|
771
|
-
opts.on('-D', '--details [on|off]', String, "Can be used to enable / disable execution details. Default
|
793
|
+
opts.on('-D', '--details [on|off]', String, "Can be used to enable / disable execution details. Default is on") do |val|
|
772
794
|
options[:details] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
773
795
|
end
|
774
796
|
build_common_options(opts, options, [:json, :dry_run, :remote])
|
@@ -970,7 +992,7 @@ class Morpheus::Cli::JobsCommand
|
|
970
992
|
def format_status(status_string, return_color=cyan)
|
971
993
|
out = ""
|
972
994
|
if status_string
|
973
|
-
if ['success', 'successful', 'ok'].include?(status_string)
|
995
|
+
if ['complete','success', 'successful', 'ok'].include?(status_string)
|
974
996
|
out << "#{green}#{status_string.upcase}"
|
975
997
|
elsif ['error', 'offline', 'failed', 'failure'].include?(status_string)
|
976
998
|
out << "#{red}#{status_string.upcase}"
|
@@ -244,15 +244,14 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
244
244
|
options = {}
|
245
245
|
params = {}
|
246
246
|
logo_file = nil
|
247
|
-
option_type_ids = nil
|
248
247
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
249
248
|
opts.banner = subcommand_usage("[name]")
|
250
249
|
build_option_type_options(opts, options, add_instance_type_option_types())
|
251
250
|
opts.on('--option-types [x,y,z]', Array, "List of Option Type IDs") do |list|
|
252
251
|
if list.nil?
|
253
|
-
|
252
|
+
params['optionTypes'] = []
|
254
253
|
else
|
255
|
-
|
254
|
+
params['optionTypes'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
256
255
|
end
|
257
256
|
end
|
258
257
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
@@ -348,6 +347,13 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
348
347
|
opts.banner = subcommand_usage("[name] [options]")
|
349
348
|
build_option_type_options(opts, options, update_instance_type_option_types())
|
350
349
|
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
350
|
+
opts.on('--option-types [x,y,z]', Array, "List of Option Type IDs") do |list|
|
351
|
+
if list.nil?
|
352
|
+
params['optionTypes'] = []
|
353
|
+
else
|
354
|
+
params['optionTypes'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
355
|
+
end
|
356
|
+
end
|
351
357
|
opts.footer = "Update an instance type." + "\n" +
|
352
358
|
"[name] is required. This is the name or id of a instance type."
|
353
359
|
end
|
@@ -375,6 +381,14 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
375
381
|
params['hasSettings'] = ['on','true','1'].include?(params['hasSettings'].to_s) if params.key?('hasSettings')
|
376
382
|
params['hasAutoScale'] = ['on','true','1'].include?(params['hasAutoScale'].to_s) if params.key?('hasAutoScale')
|
377
383
|
params['hasDeployment'] = ['on','true','1'].include?(params['hasDeployment'].to_s) if params.key?('hasDeployment')
|
384
|
+
if params['optionTypes']
|
385
|
+
prompt_results = prompt_for_option_types(params, options, @api_client)
|
386
|
+
if prompt_results[:success]
|
387
|
+
params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
|
388
|
+
else
|
389
|
+
return 1
|
390
|
+
end
|
391
|
+
end
|
378
392
|
if params.empty?
|
379
393
|
puts optparse
|
380
394
|
#option_lines = update_instance_type_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'morpheus/cli/mixins/print_helper'
|
2
|
+
# Mixin for Morpheus::Cli command classes
|
3
|
+
# Provides common methods for infrastructure management
|
4
|
+
module Morpheus::Cli::CatalogHelper
|
5
|
+
|
6
|
+
def self.included(klass)
|
7
|
+
klass.send :include, Morpheus::Cli::PrintHelper
|
8
|
+
end
|
9
|
+
|
10
|
+
def catalog_item_types_interface
|
11
|
+
raise "#{self.class} has not defined @catalog_item_types_interface" if @catalog_item_types_interface.nil?
|
12
|
+
@catalog_item_types_interface
|
13
|
+
end
|
14
|
+
|
15
|
+
# def service_catalog_interface
|
16
|
+
# raise "#{self.class} has not defined @service_catalog_interface" if @service_catalog_interface.nil?
|
17
|
+
# @service_catalog_interface
|
18
|
+
# end
|
19
|
+
|
20
|
+
def catalog_item_type_object_key
|
21
|
+
'catalogItemType'
|
22
|
+
end
|
23
|
+
|
24
|
+
def catalog_item_type_list_key
|
25
|
+
'catalogItemTypes'
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_catalog_item_type_by_name_or_id(val)
|
29
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
30
|
+
return find_catalog_item_type_by_id(val)
|
31
|
+
else
|
32
|
+
return find_catalog_item_type_by_name(val)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_catalog_item_type_by_id(id)
|
37
|
+
begin
|
38
|
+
json_response = catalog_item_types_interface.get(id.to_i)
|
39
|
+
return json_response[catalog_item_type_object_key]
|
40
|
+
rescue RestClient::Exception => e
|
41
|
+
if e.response && e.response.code == 404
|
42
|
+
print_red_alert "catalog_item_type not found by id '#{id}'"
|
43
|
+
else
|
44
|
+
raise e
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_catalog_item_type_by_name(name)
|
50
|
+
json_response = catalog_item_types_interface.list({name: name.to_s})
|
51
|
+
catalog_item_types = json_response[catalog_item_type_list_key]
|
52
|
+
if catalog_item_types.empty?
|
53
|
+
print_red_alert "catalog_item_type not found by name '#{name}'"
|
54
|
+
return nil
|
55
|
+
elsif catalog_item_types.size > 1
|
56
|
+
print_red_alert "#{catalog_item_types.size} catalog_item_types found by name '#{name}'"
|
57
|
+
puts_error as_pretty_table(catalog_item_types, [:id, :name], {color:red})
|
58
|
+
print_red_alert "Try using ID instead"
|
59
|
+
print reset,"\n"
|
60
|
+
return nil
|
61
|
+
else
|
62
|
+
return catalog_item_types[0]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
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
|
}
|
@@ -1285,4 +1285,50 @@ module Morpheus::Cli::PrintHelper
|
|
1285
1285
|
end
|
1286
1286
|
end
|
1287
1287
|
|
1288
|
+
# convert JSON or YAML string to a map
|
1289
|
+
def parse_json_or_yaml(config, parsers = [:json, :yaml])
|
1290
|
+
rtn = {success: false, data: nil, err: nil}
|
1291
|
+
err = nil
|
1292
|
+
config = config.strip
|
1293
|
+
if config[0..2] == "---"
|
1294
|
+
parsers = [:yaml]
|
1295
|
+
end
|
1296
|
+
# ok only parse json for strings that start with {, consolidated yaml can look like json and cause issues}
|
1297
|
+
if config[0] && config[0].chr == "{" && config[-1] && config[-1].chr == "}"
|
1298
|
+
parsers = [:json]
|
1299
|
+
end
|
1300
|
+
parsers.each do |parser|
|
1301
|
+
if parser == :yaml
|
1302
|
+
begin
|
1303
|
+
# todo: one method to parse and return Hash
|
1304
|
+
# load does not raise an exception, it just returns the bad string
|
1305
|
+
#YAML.parse(config)
|
1306
|
+
config_map = YAML.load(config)
|
1307
|
+
if !config_map.is_a?(Hash)
|
1308
|
+
raise "Failed to parse config as YAML"
|
1309
|
+
end
|
1310
|
+
rtn[:data] = config_map
|
1311
|
+
rtn[:success] = true
|
1312
|
+
break
|
1313
|
+
rescue => ex
|
1314
|
+
rtn[:err] = ex if rtn[:err].nil?
|
1315
|
+
end
|
1316
|
+
elsif parser == :json
|
1317
|
+
begin
|
1318
|
+
config_map = JSON.parse(config)
|
1319
|
+
rtn[:data] = config_map
|
1320
|
+
rtn[:success] = true
|
1321
|
+
break
|
1322
|
+
rescue => ex
|
1323
|
+
rtn[:err] = ex if rtn[:err].nil?
|
1324
|
+
end
|
1325
|
+
end
|
1326
|
+
end
|
1327
|
+
return rtn
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
def parse_yaml_or_json(config, parsers = [:yaml, :json])
|
1331
|
+
parse_json_or_yaml(config, parsers)
|
1332
|
+
end
|
1333
|
+
|
1288
1334
|
end
|
@@ -596,22 +596,28 @@ class Morpheus::Cli::NetworkPoolsCommand
|
|
596
596
|
def add_ip(args)
|
597
597
|
options = {}
|
598
598
|
params = {}
|
599
|
+
next_free_ip = false
|
599
600
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
600
|
-
opts.banner = subcommand_usage("[network-pool] [ip]")
|
601
|
+
opts.banner = subcommand_usage("[network-pool] [ip] [--next]")
|
601
602
|
opts.on('--ip-address VALUE', String, "IP Address for this network pool IP") do |val|
|
602
603
|
options[:options]['ipAddress'] = val
|
603
604
|
end
|
605
|
+
opts.on('--next-free-ip', '--next-free-ip', "Use the next available ip address. This can be used instead of specifying an ip address") do
|
606
|
+
next_free_ip = true
|
607
|
+
end
|
604
608
|
opts.on('--hostname VALUE', String, "Hostname for this network pool IP") do |val|
|
605
609
|
options[:options]['hostname'] = val
|
606
610
|
end
|
607
611
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
|
608
612
|
opts.footer = "Create a new network pool IP." + "\n" +
|
609
613
|
"[network-pool] is required. This is the name or id of a network pool.\n" +
|
610
|
-
"[ip] is required
|
614
|
+
"[ip] is required or --next-free-ip to use the next available address instead."
|
611
615
|
end
|
612
616
|
optparse.parse!(args)
|
613
|
-
if
|
614
|
-
|
617
|
+
if next_free_ip
|
618
|
+
verify_args!(args:args, count:1, optparse:optparse)
|
619
|
+
else
|
620
|
+
verify_args!(args:args, min:1, max:2, optparse:optparse)
|
615
621
|
end
|
616
622
|
connect(options)
|
617
623
|
begin
|
@@ -639,8 +645,10 @@ class Morpheus::Cli::NetworkPoolsCommand
|
|
639
645
|
payload['networkPoolIp'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
640
646
|
|
641
647
|
# IP Address
|
642
|
-
|
643
|
-
|
648
|
+
unless next_free_ip
|
649
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'ipAddress', 'fieldLabel' => 'IP Address', 'type' => 'text', 'required' => true, 'description' => 'IP Address for this network pool IP.'}], options[:options])
|
650
|
+
payload['networkPoolIp']['ipAddress'] = v_prompt['ipAddress'] unless v_prompt['ipAddress'].to_s.empty?
|
651
|
+
end
|
644
652
|
|
645
653
|
# Hostname
|
646
654
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'hostname', 'fieldLabel' => 'Hostname', 'type' => 'text', 'required' => true, 'description' => 'Hostname for this network pool IP.'}], options[:options])
|