morpheus-cli 6.1.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +8 -4
  4. data/lib/morpheus/api/backup_jobs_interface.rb +4 -0
  5. data/lib/morpheus/api/backup_restores_interface.rb +23 -0
  6. data/lib/morpheus/api/backup_results_interface.rb +28 -0
  7. data/lib/morpheus/api/backups_interface.rb +5 -4
  8. data/lib/morpheus/cli/cli_command.rb +172 -45
  9. data/lib/morpheus/cli/commands/appliance_settings_command.rb +7 -19
  10. data/lib/morpheus/cli/commands/apps.rb +1 -1
  11. data/lib/morpheus/cli/commands/backup_jobs_command.rb +77 -20
  12. data/lib/morpheus/cli/commands/backup_restores_command.rb +144 -0
  13. data/lib/morpheus/cli/commands/backup_results_command.rb +149 -0
  14. data/lib/morpheus/cli/commands/backups_command.rb +214 -93
  15. data/lib/morpheus/cli/commands/hosts.rb +15 -2
  16. data/lib/morpheus/cli/commands/instances.rb +23 -3
  17. data/lib/morpheus/cli/commands/load_balancer_pools.rb +37 -1
  18. data/lib/morpheus/cli/commands/security_groups.rb +58 -37
  19. data/lib/morpheus/cli/commands/service_catalog_command.rb +50 -83
  20. data/lib/morpheus/cli/commands/view.rb +20 -20
  21. data/lib/morpheus/cli/mixins/backups_helper.rb +58 -0
  22. data/lib/morpheus/cli/mixins/print_helper.rb +27 -4
  23. data/lib/morpheus/cli/option_types.rb +10 -7
  24. data/lib/morpheus/cli/version.rb +1 -1
  25. data/lib/morpheus/formatters.rb +1 -1
  26. data/lib/morpheus/routes.rb +18 -3
  27. metadata +6 -8
  28. data/lib/morpheus/api/doc_interface.rb +0 -50
  29. data/lib/morpheus/cli/commands/doc.rb +0 -182
  30. data/test/api/doc_interface_test.rb +0 -35
  31. data/test/cli/doc_test.rb +0 -35
@@ -1,3 +1,4 @@
1
+
1
2
  require 'morpheus/cli/cli_command'
2
3
 
3
4
  class Morpheus::Cli::BackupsCommand
@@ -5,17 +6,20 @@ class Morpheus::Cli::BackupsCommand
5
6
  include Morpheus::Cli::BackupsHelper
6
7
  include Morpheus::Cli::ProvisioningHelper
7
8
  include Morpheus::Cli::OptionSourceHelper
8
-
9
- set_command_hidden # hide until ready
10
9
 
10
+ set_command_description "View and manage backups"
11
11
  set_command_name :'backups'
12
+ register_subcommands :list, :get, :add, :update, :remove, :execute #, :restore
13
+ register_subcommands :list_jobs, :get_job, :add_job, :update_job, :remove_job, :execute_job
14
+ register_subcommands :list_results, :get_result, :remove_result
15
+ register_subcommands :list_restores, :get_restore, :remove_restore
12
16
 
13
- register_subcommands :list, :get, :add, :update, :remove, :run, :restore
14
-
15
17
  def connect(opts)
16
18
  @api_client = establish_remote_appliance_connection(opts)
17
19
  @backups_interface = @api_client.backups
18
20
  @backup_jobs_interface = @api_client.backup_jobs
21
+ @backup_results_interface = @api_client.backup_results
22
+ @backup_restores_interface = @api_client.backup_restores
19
23
  @instances_interface = @api_client.instances
20
24
  @servers_interface = @api_client.servers
21
25
  end
@@ -40,14 +44,9 @@ class Morpheus::Cli::BackupsCommand
40
44
  options[:phrase] = args.join(" ")
41
45
  end
42
46
  params.merge!(parse_list_options(options))
43
- @backups_interface.setopts(options)
44
- if options[:dry_run]
45
- print_dry_run @backups_interface.dry.list(params)
46
- return
47
- end
48
- json_response = @backups_interface.list(params)
49
- backups = json_response['backups']
50
- render_response(json_response, options, 'backups') do
47
+ parse_options(options, params)
48
+ execute_api(@backups_interface, :list, [], options, 'backup') do |json_response|
49
+ backups = json_response['backups']
51
50
  print_h1 "Morpheus Backups", parse_list_subtitles(options), options
52
51
  if backups.empty?
53
52
  print cyan,"No backups found.",reset,"\n"
@@ -74,6 +73,7 @@ EOT
74
73
  optparse.parse!(args)
75
74
  verify_args!(args:args, optparse:optparse, min:1)
76
75
  connect(options)
76
+ parse_options(options, params)
77
77
  id_list = parse_id_list(args)
78
78
  return run_command_for_each_arg(id_list) do |arg|
79
79
  _get(arg, params, options)
@@ -88,14 +88,10 @@ EOT
88
88
  end
89
89
  id = record['id']
90
90
  end
91
- @backups_interface.setopts(options)
92
- if options[:dry_run]
93
- print_dry_run @backups_interface.dry.get(id, params)
94
- return
95
- end
96
- json_response = @backups_interface.get(id, params)
97
- backup = json_response['backup']
98
- render_response(json_response, options, 'backup') do
91
+ options[:params] = params # parse_options(options, params)
92
+ options.delete(:payload)
93
+ execute_api(@backups_interface, :get, [id], options, 'backup') do |json_response|
94
+ backup = json_response['backup']
99
95
  print_h1 "Backup Details", [], options
100
96
  print cyan
101
97
  columns = backup_column_definitions
@@ -105,7 +101,6 @@ EOT
105
101
  print_description_list(columns, backup, options)
106
102
  print reset,"\n"
107
103
  end
108
- return 0, nil
109
104
  end
110
105
 
111
106
  def add(args)
@@ -113,7 +108,6 @@ EOT
113
108
  params = {}
114
109
  optparse = Morpheus::Cli::OptionParser.new do |opts|
115
110
  opts.banner = subcommand_usage("[name] [options]")
116
- # build_option_type_options(opts, options, add_backup_option_types)
117
111
  opts.on('--source VALUE', String, "Backup Source: instance, host or provider") do |val|
118
112
  options[:options]['source'] = val
119
113
  end
@@ -133,7 +127,8 @@ EOT
133
127
  opts.on('--name VALUE', String, "Name") do |val|
134
128
  options[:options]['name'] = val
135
129
  end
136
- build_standard_add_options(opts, options)
130
+ # build_option_type_options(opts, options, add_backup_option_types)
131
+ build_standard_add_many_options(opts, options)
137
132
  opts.footer = <<-EOT
138
133
  Create a new backup.
139
134
  EOT
@@ -142,13 +137,10 @@ EOT
142
137
  verify_args!(args:args, optparse:optparse, min:0, max:1)
143
138
  options[:options]['name'] = args[0] if args[0]
144
139
  connect(options)
145
- payload = {}
146
- if options[:payload]
147
- payload = options[:payload]
148
- payload.deep_merge!({'backup' => parse_passed_options(options)})
149
- else
150
- payload.deep_merge!({'backup' => parse_passed_options(options)})
151
-
140
+ parse_payload(options, 'backup') do |payload|
141
+ # v_prompt = Morpheus::Cli::OptionTypes.no_prompt(add_backup_option_types, options[:options], @api_client)
142
+ # v_prompt.deep_compact!.booleanize! # remove empty values and convert checkbox "on" and "off" to true and false
143
+ # params.deep_merge!(v_prompt)
152
144
  location_type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'source', 'fieldLabel' => 'Source', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Host', 'value' => 'server'}, {'name' => 'Provider', 'value' => 'provider'}], 'defaultValue' => 'instance', 'required' => true, 'description' => 'Where is the backup located?'}], options[:options], @api_client)['source']
153
145
  params['locationType'] = location_type
154
146
  if location_type == 'instance'
@@ -183,7 +175,6 @@ EOT
183
175
  end
184
176
  elsif location_type == 'server'
185
177
 
186
-
187
178
  end
188
179
  # Backup Type
189
180
  avail_backup_types = (create_results['backupTypes'] || []).collect {|it| {'name' => it['name'], 'value' => it['code']} }
@@ -197,9 +188,15 @@ EOT
197
188
  params['jobAction'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobAction', 'fieldLabel' => 'Backup Job Type', 'type' => 'select', 'optionSource' => 'backupJobActions', 'required' => true, 'defaultValue' => 'new'}], options[:options], @api_client)['jobAction']
198
189
  if params['jobAction'] == 'new'
199
190
  params['jobName'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobName', 'fieldLabel' => 'Job Name', 'type' => 'text', 'required' => false, 'defaultValue' => nil}], options[:options], @api_client)['jobName']
200
- default_retention_count = create_results['backup'] ? create_results['backup']['retentionCount'] : nil
191
+ default_retention_count = (create_results['backup'] && create_results['backup']['retentionCount']) ? create_results['backup']['retentionCount'] : ((create_results['backupSettings'] && create_results['backupSettings']['retentionCount']) ? create_results['backupSettings']['retentionCount'] : nil)
201
192
  params['retentionCount'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'retentionCount', 'fieldLabel' => 'Retention Count', 'type' => 'number', 'required' => false, 'defaultValue' => default_retention_count}], options[:options], @api_client)['retentionCount']
202
- params['jobSchedule'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobSchedule', 'fieldLabel' => 'Backup Schedule', 'type' => 'select', 'optionSource' => 'executeSchedules', 'required' => true}], options[:options], @api_client)['jobSchedule']
193
+ params['jobSchedule'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobSchedule', 'fieldLabel' => 'Backup Schedule', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
194
+ schedules = api_client.options.options_for_source('executeSchedules',{})['data']
195
+ [{"name" => "Manual", "value" => "manual"}] + schedules
196
+ }, 'required' => false}], options[:options], @api_client)['jobSchedule']
197
+ if params['jobSchedule'] == 'manual' || params['jobSchedule'] == ''
198
+ params.delete('jobSchedule')
199
+ end
203
200
  elsif params['jobAction'] == 'clone'
204
201
  params['jobId'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobId', 'fieldLabel' => 'Backup Job', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
205
202
  @backup_jobs_interface.list({max:10000})['jobs'].collect {|backup_job|
@@ -215,21 +212,13 @@ EOT
215
212
  }, 'required' => true}], options[:options], @api_client)['jobId']
216
213
  end
217
214
  end
218
-
219
215
  payload['backup'].deep_merge!(params)
220
216
  end
221
- @backups_interface.setopts(options)
222
- if options[:dry_run]
223
- print_dry_run @backups_interface.dry.create(payload)
224
- return 0, nil
225
- end
226
- json_response = @backups_interface.create(payload)
227
- backup = json_response['backup']
228
- render_response(json_response, options, 'backup') do
217
+ execute_api(@backups_interface, :create, [], options, 'backup') do |json_response|
218
+ backup = json_response['backup']
229
219
  print_green_success "Added backup #{backup['name']}"
230
- return _get(backup["id"], {}, options)
220
+ _get(backup["id"], {}, options)
231
221
  end
232
- return 0, nil
233
222
  end
234
223
 
235
224
  def update(args)
@@ -238,8 +227,16 @@ EOT
238
227
  payload = {}
239
228
  optparse = Morpheus::Cli::OptionParser.new do |opts|
240
229
  opts.banner = subcommand_usage("[backup] [options]")
230
+ # opts.on('--name NAME', String, "Name") do |val|
231
+ # options[:options]['name'] = val
232
+ # end
233
+ # opts.on('--job JOB', String, "Name or ID of the Backup Job to associate this backup with") do |val|
234
+ # options[:options]['jobId'] = val
235
+ # end
236
+ # opts.on('--enabled [on|off]', String, "Can be used to disable") do |val|
237
+ # options[:options]['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s.empty?
238
+ # end
241
239
  build_option_type_options(opts, options, update_backup_option_types)
242
- build_option_type_options(opts, options, update_backup_advanced_option_types)
243
240
  build_standard_update_options(opts, options)
244
241
  opts.footer = <<-EOT
245
242
  Update a backup.
@@ -251,36 +248,21 @@ EOT
251
248
  connect(options)
252
249
  backup = find_backup_by_name_or_id(args[0])
253
250
  return 1 if backup.nil?
254
- payload = {}
255
- if options[:payload]
256
- payload = options[:payload]
257
- payload.deep_merge!({'backup' => parse_passed_options(options)})
258
- else
259
- payload.deep_merge!({'backup' => parse_passed_options(options)})
251
+ parse_payload(options, 'backup') do |payload|
260
252
  # do not prompt on update
261
- v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_backup_option_types, options[:options], @api_client, options[:params])
262
- v_prompt.deep_compact!
253
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_backup_option_types, options[:options], @api_client)
254
+ v_prompt.deep_compact!.booleanize! # remove empty values and convert checkbox "on" and "off" to true and false
263
255
  params.deep_merge!(v_prompt)
264
- advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_backup_advanced_option_types, options[:options], @api_client, options[:params])
265
- advanced_config.deep_compact!
266
- params.deep_merge!(advanced_config)
267
256
  payload.deep_merge!({'backup' => params})
268
257
  if payload['backup'].empty? # || options[:no_prompt]
269
258
  raise_command_error "Specify at least one option to update.\n#{optparse}"
270
259
  end
271
260
  end
272
- @backups_interface.setopts(options)
273
- if options[:dry_run]
274
- print_dry_run @backups_interface.dry.update(backup['id'], payload)
275
- return
276
- end
277
- json_response = @backups_interface.update(backup['id'], payload)
278
- backup = json_response['backup']
279
- render_response(json_response, options, 'backup') do
261
+ execute_api(@backups_interface, :update, [backup['id']], options, 'backup') do |json_response|
262
+ backup = json_response['backup']
280
263
  print_green_success "Updated backup #{backup['name']}"
281
264
  return _get(backup["id"], {}, options)
282
265
  end
283
- return 0, nil
284
266
  end
285
267
 
286
268
  def remove(args)
@@ -299,23 +281,169 @@ EOT
299
281
  connect(options)
300
282
  backup = find_backup_by_name_or_id(args[0])
301
283
  return 1 if backup.nil?
302
- @backups_interface.setopts(options)
303
- if options[:dry_run]
304
- print_dry_run @backups_interface.dry.destroy(backup['id'], params)
305
- return
284
+ parse_options(options, params)
285
+ confirm!("Are you sure you want to delete the backup #{backup['name']}?", options)
286
+ execute_api(@backups_interface, :destroy, [backup['id']], options, 'backup') do |json_response|
287
+ print_green_success "Removed backup #{backup['name']}"
306
288
  end
307
- unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the backup #{backup['name']}?")
308
- return 9, "aborted command"
289
+ end
290
+
291
+ def execute(args)
292
+ options = {}
293
+ params = {}
294
+ payload = {}
295
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
296
+ opts.banner = subcommand_usage("[backup] [options]")
297
+ build_standard_post_options(opts, options)
298
+ opts.footer = <<-EOT
299
+ Execute a backup to create a new backup result.
300
+ [backup] is required. This is the name or id of a backup.
301
+ EOT
309
302
  end
310
- json_response = @backups_interface.destroy(backup['id'], params)
311
- render_response(json_response, options) do
312
- print_green_success "Removed backup #{backup['name']}"
303
+ optparse.parse!(args)
304
+ verify_args!(args:args, optparse:optparse, count:1)
305
+ connect(options)
306
+ backup = find_backup_by_name_or_id(args[0])
307
+ return 1 if backup.nil?
308
+ parse_payload(options)
309
+ execute_api(@backups_interface, :execute_backup, [backup['id']], options, 'backup') do |json_response|
310
+ print_green_success "Executing backup #{backup['name']}"
311
+ # should get the result maybe, or could even support refreshing until it is complete...
312
+ # return _get(backup["id"], {}, options)
313
+ end
314
+ end
315
+
316
+ def restore(args)
317
+ raise "Not Yet Implemented"
318
+ options = {}
319
+ params = {}
320
+ payload = {}
321
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
322
+ opts.banner = subcommand_usage("[backup] [result] [options]")
323
+ build_standard_post_options(opts, options)
324
+ opts.on('--result ID', String, "Backup Result ID that is being restored") do |val|
325
+ options[:options]['backupResultId'] = val
326
+ end
327
+ opts.on('--restore-instance existing|new', String, "Instance being targeted for the restore, existing to restore the current instance or new to create a new instance. The current instance is targeted by default.") do |val|
328
+ # restoreInstanceSelect=current|new and the flag on the restore object is called 'restoreToNew'
329
+ options[:options]['restoreInstanceSelect'] = val
330
+ end
331
+ opts.footer = <<-EOT
332
+ Restore a backup, replacing the existing target with the specified backup result.
333
+ [backup] is required. This is the name or id of a backup.
334
+ --result ID is required. This is the id of a backup result being restored.
335
+ EOT
336
+ end
337
+ optparse.parse!(args)
338
+ verify_args!(args:args, optparse:optparse, max:1)
339
+ connect(options)
340
+ backup = nil
341
+ backup_result = nil
342
+ if args[0]
343
+ backup = find_backup_by_name_or_id(args[0])
344
+ return 1 if backup.nil?
345
+ else
346
+ # Prompt for backup
347
+ if backup.nil?
348
+ # Backup
349
+ available_backups = @backups_interface.list({max:10000})['backups'].collect {|it| {'name' => it['name'], 'value' => it['id']}}
350
+ backup_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'backupId', 'fieldLabel' => 'Backup', 'type' => 'select', 'selectOptions' => available_backups, 'required' => true}], options[:options], @api_client)['backupId']
351
+ backup = find_backup_by_name_or_id(backup_id)
352
+ return 1 if backup.nil?
353
+ end
354
+ end
355
+ # Prompt for backup result
356
+ if backup_result.nil?
357
+
358
+ # Instance
359
+ available_backup_results = @backups_interface.list({backupId: backup['id'], max:10000})['results'].collect {|it| {'name' => it['name'], 'value' => it['id']}}
360
+ params['backupResultId'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'backupResultId', 'fieldLabel' => 'Backup Result', 'type' => 'select', 'selectOptions' => available_backup_results, 'required' => true}], options[:options], @api_client)['backupResultId']
361
+ # Name
362
+ params['name'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Backup Name'}], options[:options], @api_client)['name']
363
+ end
364
+
365
+ parse_payload(options, 'restore') do |payload|
366
+ # Prompt for restore configuration
367
+ # We should probably require identifying the instance by name or id too, just to be safe.
368
+ # Target Instance
369
+ if backup_result['instance']
370
+ params['restoreInstanceSelect'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Instance being targeted for the restore, existing to restore the current instance or new to create a new instance. By default the existing instance is restored.'}], options[:options], @api_client)['restoreInstanceSelect']
371
+ end
372
+ payload['backup'].deep_merge!(params)
373
+ end
374
+
375
+ print cyan,"#{bold}WARNING!#{reset}#{cyan} Restoring a backup will erase all data when restored to an existing instance.",reset,"\n"
376
+ confirm!("Are you sure you want to restore the backup result ID: #{backup_result['id']} Name: #{backup_result['backup']['name'] rescue ''} Date: (#{format_local_dt(backup_result['dateCreated'])})?", options)
377
+ execute_api(@backups_interface, :restore, [backup['id']], options, 'backup') do |json_response|
378
+ print_green_success "Restoring backup result ID: #{backup_result['id']} Name: #{backup_result['backup']['name'] rescue ''} Date: (#{format_local_dt(backup_result['dateCreated'])}"
379
+ # should get the restore maybe, or could even support refreshing until it is complete...
380
+ # restore = json_response["restore"]
381
+ # return _get_restore(restore["id"], {}, options)
313
382
  end
314
- return 0, nil
383
+ end
384
+
385
+ # Delegate jobs, results and restores
386
+ # to backup-jobs, backup-results and backup-restores
387
+ # which are hidden in the docs
388
+
389
+ ## Backup Jobs
390
+
391
+ def list_jobs(args)
392
+ Morpheus::Cli::BackupJobsCommand.new.list(args)
393
+ end
394
+
395
+ def get_job(args)
396
+ Morpheus::Cli::BackupJobsCommand.new.get(args)
397
+ end
398
+
399
+ def add_job(args)
400
+ Morpheus::Cli::BackupJobsCommand.new.add(args)
401
+ end
402
+
403
+ def update_job(args)
404
+ Morpheus::Cli::BackupJobsCommand.new.update(args)
405
+ end
406
+
407
+ def remove_job(args)
408
+ Morpheus::Cli::BackupJobsCommand.new.remove(args)
409
+ end
410
+
411
+ def execute_job(args)
412
+ Morpheus::Cli::BackupJobsCommand.new.execute(args)
413
+ end
414
+
415
+ ## Backup Results
416
+
417
+ def list_results(args)
418
+ Morpheus::Cli::BackupResultsCommand.new.list(args)
419
+ end
420
+
421
+ def get_result(args)
422
+ Morpheus::Cli::BackupResultsCommand.new.get(args)
423
+ end
424
+
425
+ def remove_result(args)
426
+ Morpheus::Cli::BackupResultsCommand.new.remove(args)
427
+ end
428
+
429
+ ## Backup Restores
430
+
431
+ def list_restores(args)
432
+ Morpheus::Cli::BackupRestoresCommand.new.list(args)
433
+ end
434
+
435
+ def get_restore(args)
436
+ Morpheus::Cli::BackupRestoresCommand.new.get(args)
437
+ end
438
+
439
+ def remove_restore(args)
440
+ Morpheus::Cli::BackupRestoresCommand.new.remove(args)
315
441
  end
316
442
 
317
443
  private
318
444
 
445
+ ## Backups
446
+
319
447
  def backup_list_column_definitions()
320
448
  {
321
449
  "ID" => 'id',
@@ -345,12 +473,13 @@ EOT
345
473
  "Host" => lambda {|it| it['server']['name'] rescue '' },
346
474
  "Schedule" => lambda {|it| it['schedule']['name'] rescue '' },
347
475
  "Backup Job" => lambda {|it| it['job']['name'] rescue '' },
476
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
348
477
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
349
478
  "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
350
479
  }
351
480
  end
352
481
 
353
- # this is not so simple, need to first choose select instance, host or provider
482
+ # not used atm, this is not so simple, need to first choose select instance, host or provider
354
483
  def add_backup_option_types
355
484
  [
356
485
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
@@ -364,24 +493,16 @@ EOT
364
493
  ]
365
494
  end
366
495
 
367
- def add_backup_advanced_option_types
368
- []
369
- end
370
-
371
496
  def update_backup_option_types
372
- add_backup_option_types.collect {|it|
373
- it.delete('required')
374
- it.delete('defaultValue')
375
- it
376
- }
377
- end
378
-
379
- def update_backup_advanced_option_types
380
- add_backup_advanced_option_types.collect {|it|
381
- it.delete('required')
382
- it.delete('defaultValue')
383
- it
384
- }
497
+ [
498
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text'},
499
+ {'fieldName' => 'jobId', 'fieldLabel' => 'Backup Job', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
500
+ @backup_jobs_interface.list({max:10000})['jobs'].collect {|backup_job|
501
+ {'name' => backup_job['name'], 'value' => backup_job['id'], 'id' => backup_job['id']}
502
+ }
503
+ } },
504
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox'},
505
+ ]
385
506
  end
386
507
 
387
508
  end
@@ -1500,8 +1500,19 @@ class Morpheus::Cli::Hosts
1500
1500
  params = {}
1501
1501
  options = {}
1502
1502
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1503
- opts.banner = subcommand_usage("[name] [workflow] [options]")
1503
+ opts.banner = subcommand_usage("[host] [workflow] [options]")
1504
+ opts.on("--phase PHASE", String, "Task Phase to run for Provisioning workflows. The default is provision.") do |val|
1505
+ options[:phase] = val
1506
+ end
1504
1507
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
1508
+ opts.footer = <<-EOT
1509
+ Run workflow for a host.
1510
+ [host] is required. This is the name or id of a host
1511
+ [workflow] is required. This is the name or id of a workflow
1512
+ By default the provision phase is executed.
1513
+ Use the --phase option to execute a different phase.
1514
+ The available phases are start, stop, preProvision, provision, postProvision, preDeploy, deploy, reconfigure, teardown, startup and shutdown.
1515
+ EOT
1505
1516
  end
1506
1517
  optparse.parse!(args)
1507
1518
  if args.count != 2
@@ -1555,7 +1566,9 @@ class Morpheus::Cli::Hosts
1555
1566
  payload['taskSet']["#{workflow['id']}"] ||= {}
1556
1567
  payload['taskSet']["#{workflow['id']}"].deep_merge!(params)
1557
1568
  end
1558
-
1569
+ if options[:phase]
1570
+ payload['taskPhase'] = options[:phase]
1571
+ end
1559
1572
  begin
1560
1573
  @servers_interface.setopts(options)
1561
1574
  if options[:dry_run]
@@ -258,7 +258,7 @@ class Morpheus::Cli::Instances
258
258
  end
259
259
  row = {
260
260
  id: instance['id'],
261
- name: instance['name'],
261
+ name: instance['displayName'] ? instance['displayName'] : instance['name'],
262
262
  labels: format_list(instance['labels'], '', 3),
263
263
  connection: format_instance_connection_string(instance),
264
264
  environment: instance['instanceContext'],
@@ -599,6 +599,9 @@ class Morpheus::Cli::Instances
599
599
  optparse = Morpheus::Cli::OptionParser.new do |opts|
600
600
  opts.banner = subcommand_usage("[instance]")
601
601
  opts.on('--name VALUE', String, "Name") do |val|
602
+ params['name'] = val
603
+ end
604
+ opts.on('--displayName VALUE', String, "Name") do |val|
602
605
  params['displayName'] = val
603
606
  end
604
607
  opts.on('--description VALUE', String, "Description") do |val|
@@ -1400,6 +1403,7 @@ class Morpheus::Cli::Instances
1400
1403
  description_cols = {
1401
1404
  "ID" => 'id',
1402
1405
  "Name" => 'name',
1406
+ "Display Name" => 'displayName',
1403
1407
  "Description" => 'description',
1404
1408
  "Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
1405
1409
  "Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
@@ -3353,7 +3357,18 @@ EOT
3353
3357
  options = {}
3354
3358
  optparse = Morpheus::Cli::OptionParser.new do |opts|
3355
3359
  opts.banner = subcommand_usage("[instance] [workflow] [options]")
3360
+ opts.on("--phase PHASE", String, "Task Phase to run for Provisioning workflows. The default is provision.") do |val|
3361
+ options[:phase] = val
3362
+ end
3356
3363
  build_common_options(opts, options, [:options, :json, :dry_run, :remote])
3364
+ opts.footer = <<-EOT
3365
+ Run workflow for an instance.
3366
+ [instance] is required. This is the name or id of an instance
3367
+ [workflow] is required. This is the name or id of a workflow
3368
+ By default the provision phase is executed.
3369
+ Use the --phase option to execute a different phase.
3370
+ The available phases are start, stop, preProvision, provision, postProvision, preDeploy, deploy, reconfigure, teardown, startup and shutdown.
3371
+ EOT
3357
3372
  end
3358
3373
  optparse.parse!(args)
3359
3374
  if args.count != 2
@@ -3387,6 +3402,9 @@ EOT
3387
3402
  # end
3388
3403
 
3389
3404
  workflow_payload = {taskSet: {"#{workflow['id']}" => params }}
3405
+ if options[:phase]
3406
+ workflow_payload['taskPhase'] = options[:phase]
3407
+ end
3390
3408
  begin
3391
3409
  @instances_interface.setopts(options)
3392
3410
  if options[:dry_run]
@@ -5294,6 +5312,7 @@ private
5294
5312
  rescue RestClient::Exception => e
5295
5313
  if e.response && e.response.code == 404
5296
5314
  print_red_alert "Workflow not found by id #{id}"
5315
+ exit 1
5297
5316
  else
5298
5317
  raise e
5299
5318
  end
@@ -5304,12 +5323,12 @@ private
5304
5323
  workflows = @task_sets_interface.list({name: name.to_s})['taskSets']
5305
5324
  if workflows.empty?
5306
5325
  print_red_alert "Workflow not found by name #{name}"
5307
- return nil
5326
+ exit 1
5308
5327
  elsif workflows.size > 1
5309
5328
  print_red_alert "#{workflows.size} workflows by name #{name}"
5310
5329
  print_workflows_table(workflows, {color: red})
5311
5330
  print reset,"\n\n"
5312
- return nil
5331
+ exit 1
5313
5332
  else
5314
5333
  return workflows[0]
5315
5334
  end
@@ -5423,6 +5442,7 @@ private
5423
5442
  def add_instance_schedule_option_types()
5424
5443
  [
5425
5444
  {'code' => 'scheduleType', 'fieldName' => 'scheduleType', 'fieldLabel' => 'Schedule Type', 'type' => 'select', 'selectOptions' => [{'name'=>'Day Of Week', 'value'=>'dayOfWeek'},{'name'=>'Exact', 'value'=>'exact'}], 'description' => "Schedule type can be recurring day of the week str or exact start and end timestamp", 'required' => true, 'defaultValue' => 'dayOfWeek'},
5445
+ {'dependsOnCode' => 'scheduleType:dayOfWeek', 'fieldName' => 'scheduleTimezone', 'fieldLabel' => 'Timezone', 'type' => 'select', 'optionSource' => 'timezones' , 'description' => "The timezone", 'defaultValue' => "UTC", 'required' => false},
5426
5446
  {'dependsOnCode' => 'scheduleType:dayOfWeek', 'fieldName' => 'startDayOfWeek', 'fieldLabel' => 'Start Day Of Week', 'type' => 'select', 'selectOptions' => day_of_week_dropdown, 'description' => "Start day of the week Sunday-Saturday (1-7)", 'defaultValue' => "Sunday", 'required' => true},
5427
5447
  {'dependsOnCode' => 'scheduleType:dayOfWeek', 'fieldName' => 'startTime', 'fieldLabel' => 'Start Time (HH:MM)', 'type' => 'text', 'description' => "Start time in HH:MM 24-hour format", 'placeHolder' => 'HH:MM', 'defaultValue' => "01:00", 'required' => true},
5428
5448
  {'dependsOnCode' => 'scheduleType:dayOfWeek', 'fieldName' => 'endDayOfWeek', 'fieldLabel' => 'End Day Of Week', 'type' => 'select', 'selectOptions' => day_of_week_dropdown, 'description' => "End day of the week Sunday-Saturday (1-7)", 'defaultValue' => "Sunday", 'required' => true},
@@ -13,7 +13,7 @@ class Morpheus::Cli::LoadBalancerPools
13
13
  set_rest_parent_name :load_balancers
14
14
 
15
15
  register_subcommands :list, :get, :add, :update, :remove
16
- register_interfaces :load_balancers, :load_balancer_types
16
+ register_interfaces :load_balancer_pools_secondary, :load_balancers, :load_balancer_types
17
17
 
18
18
 
19
19
  # set_rest_interface_name :load_balancer_pools
@@ -90,4 +90,40 @@ class Morpheus::Cli::LoadBalancerPools
90
90
 
91
91
  ## using CliCommand's generic find_by methods
92
92
 
93
+ def find_load_balancer_pool_by_name_or_id(load_balancer_pool_id, val)
94
+ if val.to_s =~ /\A\d{1,}\Z/
95
+ return find_load_balancer_pool_by_id(load_balancer_pool_id, val)
96
+ else
97
+ return find_load_balancer_pool_by_name(load_balancer_pool_id, val)
98
+ end
99
+ end
100
+
101
+ def find_load_balancer_pool_by_id(load_balancer_pool_id, id)
102
+ begin
103
+ json_response = @load_balancer_pools_secondary_interface.get(load_balancer_pool_id, id.to_i)
104
+ return json_response[load_balancer_pool_object_key]
105
+ rescue RestClient::Exception => e
106
+ if e.response && e.response.code == 404
107
+ print_red_alert "Load Balancer Pool not found by id #{id}"
108
+ else
109
+ raise e
110
+ end
111
+ end
112
+ end
113
+
114
+ def find_load_balancer_pool_by_name(load_balancer_pool_id, name)
115
+ lbs = @load_balancer_pools_secondary_interface.list(load_balancer_pool_id, {name: name.to_s})[load_balancer_pool_list_key]
116
+ if lbs.empty?
117
+ print_red_alert "Load Balancer Pool not found by name #{name}"
118
+ return nil
119
+ elsif lbs.size > 1
120
+ print_red_alert "#{lbs.size} load balancer pools found by name #{name}"
121
+ #print_lbs_table(lbs, {color: red})
122
+ print reset,"\n\n"
123
+ return nil
124
+ else
125
+ return lbs[0]
126
+ end
127
+ end
128
+
93
129
  end