morpheus-cli 7.0.0 → 7.0.2
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 +5 -0
- data/lib/morpheus/api/email_templates_interface.rb +53 -0
- data/lib/morpheus/cli/commands/budgets_command.rb +24 -11
- data/lib/morpheus/cli/commands/clusters.rb +16 -18
- data/lib/morpheus/cli/commands/email_templates_command.rb +373 -0
- data/lib/morpheus/cli/commands/license.rb +17 -17
- data/lib/morpheus/cli/mixins/print_helper.rb +2 -2
- data/lib/morpheus/cli/option_types.rb +8 -3
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6cc9570fd3a41bf3c6ec4fb5b5ab5801171554a630eb269af90dcc6672fe141
|
4
|
+
data.tar.gz: 63150328a3155ed9ba99d57963be4e16eab3e54934eff64f94070b4fbf485c40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d2375caf166551c16c460bf0b1cae7e2b672534c9a29a784408e2eac9e4fc336e01d93685ce5e0572933285a9e4766bc304314f8abfb2d62b700e09b9190f14
|
7
|
+
data.tar.gz: f30d57bcf10c3b3cb976329ec94a4ffff39f66da33ceffab25a7ab5246f921070f41547fe2b9c5f77de8e8814fc2ca8bf66855f93cf390044eac2fa76ba83ff3
|
data/Dockerfile
CHANGED
@@ -998,6 +998,11 @@ class Morpheus::APIClient
|
|
998
998
|
Morpheus::NetworkFloatingIpsInterface.new(common_interface_options).setopts(@options)
|
999
999
|
end
|
1000
1000
|
|
1001
|
+
def email_templates
|
1002
|
+
Morpheus::EmailTemplatesInterface.new(common_interface_options).setopts(@options)
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
|
1001
1006
|
def rest(endpoint)
|
1002
1007
|
Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
|
1003
1008
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::EmailTemplatesInterface < Morpheus::APIClient
|
4
|
+
|
5
|
+
def list(params={})
|
6
|
+
url = "#{@base_url}/api/email-templates"
|
7
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
8
|
+
opts = {method: :get, url: url, headers: headers}
|
9
|
+
execute(opts)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(id, params={})
|
13
|
+
url = "#{@base_url}/api/email-templates/#{id}"
|
14
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
15
|
+
if params.is_a?(Hash)
|
16
|
+
headers[:params].merge!(params)
|
17
|
+
elsif params.is_a?(Numeric)
|
18
|
+
url = "#{base_path}/#{params}"
|
19
|
+
elsif params.is_a?(String)
|
20
|
+
headers[:params]['name'] = params
|
21
|
+
end
|
22
|
+
execute(method: :get, url: url, headers: headers)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def update(id, payload)
|
27
|
+
url = "#{@base_url}/api/email-templates/#{id}"
|
28
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
29
|
+
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def create(options)
|
34
|
+
url = "#{@base_url}/api/email-templates"
|
35
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
36
|
+
payload = options
|
37
|
+
execute(method: :post, url: url, headers: headers, payload: payload.to_json)
|
38
|
+
end
|
39
|
+
|
40
|
+
def template_types(params={})
|
41
|
+
url = "#{@base_url}/api/email-templates/types"
|
42
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
43
|
+
opts = {method: :get, url: url, headers: headers}
|
44
|
+
execute(opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy(id, params={})
|
48
|
+
url = "#{@base_url}/api/email-templates/#{id}"
|
49
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
50
|
+
execute(method: :delete, url: url, headers: headers)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -132,6 +132,7 @@ class Morpheus::Cli::BudgetsCommand
|
|
132
132
|
"Scope" => lambda {|it| format_budget_scope(it) },
|
133
133
|
"Period" => lambda {|it| it['year'] },
|
134
134
|
"Interval" => lambda {|it| it['interval'].to_s.capitalize },
|
135
|
+
"Forecast Model" => lambda {|it| it['forecastType'] ? it['forecastType']['name'] : '' },
|
135
136
|
# the UI doesn't consider timezone, so uhh do it this hacky way for now.
|
136
137
|
"Start Date" => lambda {|it|
|
137
138
|
if it['timezone'] == 'UTC'
|
@@ -173,6 +174,7 @@ class Morpheus::Cli::BudgetsCommand
|
|
173
174
|
}
|
174
175
|
budget_row = {label:"Budget"}
|
175
176
|
actual_row = {label:"Actual"}
|
177
|
+
forecast_row = {label:"Forecast"}
|
176
178
|
multi_year = false
|
177
179
|
if budget['startDate'] && budget['endDate'] && parse_time(budget['startDate']).year != parse_time(budget['endDate']).year
|
178
180
|
multi_year = true
|
@@ -192,8 +194,18 @@ class Morpheus::Cli::BudgetsCommand
|
|
192
194
|
budget_row[interval_key] = "#{cyan}#{format_money(budget_cost, currency)}#{cyan}"
|
193
195
|
actual_row[interval_key] = "#{cyan}#{format_money(actual_cost, currency)}#{cyan}"
|
194
196
|
end
|
197
|
+
forecast_cost = it["forecast"] ? it["forecast"].to_f : 0
|
198
|
+
forecast_over_budget = forecast_cost > 0 && forecast_cost > budget_cost
|
199
|
+
if forecast_over_budget
|
200
|
+
forecast_row[interval_key] = "#{red}#{format_money(forecast_cost, currency)}#{cyan}"
|
201
|
+
else
|
202
|
+
forecast_row[interval_key] = "#{cyan}#{format_money(forecast_cost, currency)}#{cyan}"
|
203
|
+
end
|
195
204
|
end
|
196
205
|
chart_data = [budget_row, actual_row]
|
206
|
+
if budget['stats']['intervals'].find { |it| it['forecast'] && it['forecast'] != 0 }
|
207
|
+
chart_data << forecast_row
|
208
|
+
end
|
197
209
|
print as_pretty_table(chart_data, budget_summary_columns, options)
|
198
210
|
print reset,"\n"
|
199
211
|
rescue => ex
|
@@ -575,26 +587,27 @@ EOT
|
|
575
587
|
|
576
588
|
def add_budget_option_types
|
577
589
|
[
|
578
|
-
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true
|
579
|
-
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'
|
590
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
|
591
|
+
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
|
580
592
|
# {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
|
581
|
-
{'fieldName' => 'scope', 'fieldLabel' => 'Scope', 'code' => 'budget.scope', 'type' => 'select', 'selectOptions' => [{'name'=>'Account','value'=>'account'},{'name'=>'Tenant','value'=>'tenant'},{'name'=>'Cloud','value'=>'cloud'},{'name'=>'Group','value'=>'group'},{'name'=>'User','value'=>'user'}], 'defaultValue' => 'account', 'required' => true
|
593
|
+
{'fieldName' => 'scope', 'fieldLabel' => 'Scope', 'code' => 'budget.scope', 'type' => 'select', 'selectOptions' => [{'name'=>'Account','value'=>'account'},{'name'=>'Tenant','value'=>'tenant'},{'name'=>'Cloud','value'=>'cloud'},{'name'=>'Group','value'=>'group'},{'name'=>'User','value'=>'user'}], 'defaultValue' => 'account', 'required' => true},
|
582
594
|
{'fieldName' => 'tenant', 'fieldLabel' => 'Tenant', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
|
583
595
|
@options_interface.options_for_source("tenants", {})['data']
|
584
|
-
}, 'required' => true, 'dependsOnCode' => 'budget.scope:tenant'
|
596
|
+
}, 'required' => true, 'dependsOnCode' => 'budget.scope:tenant'},
|
585
597
|
{'fieldName' => 'user', 'fieldLabel' => 'User', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
|
586
598
|
@options_interface.options_for_source("users", {})['data']
|
587
|
-
}, 'required' => true, 'dependsOnCode' => 'budget.scope:user'
|
599
|
+
}, 'required' => true, 'dependsOnCode' => 'budget.scope:user'},
|
588
600
|
{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
|
589
601
|
@options_interface.options_for_source("groups", {})['data']
|
590
|
-
}, 'required' => true, 'dependsOnCode' => 'budget.scope:group'
|
602
|
+
}, 'required' => true, 'dependsOnCode' => 'budget.scope:group'},
|
591
603
|
{'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => lambda {|api_client, api_params|
|
592
604
|
@options_interface.options_for_source("clouds", {})['data']
|
593
|
-
}, 'required' => true, 'dependsOnCode' => 'budget.scope:cloud'
|
594
|
-
{'fieldName' => 'year', 'fieldLabel' => 'Period', 'code' => 'budget.year', 'type' => 'text', 'required' => true, 'defaultValue' => Time.now.year, 'description' => "The period (year) the budget applies, YYYY or 'custom' to enter Start Date and End Date manually"
|
595
|
-
{'fieldName' => 'startDate', 'fieldLabel' => 'Start Date', 'type' => 'text', 'required' => true, 'description' => 'The Start Date for custom period budget eg. 2021-01-01', 'dependsOnCode' => 'budget.year:custom'
|
596
|
-
{'fieldName' => 'endDate', 'fieldLabel' => 'End Date', 'type' => 'text', 'required' => true, 'description' => 'The End Date for custom period budget eg. 2023-12-31 (must be 1, 2 or 3 years from Start Date)', 'dependsOnCode' => 'budget.year:custom'
|
597
|
-
{'fieldName' => 'interval', 'fieldLabel' => 'Interval', 'type' => 'select', 'selectOptions' => [{'name'=>'Year','value'=>'year'},{'name'=>'Quarter','value'=>'quarter'},{'name'=>'Month','value'=>'month'}], 'defaultValue' => 'year', 'required' => true, 'description' => 'The budget interval, determines cost amounts: "year", "quarter" or "month"',
|
605
|
+
}, 'required' => true, 'dependsOnCode' => 'budget.scope:cloud'},
|
606
|
+
{'fieldName' => 'year', 'fieldLabel' => 'Period', 'code' => 'budget.year', 'type' => 'text', 'required' => true, 'defaultValue' => Time.now.year, 'description' => "The period (year) the budget applies, YYYY or 'custom' to enter Start Date and End Date manually"},
|
607
|
+
{'fieldName' => 'startDate', 'fieldLabel' => 'Start Date', 'type' => 'text', 'required' => true, 'description' => 'The Start Date for custom period budget eg. 2021-01-01', 'dependsOnCode' => 'budget.year:custom'},
|
608
|
+
{'fieldName' => 'endDate', 'fieldLabel' => 'End Date', 'type' => 'text', 'required' => true, 'description' => 'The End Date for custom period budget eg. 2023-12-31 (must be 1, 2 or 3 years from Start Date)', 'dependsOnCode' => 'budget.year:custom'},
|
609
|
+
{'fieldName' => 'interval', 'fieldLabel' => 'Interval', 'type' => 'select', 'selectOptions' => [{'name'=>'Year','value'=>'year'},{'name'=>'Quarter','value'=>'quarter'},{'name'=>'Month','value'=>'month'}], 'defaultValue' => 'year', 'required' => true, 'description' => 'The budget interval, determines cost amounts: "year", "quarter" or "month"'},
|
610
|
+
{'fieldName' => 'forecastType.id', 'fieldLabel' => 'Forecast Model', 'type' => 'select', 'optionSource' => 'forecastTypes', 'description' => 'The budget forcecast model type, determines projected cost calculations.'},
|
598
611
|
]
|
599
612
|
end
|
600
613
|
|
@@ -4277,26 +4277,24 @@ class Morpheus::Cli::Clusters
|
|
4277
4277
|
|
4278
4278
|
if provision_type && provision_type['hasZonePools']
|
4279
4279
|
# Resource pool
|
4280
|
-
|
4281
|
-
|
4282
|
-
resource_pool = options[:resourcePool] ? find_cloud_resource_pool_by_name_or_id(cloud['id'], options[:resourcePool]) : nil
|
4280
|
+
resource_pool_id = nil
|
4281
|
+
resource_pool = options[:resourcePool] ? find_cloud_resource_pool_by_name_or_id(cloud['id'], options[:resourcePool]) : nil
|
4283
4282
|
|
4284
|
-
|
4285
|
-
|
4283
|
+
if !resource_pool
|
4284
|
+
resource_pool_options = @options_interface.options_for_source('zonePools', {groupId: group['id'], zoneId: cloud['id']}.merge(service_plan ? {planId: service_plan['id']} : {}))['data'].reject { |it| it['id'].nil? && it['name'].nil? }
|
4286
4285
|
|
4287
|
-
|
4288
|
-
|
4289
|
-
|
4290
|
-
|
4291
|
-
|
4292
|
-
|
4293
|
-
|
4294
|
-
|
4295
|
-
|
4296
|
-
|
4297
|
-
|
4298
|
-
|
4299
|
-
end
|
4286
|
+
if resource_pool_options.empty?
|
4287
|
+
print_red_alert "Cloud #{cloud['name']} has no available resource pools"
|
4288
|
+
exit 1
|
4289
|
+
elsif resource_pool_options.count > 1 && !options[:no_prompt]
|
4290
|
+
resource_pool_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'resourcePool', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}],options[:options],api_client, {})['resourcePool']
|
4291
|
+
else
|
4292
|
+
resource_pool_id = resource_pool_options.first['id']
|
4293
|
+
end
|
4294
|
+
if resource_pool_id.to_s["poolGroup-"]
|
4295
|
+
resource_pool = @resource_pool_groups_interface.get(resource_pool_id)['resourcePoolGroup']
|
4296
|
+
else
|
4297
|
+
resource_pool = @cloud_resource_pools_interface.get(cloud['id'], resource_pool_id)['resourcePool']
|
4300
4298
|
end
|
4301
4299
|
end
|
4302
4300
|
end
|
@@ -0,0 +1,373 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::EmailTemplates
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
|
6
|
+
register_subcommands :list, :get, :add, :update, :remove, :execute
|
7
|
+
|
8
|
+
def connect(opts)
|
9
|
+
@api_client = establish_remote_appliance_connection(opts)
|
10
|
+
@email_templates_interface = @api_client.email_templates
|
11
|
+
end
|
12
|
+
|
13
|
+
def handle(args)
|
14
|
+
handle_subcommand(args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def list(args)
|
18
|
+
params = {}
|
19
|
+
options = {}
|
20
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
21
|
+
opts.banner = subcommand_usage("[search]")
|
22
|
+
|
23
|
+
build_standard_list_options(opts, options)
|
24
|
+
opts.footer = "List email templates."
|
25
|
+
end
|
26
|
+
optparse.parse!(args)
|
27
|
+
connect(options)
|
28
|
+
if args.count > 0
|
29
|
+
options[:phrase] = args.join(" ")
|
30
|
+
end
|
31
|
+
params.merge!(parse_list_options(options))
|
32
|
+
@email_templates_interface.setopts(options)
|
33
|
+
if options[:dry_run]
|
34
|
+
print_dry_run @email_templates.dry.list(params)
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
json_response = @email_templates_interface.list(params)
|
39
|
+
templates = json_response['emailTemplates']
|
40
|
+
render_response(json_response, options, 'templates') do
|
41
|
+
title = "Morpheus Email Templates"
|
42
|
+
subtitles = []
|
43
|
+
subtitles += parse_list_subtitles(options)
|
44
|
+
print_h1 title, subtitles
|
45
|
+
if templates.empty?
|
46
|
+
print cyan,"No templates found.",reset,"\n"
|
47
|
+
else
|
48
|
+
print cyan
|
49
|
+
print_templates_table(templates, options)
|
50
|
+
print_results_pagination(json_response)
|
51
|
+
end
|
52
|
+
print reset,"\n"
|
53
|
+
end
|
54
|
+
if templates.empty?
|
55
|
+
return 1, "no templates found"
|
56
|
+
else
|
57
|
+
return 0, nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def get(args)
|
62
|
+
params = {}
|
63
|
+
options = {}
|
64
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
65
|
+
opts.banner = subcommand_usage("[emailTemplate]")
|
66
|
+
build_standard_get_options(opts, options)
|
67
|
+
opts.footer = <<-EOT
|
68
|
+
Get details about a specific email template.
|
69
|
+
[emailTemplate] is required. This is the name or id of an emailTemplate.
|
70
|
+
EOT
|
71
|
+
end
|
72
|
+
optparse.parse!(args)
|
73
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
74
|
+
connect(options)
|
75
|
+
parse_options(options, params)
|
76
|
+
id_list = parse_id_list(args)
|
77
|
+
return run_command_for_each_arg(id_list) do |arg|
|
78
|
+
_get(arg, params, options)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def _get(id, params, options)
|
83
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
84
|
+
record = find_by_name_or_id('emailTemplate', id)
|
85
|
+
if record.nil?
|
86
|
+
return 1, "EmailTemplate not found for '#{id}'"
|
87
|
+
end
|
88
|
+
id = record['id']
|
89
|
+
end
|
90
|
+
options[:params] = params # parse_options(options, params)
|
91
|
+
options.delete(:payload)
|
92
|
+
execute_api(@email_templates_interface, :get, [id], options, 'emailTemplate') do |json_response|
|
93
|
+
email_template = json_response['emailTemplate']
|
94
|
+
print_h1 "EmailTemplate Details", [], options
|
95
|
+
print cyan
|
96
|
+
columns = email_template_column_definitions
|
97
|
+
print_description_list(columns, email_template, options)
|
98
|
+
print reset,"\n"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def add(args)
|
103
|
+
options = {}
|
104
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
105
|
+
opts.banner = subcommand_usage( "[name]")
|
106
|
+
opts.on("--type [TEXT]", String, "Type") do |val|
|
107
|
+
options[:type] = val.to_s
|
108
|
+
end
|
109
|
+
opts.on( '--template [TEXT]', "Template" ) do |val|
|
110
|
+
options[:template] = val.to_s
|
111
|
+
end
|
112
|
+
opts.on('--accounts LIST', Array, "Tenant accounts, comma separated list of account IDs") do |list|
|
113
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
114
|
+
options[:accounts] = []
|
115
|
+
else
|
116
|
+
options[:accounts] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
121
|
+
opts.footer = "Create an email template.\n" +
|
122
|
+
"[name] is required. This is the name of the new template."
|
123
|
+
end
|
124
|
+
|
125
|
+
optparse.parse!(args)
|
126
|
+
if args.count > 1
|
127
|
+
raise_command_error "wrong number of arguments, expected 0-2 and got (#{args.count}) #{args}\n#{optparse}"
|
128
|
+
end
|
129
|
+
connect(options)
|
130
|
+
|
131
|
+
begin
|
132
|
+
payload = nil
|
133
|
+
if options[:payload]
|
134
|
+
payload = options[:payload]
|
135
|
+
# support -O OPTION switch on top of --payload
|
136
|
+
payload['emailTemplate'] ||= {}
|
137
|
+
if options[:options]
|
138
|
+
payload['emailTemplate'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
|
139
|
+
end
|
140
|
+
|
141
|
+
if options[:type]
|
142
|
+
payload['emailTemplate']['type'] = options[:type]
|
143
|
+
end
|
144
|
+
|
145
|
+
if options[:template]
|
146
|
+
payload['emailTemplate']['template'] = options[:template]
|
147
|
+
end
|
148
|
+
|
149
|
+
if options[:accounts]
|
150
|
+
payload['emailTemplate']['accounts'] = options[:accounts]
|
151
|
+
end
|
152
|
+
|
153
|
+
else
|
154
|
+
payload = {'emailTemplate' => {}}
|
155
|
+
|
156
|
+
# Template Type
|
157
|
+
template_type_id = nil
|
158
|
+
template_type = options[:type] ? find_template_type_by_name_or_id(options[:type]) : nil
|
159
|
+
|
160
|
+
if template_type
|
161
|
+
template_type_id = template_type['id']
|
162
|
+
else
|
163
|
+
available_template_types = template_types_for_dropdown
|
164
|
+
|
165
|
+
if available_template_types.empty?
|
166
|
+
print_red_alert "A template type is required"
|
167
|
+
exit 1
|
168
|
+
elsif available_template_types.count > 1 && !options[:no_prompt]
|
169
|
+
template_type_code = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'templateType', 'type' => 'select', 'fieldLabel' => 'Template Type', 'selectOptions' => template_types_for_dropdown, 'required' => true, 'description' => 'Select Template Type.'}],options[:options],@api_client,{})
|
170
|
+
template_type_code = template_type_code["templateType"]
|
171
|
+
else
|
172
|
+
template_type_code = available_template_types.first['code']
|
173
|
+
end
|
174
|
+
#template_type = get_template_types.find { |ct| ct['code'] == template_type_code }
|
175
|
+
end
|
176
|
+
|
177
|
+
payload['emailTemplate']['code'] = template_type_code
|
178
|
+
payload['emailTemplate']['template'] = Morpheus::Cli::OptionTypes.file_content_prompt({'fieldName' => 'source', 'fieldLabel' => 'File Content', 'type' => 'file-content', 'required' => true}, {'source' => {'source' => 'local'}}, nil, {})['content']
|
179
|
+
# Tenants
|
180
|
+
if options[:accounts]
|
181
|
+
payload['emailTemplate']['accounts'] = options[:accounts]
|
182
|
+
else
|
183
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'accounts', 'fieldLabel' => 'Tenants', 'type' => 'text', 'required' => false, 'description' => 'Tenant accounts, comma separated list of account IDs'}], options)
|
184
|
+
payload['emailTemplate']['accounts'] = v_prompt['accounts']
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
@email_templates_interface.setopts(options)
|
189
|
+
if options[:dry_run]
|
190
|
+
print_dry_run @email_templates_interface.dry.create(payload)
|
191
|
+
return
|
192
|
+
end
|
193
|
+
json_response = @email_templates_interface.create(payload)
|
194
|
+
if options[:json]
|
195
|
+
print JSON.pretty_generate(json_response)
|
196
|
+
print "\n"
|
197
|
+
elsif json_response['success']
|
198
|
+
get_args = [json_response["emailTemplate"]["id"]] + (options[:remote] ? ["-r",options[:remote]] : []) + (options[:refresh_interval] ? ['--refresh', options[:refresh_interval].to_s] : [])
|
199
|
+
get(get_args)
|
200
|
+
else
|
201
|
+
print_rest_errors(json_response, options)
|
202
|
+
end
|
203
|
+
rescue RestClient::Exception => e
|
204
|
+
print_rest_exception(e, options)
|
205
|
+
exit 1
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def update(args)
|
210
|
+
options = {}
|
211
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
212
|
+
opts.banner = subcommand_usage( "[emailTemplate] --template")
|
213
|
+
opts.on("--template TEMPLATE", String, "Updates Email Template") do |val|
|
214
|
+
options[:template] = val.to_s
|
215
|
+
end
|
216
|
+
opts.on('--accounts LIST', Array, "Tenant accounts, comma separated list of account IDs") do |list|
|
217
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
218
|
+
options[:accounts] = []
|
219
|
+
else
|
220
|
+
options[:accounts] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
225
|
+
opts.footer = "Update an Email Template.\n" +
|
226
|
+
"[emailTemplate] is required. This is the name or id of an existing email template."
|
227
|
+
end
|
228
|
+
|
229
|
+
optparse.parse!(args)
|
230
|
+
if args.count != 1
|
231
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
232
|
+
end
|
233
|
+
connect(options)
|
234
|
+
|
235
|
+
begin
|
236
|
+
payload = nil
|
237
|
+
email_template = nil
|
238
|
+
|
239
|
+
if options[:payload]
|
240
|
+
payload = options[:payload]
|
241
|
+
# support -O OPTION switch on top of --payload
|
242
|
+
if options[:options]
|
243
|
+
payload['emailTemplate'] ||= {}
|
244
|
+
payload['emailTemplate'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
|
245
|
+
end
|
246
|
+
|
247
|
+
if !payload['emailTemplate'].empty?
|
248
|
+
email_template = find_by_name_or_id('emailTemplate', payload['emailTemplate']['id'] || payload['emailTemplate']['name'])
|
249
|
+
end
|
250
|
+
else
|
251
|
+
email_template = find_by_name_or_id('emailTemplate', args[0])
|
252
|
+
template_payload = {}
|
253
|
+
if options[:template]
|
254
|
+
template_payload['template'] = options[:template]
|
255
|
+
end
|
256
|
+
if options[:accounts]
|
257
|
+
template_payload['accounts'] = options[:accounts]
|
258
|
+
end
|
259
|
+
|
260
|
+
payload = {"emailTemplate" => template_payload}
|
261
|
+
end
|
262
|
+
|
263
|
+
if !email_template
|
264
|
+
print_red_alert "No templates available for update"
|
265
|
+
exit 1
|
266
|
+
end
|
267
|
+
|
268
|
+
if payload.empty?
|
269
|
+
print_green_success "Nothing to update"
|
270
|
+
exit 1
|
271
|
+
end
|
272
|
+
|
273
|
+
@email_templates_interface.setopts(options)
|
274
|
+
if options[:dry_run]
|
275
|
+
print_dry_run @email_templates_interface.dry.update(email_template['id'], payload)
|
276
|
+
return
|
277
|
+
end
|
278
|
+
json_response = @email_templates_interface.update(email_template['id'], payload)
|
279
|
+
if options[:json]
|
280
|
+
print JSON.pretty_generate(json_response)
|
281
|
+
print "\n"
|
282
|
+
elsif json_response['success']
|
283
|
+
get_args = [json_response["emailTemplate"]["id"]] + (options[:remote] ? ["-r",options[:remote]] : []) + (options[:refresh_interval] ? ['--refresh', options[:refresh_interval].to_s] : [])
|
284
|
+
get(get_args)
|
285
|
+
else
|
286
|
+
print_rest_errors(json_response, options)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def remove(args)
|
292
|
+
options = {}
|
293
|
+
query_params = {}
|
294
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
295
|
+
opts.banner = subcommand_usage("[emailTemplate]")
|
296
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
|
297
|
+
opts.footer = "Delete an email template.\n" +
|
298
|
+
"[emailTemplate] is required. This is the id of an existing email template.\n" +
|
299
|
+
"Note: You cannot remove System Templates, only those that you own/created."
|
300
|
+
end
|
301
|
+
optparse.parse!(args)
|
302
|
+
if args.count != 1
|
303
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
304
|
+
end
|
305
|
+
connect(options)
|
306
|
+
|
307
|
+
begin
|
308
|
+
email_template = find_by_name_or_id('emailTemplate', args[0])
|
309
|
+
|
310
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the email template '#{email_template['name']}'?", options)
|
311
|
+
return 9, "aborted command"
|
312
|
+
end
|
313
|
+
@email_templates_interface.setopts(options)
|
314
|
+
if options[:dry_run]
|
315
|
+
print_dry_run @email_templates_interface.dry.destroy(email_template['id'], query_params)
|
316
|
+
return
|
317
|
+
end
|
318
|
+
json_response = @email_templates_interface.destroy(email_template['id'], query_params)
|
319
|
+
if options[:json]
|
320
|
+
print JSON.pretty_generate(json_response)
|
321
|
+
print "\n"
|
322
|
+
elsif !options[:quiet]
|
323
|
+
msg = "Email Template #{email_template['name']} is being removed..."
|
324
|
+
if json_response['msg'] != nil && json_response['msg'] != ''
|
325
|
+
msg = json_response['msg']
|
326
|
+
end
|
327
|
+
print_green_success msg
|
328
|
+
|
329
|
+
end
|
330
|
+
rescue RestClient::Exception => e
|
331
|
+
print_rest_exception(e, options)
|
332
|
+
exit 1
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
def print_templates_table(templates, opts={})
|
339
|
+
columns = [
|
340
|
+
{"ID" => lambda {|it| it['id'] } },
|
341
|
+
{"Name" => lambda {|it| it['name'] } },
|
342
|
+
{"Owner" => lambda {|it| it['owner']['name'] || 'System'} },
|
343
|
+
{"Tenants" => lambda {|it| it['accounts'].collect {|a| a['name'] }.join(', ') rescue it['owner'] ? 'Global' : ''} }
|
344
|
+
|
345
|
+
# {"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
|
346
|
+
]
|
347
|
+
if opts[:include_fields]
|
348
|
+
columns = opts[:include_fields]
|
349
|
+
end
|
350
|
+
print as_pretty_table(templates, columns, opts)
|
351
|
+
end
|
352
|
+
|
353
|
+
def email_template_column_definitions()
|
354
|
+
{
|
355
|
+
"ID" => 'id',
|
356
|
+
"Name" => 'name',
|
357
|
+
"Owner" => lambda {|it| it['owner']['name'] || 'System' },
|
358
|
+
"Template" => lambda {|it| it['template'] rescue '' },
|
359
|
+
"Tenants" => lambda {|it| it['accounts'].collect {|a| a['name'] }.join(', ') rescue it['owner'] ? 'Global' : ''}
|
360
|
+
}
|
361
|
+
end
|
362
|
+
|
363
|
+
def template_types_for_dropdown
|
364
|
+
get_template_types.collect {|it| {'name' => it['name'], 'code' => it['value'], 'value' => it['value']} }
|
365
|
+
end
|
366
|
+
|
367
|
+
def get_template_types(refresh=false)
|
368
|
+
if !@template_types || refresh
|
369
|
+
@template_types = @email_templates_interface.template_types()['types']
|
370
|
+
end
|
371
|
+
@template_types
|
372
|
+
end
|
373
|
+
end
|
@@ -313,26 +313,26 @@ class Morpheus::Cli::License
|
|
313
313
|
used_discovered_objects = current_usage['discoveredObjects']
|
314
314
|
|
315
315
|
|
316
|
-
max_managed_servers = license["maxManagedServers"]
|
317
|
-
max_discovered_servers = license['maxDiscoveredServers']
|
318
|
-
max_hosts = license['maxHosts']
|
319
|
-
max_mvm = license['maxMvm']
|
320
|
-
max_iac = license['maxIac']
|
321
|
-
max_xaas = license['maxXaas']
|
322
|
-
max_executions = license['maxExecutions']
|
323
|
-
max_distributed_workers = license['maxDistributedWorkers']
|
324
|
-
max_discovered_objects = license['maxDiscoveredObjects']
|
316
|
+
max_managed_servers = license["maxManagedServers"]
|
317
|
+
max_discovered_servers = license['maxDiscoveredServers']
|
318
|
+
max_hosts = license['maxHosts']
|
319
|
+
max_mvm = license['maxMvm']
|
320
|
+
max_iac = license['maxIac']
|
321
|
+
max_xaas = license['maxXaas']
|
322
|
+
max_executions = license['maxExecutions']
|
323
|
+
max_distributed_workers = license['maxDistributedWorkers']
|
324
|
+
max_discovered_objects = license['maxDiscoveredObjects']
|
325
325
|
label_width = 20
|
326
326
|
chart_opts = {max_bars: 20, unlimited_label: '0%', percent_sigdig: 0}
|
327
327
|
out = ""
|
328
|
-
out << cyan + "Managed Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_managed_servers, max_managed_servers, chart_opts) + cyan + used_managed_servers.to_s.rjust(8, ' ') + " / " + (max_managed_servers
|
329
|
-
out << cyan + "Discovered Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_discovered_servers, max_discovered_servers, chart_opts) + cyan + used_discovered_servers.to_s.rjust(8, ' ') + " / " + (max_discovered_servers
|
330
|
-
out << cyan + "Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_hosts, max_hosts, chart_opts) + cyan + used_hosts.to_s.rjust(8, ' ') + " / " + (max_hosts
|
331
|
-
out << cyan + "MVM Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_mvm, max_mvm, chart_opts) + cyan + used_mvm.to_s.rjust(8, ' ') + " / " + (max_mvm
|
332
|
-
out << cyan + "Iac Deployments".rjust(label_width, ' ') + ": " + generate_usage_bar(used_iac, max_iac, chart_opts) + cyan + used_iac.to_s.rjust(8, ' ') + " / " + (max_iac
|
333
|
-
out << cyan + "Xaas Instances".rjust(label_width, ' ') + ": " + generate_usage_bar(used_xaas, max_xaas, chart_opts) + cyan + used_xaas.to_s.rjust(8, ' ') + " / " + (max_xaas
|
334
|
-
out << cyan + "Executions".rjust(label_width, ' ') + ": " + generate_usage_bar(used_executions, max_executions, chart_opts) + cyan + used_executions.to_s.rjust(8, ' ') + " / " + (max_executions
|
335
|
-
out << cyan + "Distributed Workers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_distributed_workers, max_distributed_workers, chart_opts) + cyan + used_distributed_workers.to_s.rjust(8, ' ') + " / " + (max_distributed_workers
|
328
|
+
out << cyan + "Managed Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_managed_servers, max_managed_servers, chart_opts) + cyan + used_managed_servers.to_s.rjust(8, ' ') + " / " + (max_managed_servers ? max_managed_servers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
329
|
+
out << cyan + "Discovered Servers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_discovered_servers, max_discovered_servers, chart_opts) + cyan + used_discovered_servers.to_s.rjust(8, ' ') + " / " + (max_discovered_servers ? max_discovered_servers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
330
|
+
out << cyan + "Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_hosts, max_hosts, chart_opts) + cyan + used_hosts.to_s.rjust(8, ' ') + " / " + (max_hosts ? max_hosts.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
331
|
+
out << cyan + "MVM Hosts".rjust(label_width, ' ') + ": " + generate_usage_bar(used_mvm, max_mvm, chart_opts) + cyan + used_mvm.to_s.rjust(8, ' ') + " / " + (max_mvm ? max_mvm.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
332
|
+
out << cyan + "Iac Deployments".rjust(label_width, ' ') + ": " + generate_usage_bar(used_iac, max_iac, chart_opts) + cyan + used_iac.to_s.rjust(8, ' ') + " / " + (max_iac ? max_iac.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
333
|
+
out << cyan + "Xaas Instances".rjust(label_width, ' ') + ": " + generate_usage_bar(used_xaas, max_xaas, chart_opts) + cyan + used_xaas.to_s.rjust(8, ' ') + " / " + (max_xaas ? max_xaas.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
334
|
+
out << cyan + "Executions".rjust(label_width, ' ') + ": " + generate_usage_bar(used_executions, max_executions, chart_opts) + cyan + used_executions.to_s.rjust(8, ' ') + " / " + (max_executions ? max_executions.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
335
|
+
out << cyan + "Distributed Workers".rjust(label_width, ' ') + ": " + generate_usage_bar(used_distributed_workers, max_distributed_workers, chart_opts) + cyan + used_distributed_workers.to_s.rjust(8, ' ') + " / " + (max_distributed_workers ? max_distributed_workers.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
336
336
|
#out << cyan + "Discovered Objects".rjust(label_width, ' ') + ": " + generate_usage_bar(used_discovered_objects, max_discovered_objects, chart_opts) + cyan + used_discovered_objects.to_s.rjust(8, ' ') + " / " + (max_discovered_objects.to_i > 0 ? max_discovered_objects.to_s : unlimited_label).to_s.ljust(15, ' ') + "\n"
|
337
337
|
print out
|
338
338
|
else
|
@@ -362,7 +362,7 @@ module Morpheus::Cli::PrintHelper
|
|
362
362
|
end
|
363
363
|
end
|
364
364
|
end
|
365
|
-
if payload
|
365
|
+
if payload #&& !payload.empty?
|
366
366
|
out << + ' \\' + "\n"
|
367
367
|
if headers && headers['Content-Type'] == 'application/json'
|
368
368
|
if payload.is_a?(String)
|
@@ -386,7 +386,7 @@ module Morpheus::Cli::PrintHelper
|
|
386
386
|
# pretty_size = Filesize.from("#{payload.size} B").pretty.strip
|
387
387
|
pretty_size = "#{payload.size} B"
|
388
388
|
# print "File: #{payload.path} (#{payload.size} bytes)"
|
389
|
-
out << " -
|
389
|
+
out << " --data-binary @#{payload.path}"
|
390
390
|
elsif payload.is_a?(String)
|
391
391
|
out << " -d '#{payload}'"
|
392
392
|
elsif payload.respond_to?(:map)
|
@@ -1256,6 +1256,7 @@ module Morpheus
|
|
1256
1256
|
file_params = passed_file_params
|
1257
1257
|
end
|
1258
1258
|
is_required = option_type['required']
|
1259
|
+
|
1259
1260
|
if file_params['source']
|
1260
1261
|
file_params['sourceType'] = file_params.delete('source')
|
1261
1262
|
end
|
@@ -1482,9 +1483,13 @@ module Morpheus
|
|
1482
1483
|
end
|
1483
1484
|
|
1484
1485
|
def self.sort_option_types(option_types)
|
1485
|
-
option_types.
|
1486
|
-
|
1487
|
-
|
1486
|
+
if option_types.find {|it| it['fieldGroup'] || it['displayOrder'] }
|
1487
|
+
option_types.select {|it| (it['fieldGroup'] || 'default').casecmp?('default')}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i} +
|
1488
|
+
option_types.reject {|it| ['default', 'advanced'].include?((it['fieldGroup'] || 'default').downcase)}.sort{|a,b| a['displayOrder'] <=> b['displayOrder']}.group_by{|it| it['fieldGroup']}.values.collect { |it| it.sort{|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}}.flatten +
|
1489
|
+
option_types.select {|it| 'advanced'.casecmp?(it['fieldGroup'])}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}
|
1490
|
+
else
|
1491
|
+
option_types
|
1492
|
+
end
|
1488
1493
|
end
|
1489
1494
|
|
1490
1495
|
def self.display_select_options(opt, select_options = [], paging = nil)
|
data/lib/morpheus/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2024-
|
14
|
+
date: 2024-05-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -229,6 +229,7 @@ files:
|
|
229
229
|
- lib/morpheus/api/datastores_interface.rb
|
230
230
|
- lib/morpheus/api/deploy_interface.rb
|
231
231
|
- lib/morpheus/api/deployments_interface.rb
|
232
|
+
- lib/morpheus/api/email_templates_interface.rb
|
232
233
|
- lib/morpheus/api/environments_interface.rb
|
233
234
|
- lib/morpheus/api/execute_schedules_interface.rb
|
234
235
|
- lib/morpheus/api/execution_request_interface.rb
|
@@ -414,6 +415,7 @@ files:
|
|
414
415
|
- lib/morpheus/cli/commands/echo_command.rb
|
415
416
|
- lib/morpheus/cli/commands/edit_profile_command.rb
|
416
417
|
- lib/morpheus/cli/commands/edit_rc_command.rb
|
418
|
+
- lib/morpheus/cli/commands/email_templates_command.rb
|
417
419
|
- lib/morpheus/cli/commands/environments_command.rb
|
418
420
|
- lib/morpheus/cli/commands/execute_schedules_command.rb
|
419
421
|
- lib/morpheus/cli/commands/execution_request_command.rb
|