morpheus-cli 5.0.0 → 5.2.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/.gitignore +1 -0
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +16 -0
- data/lib/morpheus/api/billing_interface.rb +1 -0
- data/lib/morpheus/api/deploy_interface.rb +1 -1
- data/lib/morpheus/api/deployments_interface.rb +20 -1
- data/lib/morpheus/api/forgot_password_interface.rb +17 -0
- data/lib/morpheus/api/instances_interface.rb +16 -2
- data/lib/morpheus/api/invoices_interface.rb +12 -3
- data/lib/morpheus/api/search_interface.rb +13 -0
- data/lib/morpheus/api/servers_interface.rb +14 -0
- data/lib/morpheus/api/service_catalog_interface.rb +89 -0
- data/lib/morpheus/api/usage_interface.rb +18 -0
- data/lib/morpheus/cli.rb +6 -2
- data/lib/morpheus/cli/apps.rb +3 -23
- data/lib/morpheus/cli/budgets_command.rb +389 -319
- data/lib/morpheus/cli/{catalog_command.rb → catalog_item_types_command.rb} +182 -67
- data/lib/morpheus/cli/cli_command.rb +51 -10
- data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -13
- data/lib/morpheus/cli/commands/standard/history_command.rb +9 -3
- data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
- data/lib/morpheus/cli/containers_command.rb +0 -24
- data/lib/morpheus/cli/cypher_command.rb +6 -2
- data/lib/morpheus/cli/dashboard_command.rb +260 -20
- data/lib/morpheus/cli/deploy.rb +199 -90
- data/lib/morpheus/cli/deployments.rb +341 -28
- data/lib/morpheus/cli/deploys.rb +206 -41
- data/lib/morpheus/cli/error_handler.rb +7 -0
- data/lib/morpheus/cli/forgot_password.rb +133 -0
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/health_command.rb +59 -2
- data/lib/morpheus/cli/hosts.rb +271 -39
- data/lib/morpheus/cli/instances.rb +228 -129
- data/lib/morpheus/cli/invoices_command.rb +100 -20
- data/lib/morpheus/cli/jobs_command.rb +94 -92
- data/lib/morpheus/cli/library_option_lists_command.rb +1 -1
- data/lib/morpheus/cli/library_option_types_command.rb +10 -5
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -1
- data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -2
- data/lib/morpheus/cli/mixins/print_helper.rb +13 -27
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +108 -5
- data/lib/morpheus/cli/option_types.rb +271 -22
- data/lib/morpheus/cli/remote.rb +35 -10
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/roles.rb +193 -155
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +33 -11
- data/lib/morpheus/cli/tasks.rb +29 -32
- data/lib/morpheus/cli/usage_command.rb +64 -11
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +429 -254
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +33 -40
- data/lib/morpheus/formatters.rb +75 -18
- data/lib/morpheus/terminal.rb +6 -2
- metadata +10 -4
- data/lib/morpheus/cli/mixins/catalog_helper.rb +0 -66
data/lib/morpheus/cli/deploys.rb
CHANGED
@@ -4,13 +4,10 @@ require 'yaml'
|
|
4
4
|
class Morpheus::Cli::Deploys
|
5
5
|
include Morpheus::Cli::CliCommand
|
6
6
|
include Morpheus::Cli::DeploymentsHelper
|
7
|
-
|
8
|
-
# hidden until api support is added
|
9
|
-
set_command_hidden
|
10
7
|
|
11
8
|
set_command_name :deploys
|
12
|
-
|
13
|
-
register_subcommands :list, :get, :add, :remove, :deploy
|
9
|
+
set_command_description "View and manage instance deploys."
|
10
|
+
register_subcommands :list, :get, :add, :update, :remove, :deploy
|
14
11
|
|
15
12
|
def connect(opts)
|
16
13
|
@api_client = establish_remote_appliance_connection(opts)
|
@@ -70,10 +67,10 @@ EOT
|
|
70
67
|
options = {}
|
71
68
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
72
69
|
opts.banner = subcommand_usage("[id]")
|
73
|
-
build_standard_get_options(opts, options)
|
70
|
+
build_standard_get_options(opts, options, [:details])
|
74
71
|
opts.footer = <<-EOT
|
75
72
|
Get details about a specific instance deploy.
|
76
|
-
[id] is required. This is the
|
73
|
+
[id] is required. This is the id of an instance deploy.
|
77
74
|
EOT
|
78
75
|
end
|
79
76
|
optparse.parse!(args)
|
@@ -93,10 +90,18 @@ EOT
|
|
93
90
|
end
|
94
91
|
json_response = @deploy_interface.get(id, params)
|
95
92
|
app_deploy = json_response[app_deploy_object_key]
|
93
|
+
deploy_config = app_deploy['config']
|
96
94
|
render_response(json_response, options, app_deploy_object_key) do
|
97
95
|
print_h1 "Deploy Details", [], options
|
98
96
|
print cyan
|
99
97
|
print_description_list(app_deploy_column_definitions, app_deploy)
|
98
|
+
|
99
|
+
if options[:details] && deploy_config && !deploy_config.empty?
|
100
|
+
print_h2 "Config", options
|
101
|
+
print cyan
|
102
|
+
print as_description_list(deploy_config, deploy_config.keys, options)
|
103
|
+
end
|
104
|
+
|
100
105
|
print reset,"\n"
|
101
106
|
end
|
102
107
|
return 0, nil
|
@@ -109,9 +114,46 @@ EOT
|
|
109
114
|
opts.banner = subcommand_usage("[instance] [deployment] [version] [options]")
|
110
115
|
build_option_type_options(opts, options, add_app_deploy_option_types)
|
111
116
|
build_option_type_options(opts, options, add_app_deploy_advanced_option_types)
|
117
|
+
opts.on(nil, "--stage", "Stage Only, do not run the deployment right away.") do |val|
|
118
|
+
params['stageOnly'] = true
|
119
|
+
end
|
120
|
+
opts.on("-c", "--config JSON", String, "Config for deployment") do |val|
|
121
|
+
parse_result = parse_json_or_yaml(val)
|
122
|
+
config_map = parse_result[:data]
|
123
|
+
if config_map.nil?
|
124
|
+
# todo: bubble up JSON.parse error message
|
125
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
126
|
+
else
|
127
|
+
params['config'] = config_map
|
128
|
+
options[:options]['config'] = params['config'] # or file_content
|
129
|
+
end
|
130
|
+
end
|
131
|
+
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
132
|
+
options[:config_file] = val.to_s
|
133
|
+
file_content = nil
|
134
|
+
full_filename = File.expand_path(options[:config_file])
|
135
|
+
if File.exists?(full_filename)
|
136
|
+
file_content = File.read(full_filename)
|
137
|
+
else
|
138
|
+
print_red_alert "File not found: #{full_filename}"
|
139
|
+
return 1
|
140
|
+
end
|
141
|
+
parse_result = parse_json_or_yaml(file_content)
|
142
|
+
config_map = parse_result[:data]
|
143
|
+
if config_map.nil?
|
144
|
+
# todo: bubble up JSON.parse error message
|
145
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
146
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
147
|
+
else
|
148
|
+
params['config'] = config_map
|
149
|
+
options[:options]['config'] = params['config'] # or file_content
|
150
|
+
end
|
151
|
+
end
|
112
152
|
build_standard_add_options(opts, options)
|
113
153
|
opts.footer = <<-EOT
|
114
154
|
Create a new instance deploy.
|
155
|
+
This deploys a specific deployment version to a target instance.
|
156
|
+
By default the deployment is run right away, unless the --stage option is used.
|
115
157
|
EOT
|
116
158
|
end
|
117
159
|
optparse.parse!(args)
|
@@ -134,11 +176,110 @@ EOT
|
|
134
176
|
payload[app_deploy_object_key].deep_merge!(params)
|
135
177
|
end
|
136
178
|
@deploy_interface.setopts(options)
|
179
|
+
instance_id = payload[app_deploy_object_key]['instance']
|
137
180
|
if options[:dry_run]
|
138
|
-
print_dry_run @deploy_interface.dry.create(payload)
|
181
|
+
print_dry_run @deploy_interface.dry.create(instance_id, payload)
|
139
182
|
return 0, nil
|
140
183
|
end
|
141
|
-
|
184
|
+
# unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to deploy?")
|
185
|
+
# return 9, "aborted command"
|
186
|
+
# end
|
187
|
+
json_response = @deploy_interface.create(instance_id, payload)
|
188
|
+
app_deploy = json_response[app_deploy_object_key]
|
189
|
+
render_response(json_response, options, app_deploy_object_key) do
|
190
|
+
if app_deploy['status'] == 'staged'
|
191
|
+
begin
|
192
|
+
print_green_success "Staged Deploy #{app_deploy['deployment']['name']} version #{app_deploy['deploymentVersion']['userVersion']} to instance #{app_deploy['instance']['name']}"
|
193
|
+
rescue => ex
|
194
|
+
print_green_success "Staged Deploy"
|
195
|
+
end
|
196
|
+
else
|
197
|
+
begin
|
198
|
+
print_green_success "Deploying #{app_deploy['deployment']['name']} version #{app_deploy['deploymentVersion']['userVersion']} to instance #{app_deploy['instance']['name']}"
|
199
|
+
rescue => ex
|
200
|
+
print_green_success "Deploying"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
return _get(app_deploy["id"], {}, options)
|
204
|
+
end
|
205
|
+
return 0, nil
|
206
|
+
end
|
207
|
+
|
208
|
+
def update(args)
|
209
|
+
options = {}
|
210
|
+
params = {}
|
211
|
+
payload = {}
|
212
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
213
|
+
opts.banner = subcommand_usage("[id] [options]")
|
214
|
+
opts.on("-c", "--config JSON", String, "Config for deployment") do |val|
|
215
|
+
parse_result = parse_json_or_yaml(val)
|
216
|
+
config_map = parse_result[:data]
|
217
|
+
if config_map.nil?
|
218
|
+
# todo: bubble up JSON.parse error message
|
219
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
220
|
+
else
|
221
|
+
params['config'] = config_map
|
222
|
+
options[:options]['config'] = params['config'] # or file_content
|
223
|
+
end
|
224
|
+
end
|
225
|
+
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
226
|
+
options[:config_file] = val.to_s
|
227
|
+
file_content = nil
|
228
|
+
full_filename = File.expand_path(options[:config_file])
|
229
|
+
if File.exists?(full_filename)
|
230
|
+
file_content = File.read(full_filename)
|
231
|
+
else
|
232
|
+
print_red_alert "File not found: #{full_filename}"
|
233
|
+
return 1
|
234
|
+
end
|
235
|
+
parse_result = parse_json_or_yaml(file_content)
|
236
|
+
config_map = parse_result[:data]
|
237
|
+
if config_map.nil?
|
238
|
+
# todo: bubble up JSON.parse error message
|
239
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
240
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
241
|
+
else
|
242
|
+
params['config'] = config_map
|
243
|
+
options[:options]['config'] = params['config'] # or file_content
|
244
|
+
end
|
245
|
+
end
|
246
|
+
#build_option_type_options(opts, options, update_app_deploy_option_types)
|
247
|
+
#build_option_type_options(opts, options, update_app_deploy_advanced_option_types)
|
248
|
+
build_standard_update_options(opts, options)
|
249
|
+
opts.footer = <<-EOT
|
250
|
+
Update an instance deploy.
|
251
|
+
[id] is required. This is the id of an instance deploy.
|
252
|
+
EOT
|
253
|
+
end
|
254
|
+
optparse.parse!(args)
|
255
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
256
|
+
connect(options)
|
257
|
+
app_deploy = find_app_deploy_by_id(args[0])
|
258
|
+
return 1 if app_deploy.nil?
|
259
|
+
payload = {}
|
260
|
+
if options[:payload]
|
261
|
+
payload = options[:payload]
|
262
|
+
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
263
|
+
else
|
264
|
+
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
265
|
+
# do not prompt on update
|
266
|
+
#v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_option_types, options[:options], @api_client, options[:params])
|
267
|
+
#v_prompt.deep_compact!
|
268
|
+
#params.deep_merge!(v_prompt)
|
269
|
+
#advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_advanced_option_types, options[:options], @api_client, options[:params])
|
270
|
+
#advanced_config.deep_compact!
|
271
|
+
#params.deep_merge!(advanced_config)
|
272
|
+
payload.deep_merge!({app_deploy_object_key => params})
|
273
|
+
if payload[app_deploy_object_key].empty? # || options[:no_prompt]
|
274
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
@deploy_interface.setopts(options)
|
278
|
+
if options[:dry_run]
|
279
|
+
print_dry_run @deploy_interface.dry.update(app_deploy['id'], payload)
|
280
|
+
return
|
281
|
+
end
|
282
|
+
json_response = @deploy_interface.update(app_deploy['id'], payload)
|
142
283
|
app_deploy = json_response[app_deploy_object_key]
|
143
284
|
render_response(json_response, options, app_deploy_object_key) do
|
144
285
|
print_green_success "Deploying..."
|
@@ -155,7 +296,7 @@ EOT
|
|
155
296
|
build_standard_remove_options(opts, options)
|
156
297
|
opts.footer = <<-EOT
|
157
298
|
Delete an instance deploy.
|
158
|
-
[id] is required. This is the
|
299
|
+
[id] is required. This is the id of an instance deploy.
|
159
300
|
EOT
|
160
301
|
end
|
161
302
|
optparse.parse!(args)
|
@@ -163,6 +304,9 @@ EOT
|
|
163
304
|
connect(options)
|
164
305
|
app_deploy = find_app_deploy_by_id(args[0])
|
165
306
|
return 1 if app_deploy.nil?
|
307
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the deploy #{app_deploy['id']}?")
|
308
|
+
return 9, "aborted command"
|
309
|
+
end
|
166
310
|
@deploy_interface.setopts(options)
|
167
311
|
if options[:dry_run]
|
168
312
|
print_dry_run @deploy_interface.dry.destroy(app_deploy['id'], params)
|
@@ -170,7 +314,7 @@ EOT
|
|
170
314
|
end
|
171
315
|
json_response = @deploy_interface.destroy(app_deploy['id'], params)
|
172
316
|
render_response(json_response, options) do
|
173
|
-
print_green_success "Removed deploy #{app_deploy['
|
317
|
+
print_green_success "Removed deploy #{app_deploy['id']}"
|
174
318
|
end
|
175
319
|
return 0, nil
|
176
320
|
end
|
@@ -181,12 +325,44 @@ EOT
|
|
181
325
|
payload = {}
|
182
326
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
183
327
|
opts.banner = subcommand_usage("[id] [options]")
|
184
|
-
|
185
|
-
|
186
|
-
|
328
|
+
opts.on("-c", "--config JSON", String, "Config for deployment") do |val|
|
329
|
+
parse_result = parse_json_or_yaml(val)
|
330
|
+
config_map = parse_result[:data]
|
331
|
+
if config_map.nil?
|
332
|
+
# todo: bubble up JSON.parse error message
|
333
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
334
|
+
else
|
335
|
+
params['config'] = config_map
|
336
|
+
options[:options]['config'] = params['config'] # or file_content
|
337
|
+
end
|
338
|
+
end
|
339
|
+
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
340
|
+
options[:config_file] = val.to_s
|
341
|
+
file_content = nil
|
342
|
+
full_filename = File.expand_path(options[:config_file])
|
343
|
+
if File.exists?(full_filename)
|
344
|
+
file_content = File.read(full_filename)
|
345
|
+
else
|
346
|
+
print_red_alert "File not found: #{full_filename}"
|
347
|
+
return 1
|
348
|
+
end
|
349
|
+
parse_result = parse_json_or_yaml(file_content)
|
350
|
+
config_map = parse_result[:data]
|
351
|
+
if config_map.nil?
|
352
|
+
# todo: bubble up JSON.parse error message
|
353
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
354
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
355
|
+
else
|
356
|
+
params['config'] = config_map
|
357
|
+
options[:options]['config'] = params['config'] # or file_content
|
358
|
+
end
|
359
|
+
end
|
360
|
+
#build_option_type_options(opts, options, update_app_deploy_option_types)
|
361
|
+
#build_option_type_options(opts, options, update_app_deploy_advanced_option_types)
|
362
|
+
build_standard_update_options(opts, options, [:auto_confirm])
|
187
363
|
opts.footer = <<-EOT
|
188
|
-
|
189
|
-
[id] is required. This is the
|
364
|
+
Deploy an instance deploy.
|
365
|
+
[id] is required. This is the id of an instance deploy.
|
190
366
|
EOT
|
191
367
|
end
|
192
368
|
optparse.parse!(args)
|
@@ -201,23 +377,26 @@ EOT
|
|
201
377
|
else
|
202
378
|
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
203
379
|
# do not prompt on update
|
204
|
-
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_option_types, options[:options], @api_client, options[:params])
|
205
|
-
v_prompt.deep_compact!
|
206
|
-
params.deep_merge!(v_prompt)
|
207
|
-
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_advanced_option_types, options[:options], @api_client, options[:params])
|
208
|
-
advanced_config.deep_compact!
|
209
|
-
params.deep_merge!(advanced_config)
|
380
|
+
#v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_option_types, options[:options], @api_client, options[:params])
|
381
|
+
#v_prompt.deep_compact!
|
382
|
+
#params.deep_merge!(v_prompt)
|
383
|
+
#advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_advanced_option_types, options[:options], @api_client, options[:params])
|
384
|
+
#advanced_config.deep_compact!
|
385
|
+
#params.deep_merge!(advanced_config)
|
210
386
|
payload.deep_merge!({app_deploy_object_key => params})
|
211
|
-
if payload[app_deploy_object_key].empty? # || options[:no_prompt]
|
212
|
-
|
213
|
-
end
|
387
|
+
# if payload[app_deploy_object_key].empty? # || options[:no_prompt]
|
388
|
+
# raise_command_error "Specify at least one option to update.\n#{optparse}"
|
389
|
+
# end
|
390
|
+
end
|
391
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to deploy #{app_deploy['deployment']['name']} version #{app_deploy['deploymentVersion']['userVersion']} to instance #{app_deploy['instance']['name']}?")
|
392
|
+
return 9, "aborted command"
|
214
393
|
end
|
215
394
|
@deploy_interface.setopts(options)
|
216
395
|
if options[:dry_run]
|
217
396
|
print_dry_run @deploy_interface.dry.update(app_deploy['id'], payload)
|
218
397
|
return
|
219
398
|
end
|
220
|
-
json_response = @deploy_interface.
|
399
|
+
json_response = @deploy_interface.deploy(app_deploy['id'], payload)
|
221
400
|
app_deploy = json_response[app_deploy_object_key]
|
222
401
|
render_response(json_response, options, app_deploy_object_key) do
|
223
402
|
print_green_success "Deploying..."
|
@@ -225,6 +404,7 @@ EOT
|
|
225
404
|
end
|
226
405
|
return 0, nil
|
227
406
|
end
|
407
|
+
|
228
408
|
private
|
229
409
|
|
230
410
|
## Deploys (AppDeploy)
|
@@ -302,20 +482,5 @@ EOT
|
|
302
482
|
}
|
303
483
|
end
|
304
484
|
|
305
|
-
def format_app_deploy_status(status, return_color=cyan)
|
306
|
-
out = ""
|
307
|
-
s = status.to_s.downcase
|
308
|
-
if s == 'deployed'
|
309
|
-
out << "#{green}#{s.upcase}#{return_color}"
|
310
|
-
elsif s == 'open' || s == 'archived' || s == 'committed'
|
311
|
-
out << "#{cyan}#{s.upcase}#{return_color}"
|
312
|
-
elsif s == 'failed'
|
313
|
-
out << "#{red}#{s.upcase}#{return_color}"
|
314
|
-
else
|
315
|
-
out << "#{yellow}#{s.upcase}#{return_color}"
|
316
|
-
end
|
317
|
-
out
|
318
|
-
end
|
319
|
-
|
320
485
|
end
|
321
486
|
|
@@ -25,6 +25,13 @@ class Morpheus::Cli::ErrorHandler
|
|
25
25
|
#@stderr.puts "#{dark}Handling error #{err.class} - #{err}#{reset}"
|
26
26
|
|
27
27
|
case (err)
|
28
|
+
# when Morpheus::Cli::CommandNotFoundError
|
29
|
+
# puts_angry_error err.message
|
30
|
+
# @stderr.puts "Try help to see a list of available commands"
|
31
|
+
# do_print_stacktrace = false
|
32
|
+
# if err.exit_code
|
33
|
+
# exit_code = err.exit_code
|
34
|
+
# end
|
28
35
|
when ::OptionParser::InvalidOption, ::OptionParser::AmbiguousOption,
|
29
36
|
::OptionParser::MissingArgument, ::OptionParser::InvalidArgument,
|
30
37
|
::OptionParser::NeedlessArgument
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::ForgotPassword
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
|
6
|
+
set_command_name :'forgot'
|
7
|
+
set_command_description "Send a forgot password email and reset your password."
|
8
|
+
|
9
|
+
def connect(opts)
|
10
|
+
@api_client = establish_remote_appliance_connection(opts)
|
11
|
+
@forgot_interface = @api_client.forgot
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle(args)
|
15
|
+
# handle_subcommand(args)
|
16
|
+
# end
|
17
|
+
|
18
|
+
# def email(args)
|
19
|
+
options = {}
|
20
|
+
params = {}
|
21
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
22
|
+
opts.banner = "Usage: #{prog_name} #{command_name} [username]"
|
23
|
+
opts.on( '-U', '--username USERNAME', "Username of the user to be emailed." ) do |val|
|
24
|
+
options[:options]['username'] = val
|
25
|
+
end
|
26
|
+
opts.on("--email [USERNAME]", String, "Email only. Only send an email, skip the reset password.") do |val|
|
27
|
+
options[:email_only] = true
|
28
|
+
if !val.to_s.empty?
|
29
|
+
options[:options]['username'] = val
|
30
|
+
end
|
31
|
+
end
|
32
|
+
opts.on("--reset [TOKEN]", "Reset only. Only reset password, skip sending an email.") do |val|
|
33
|
+
options[:reset_only] = true
|
34
|
+
if !val.to_s.empty?
|
35
|
+
options[:options]['token'] = val
|
36
|
+
end
|
37
|
+
end
|
38
|
+
opts.on( '-T', '--token TOKEN', "Token, the secret token that was emailed to the user. Only reset password, skip sending an email." ) do |val|
|
39
|
+
options[:reset_only] = true
|
40
|
+
options[:options]['token'] = val
|
41
|
+
end
|
42
|
+
opts.on( '-P', '--password PASSWORD', "New Password, the new password for the user." ) do |val|
|
43
|
+
options[:options]['password'] = val
|
44
|
+
end
|
45
|
+
|
46
|
+
build_standard_post_options(opts, options, [], [:remote_username,:remote_password,:remote_token])
|
47
|
+
opts.footer = <<-EOT
|
48
|
+
Send a forgot password email and reset your password.
|
49
|
+
[username] is required. This is the username to be notified.
|
50
|
+
By default this command prompts to perform two actions.
|
51
|
+
First it sends a forgot password email to the specified user.
|
52
|
+
Then it attempts to reset the password with the secret token and a new password.
|
53
|
+
Use the --email and --token options to only perform one of these actions, instead of prompting to do both.
|
54
|
+
That is, only send the email or only reset the password.
|
55
|
+
|
56
|
+
EOT
|
57
|
+
end
|
58
|
+
optparse.parse!(args)
|
59
|
+
connect(options)
|
60
|
+
verify_args!(args:args, optparse:optparse, max:1)
|
61
|
+
|
62
|
+
if options[:email_only] && options[:options]['token']
|
63
|
+
raise_command_error "Invalid usage. --email cannot be used with --token or --reset, use one or the other", args, optparse
|
64
|
+
end
|
65
|
+
|
66
|
+
if args[0]
|
67
|
+
options[:options]['username'] = args[0]
|
68
|
+
end
|
69
|
+
|
70
|
+
params.merge!(parse_query_options(options))
|
71
|
+
|
72
|
+
# Step 1. Send Forgot Password Email
|
73
|
+
if options[:reset_only] != true
|
74
|
+
print_h1 "Forgot Password", [], options unless options[:quiet] || options[:json] || options[:yaml]
|
75
|
+
payload = {}
|
76
|
+
payload['username'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'username', 'fieldLabel' => 'Username', 'type' => 'text', 'description' => "Enter the username of your Morpheus User.", 'required' => true, :fmt => :natural}], options[:options],@api_client)['username']
|
77
|
+
@forgot_interface.setopts(options)
|
78
|
+
if options[:dry_run]
|
79
|
+
print_dry_run @forgot_interface.dry.send_email(payload, params)
|
80
|
+
return
|
81
|
+
end
|
82
|
+
json_response = @forgot_interface.send_email(payload, params)
|
83
|
+
if options[:email_only]
|
84
|
+
render_response(json_response, options) do
|
85
|
+
print_green_success(json_response["msg"] || "Email has been sent") unless options[:quiet]
|
86
|
+
end
|
87
|
+
return 0, nil
|
88
|
+
else
|
89
|
+
print_green_success(json_response["msg"] || "Email has been sent") unless options[:quiet]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Step 2. Reset Password
|
94
|
+
print_h1 "Reset Password", [], options unless options[:quiet] || options[:json] || options[:yaml]
|
95
|
+
payload = {}
|
96
|
+
if options[:payload]
|
97
|
+
payload = options[:payload]
|
98
|
+
payload.deep_merge!(parse_passed_options(options))
|
99
|
+
else
|
100
|
+
payload.deep_merge!(parse_passed_options(options))
|
101
|
+
# prompt for Token
|
102
|
+
payload['token'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'token', 'fieldLabel' => 'Token', 'type' => 'text', 'description' => "Enter the token that you obtained from the forgot password email.", 'required' => true, :fmt => :natural}], options[:options],@api_client)['token']
|
103
|
+
# New Password
|
104
|
+
# todo: prompt_password_with_confirmation()
|
105
|
+
password_value = options[:options]['password']
|
106
|
+
confirm_password_value = password_value
|
107
|
+
while password_value.to_s.empty?
|
108
|
+
password_value = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'password', 'fieldLabel' => 'New Password', 'type' => 'password', 'description' => "Enter your new password.", 'required' => true, :fmt => :natural}], options[:options],@api_client)['password']
|
109
|
+
confirm_password_value = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'password', 'fieldLabel' => 'Confirm New Password', 'type' => 'password', 'description' => "Enter your new password again to confirm it is what you intend.", 'required' => true, :fmt => :natural}], options[:options],@api_client)['password']
|
110
|
+
if password_value != confirm_password_value
|
111
|
+
print_red_alert("Passwords did not match. Please try again.")
|
112
|
+
password_value = nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
payload['password'] = password_value
|
116
|
+
end
|
117
|
+
|
118
|
+
@forgot_interface.setopts(options)
|
119
|
+
if options[:dry_run]
|
120
|
+
print_dry_run @forgot_interface.dry.reset_password(payload, params)
|
121
|
+
return
|
122
|
+
end
|
123
|
+
json_response = @forgot_interface.reset_password(payload, params)
|
124
|
+
render_response(json_response, options) do
|
125
|
+
print_green_success(json_response["msg"] || "Password has been updated") unless options[:quiet]
|
126
|
+
end
|
127
|
+
return 0, nil
|
128
|
+
end
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
end
|
133
|
+
|