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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8864c6fde23535cdf51e56b3bc94a8cb33c5a0d3fbe5f1a81e9ca9b16481b2b8
4
- data.tar.gz: 747c7097e26216cb0e088f289b789f9b3e2b8e71563457b831069aa27e66aa71
3
+ metadata.gz: b6cc9570fd3a41bf3c6ec4fb5b5ab5801171554a630eb269af90dcc6672fe141
4
+ data.tar.gz: 63150328a3155ed9ba99d57963be4e16eab3e54934eff64f94070b4fbf485c40
5
5
  SHA512:
6
- metadata.gz: 94cfd0a6625753fd42090fe83bdedc08826fb19486135c2d89bc2f449314bc53b053f3e86210d3ab6c5c35add845fc303d9dbfe4fb13a27b324dde927f6b05bb
7
- data.tar.gz: 492eed20dd75f0a10fc53275a6bd5b5044ea5286d26f8bd37c3736c4893a69488e1c4f6aaabfbc289dd5fd8a2229f3b5b947f1872dd0dc57c84063a001a20412
6
+ metadata.gz: 7d2375caf166551c16c460bf0b1cae7e2b672534c9a29a784408e2eac9e4fc336e01d93685ce5e0572933285a9e4766bc304314f8abfb2d62b700e09b9190f14
7
+ data.tar.gz: f30d57bcf10c3b3cb976329ec94a4ffff39f66da33ceffab25a7ab5246f921070f41547fe2b9c5f77de8e8814fc2ca8bf66855f93cf390044eac2fa76ba83ff3
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.7.5
2
2
 
3
- RUN gem install morpheus-cli -v 7.0.1
3
+ RUN gem install morpheus-cli -v 7.0.2
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -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, 'displayOrder' => 1},
579
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 1},
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, 'displayOrder' => 3},
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', 'displayOrder' => 4},
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', 'displayOrder' => 5},
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', 'displayOrder' => 6},
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', 'displayOrder' => 7},
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", 'displayOrder' => 8},
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', 'displayOrder' => 9},
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', 'displayOrder' => 10},
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"', 'displayOrder' => 11}
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
- if !['resourcePoolId', 'resourceGroup', 'vpc'].find { |it| cloud['config'][it] && cloud['config'][it].length > 0 }
4281
- resource_pool_id = nil
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
- if !resource_pool
4285
- 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? }
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
- if resource_pool_options.empty?
4288
- print_red_alert "Cloud #{cloud['name']} has no available resource pools"
4289
- exit 1
4290
- elsif resource_pool_options.count > 1 && !options[:no_prompt]
4291
- 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']
4292
- else
4293
- resource_pool_id = resource_pool_options.first['id']
4294
- end
4295
- if resource_pool_id.to_s["poolGroup-"]
4296
- resource_pool = @resource_pool_groups_interface.get(resource_pool_id)['resourcePoolGroup']
4297
- else
4298
- resource_pool = @cloud_resource_pools_interface.get(cloud['id'], resource_pool_id)['resourcePool']
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 && !payload.empty?
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 << " -d @#{payload.path}"
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.select {|it| (it['fieldGroup'] || 'default').casecmp?('default')}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i} +
1486
- 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 +
1487
- option_types.select {|it| 'advanced'.casecmp?(it['fieldGroup'])}.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}
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)
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "7.0.1"
4
+ VERSION = "7.0.2"
5
5
  end
6
6
  end
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.1
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-04-17 00:00:00.000000000 Z
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