morpheus-cli 7.0.1 → 7.0.2
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 +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/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
|
@@ -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
|