morpheus-cli 6.1.2 → 6.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +8 -0
  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/api/monitoring_settings_interface.rb +0 -4
  9. data/lib/morpheus/cli/cli_command.rb +176 -46
  10. data/lib/morpheus/cli/commands/appliance_settings_command.rb +7 -19
  11. data/lib/morpheus/cli/commands/apps.rb +1 -1
  12. data/lib/morpheus/cli/commands/backup_jobs_command.rb +78 -20
  13. data/lib/morpheus/cli/commands/backup_restores_command.rb +144 -0
  14. data/lib/morpheus/cli/commands/backup_results_command.rb +149 -0
  15. data/lib/morpheus/cli/commands/backups_command.rb +215 -93
  16. data/lib/morpheus/cli/commands/hosts.rb +15 -2
  17. data/lib/morpheus/cli/commands/instances.rb +18 -3
  18. data/lib/morpheus/cli/commands/monitoring_settings.rb +0 -16
  19. data/lib/morpheus/cli/commands/plugins.rb +2 -1
  20. data/lib/morpheus/cli/commands/roles.rb +9 -9
  21. data/lib/morpheus/cli/commands/service_catalog_command.rb +50 -83
  22. data/lib/morpheus/cli/commands/user_sources_command.rb +36 -8
  23. data/lib/morpheus/cli/commands/view.rb +20 -20
  24. data/lib/morpheus/cli/mixins/backups_helper.rb +58 -0
  25. data/lib/morpheus/cli/mixins/print_helper.rb +27 -4
  26. data/lib/morpheus/cli/option_types.rb +10 -7
  27. data/lib/morpheus/cli/version.rb +1 -1
  28. data/lib/morpheus/formatters.rb +1 -1
  29. data/lib/morpheus/routes.rb +18 -3
  30. metadata +6 -2
@@ -10,7 +10,7 @@ class Morpheus::Cli::BackupJobsCommand
10
10
 
11
11
  set_command_name :'backup-jobs'
12
12
 
13
- register_subcommands :list, :get, :add, :update, :remove, :run
13
+ register_subcommands :list, :get, :add, :update, :remove, :execute
14
14
 
15
15
  def connect(opts)
16
16
  @api_client = establish_remote_appliance_connection(opts)
@@ -27,7 +27,7 @@ class Morpheus::Cli::BackupJobsCommand
27
27
  params = {}
28
28
  ref_ids = []
29
29
  optparse = Morpheus::Cli::OptionParser.new do |opts|
30
- opts.banner = subcommand_usage("[search]")
30
+ opts.banner = "Usage: #{prog_name} backups list-jobs [search]"
31
31
  build_standard_list_options(opts, options)
32
32
  opts.footer = "List backup jobs."
33
33
  end
@@ -50,7 +50,7 @@ class Morpheus::Cli::BackupJobsCommand
50
50
  if backup_jobs.empty?
51
51
  print yellow,"No backup jobs found.",reset,"\n"
52
52
  else
53
- print as_pretty_table(backup_jobs, backup_job_column_definitions.upcase_keys!, options)
53
+ print as_pretty_table(backup_jobs, backup_job_list_column_definitions.upcase_keys!, options)
54
54
  print_results_pagination(json_response)
55
55
  end
56
56
  print reset,"\n"
@@ -62,7 +62,8 @@ class Morpheus::Cli::BackupJobsCommand
62
62
  params = {}
63
63
  options = {}
64
64
  optparse = Morpheus::Cli::OptionParser.new do |opts|
65
- opts.banner = subcommand_usage("[job]")
65
+ # opts.banner = subcommand_usage("[job]")
66
+ opts.banner = "Usage: #{prog_name} backups get-job [job]"
66
67
  build_standard_get_options(opts, options)
67
68
  opts.footer = <<-EOT
68
69
  Get details about a specific backup job.
@@ -99,9 +100,21 @@ EOT
99
100
  json_response = @backup_jobs_interface.get(id, params)
100
101
  backup_job = json_response['job']
101
102
  render_response(json_response, options, 'job') do
103
+ backup_job = json_response['job']
104
+ backups = backup_job['backups'] || []
102
105
  print_h1 "Backup Job Details", [], options
103
106
  print cyan
104
- print_description_list(backup_job_column_definitions, backup_job)
107
+ columns = backup_job_column_definitions
108
+ columns.delete("Provider") if backup_job['backupProvider'].nil?
109
+ columns.delete("Repository") if backup_job['backupRepository'].nil?
110
+ print_description_list(columns, backup_job)
111
+ # print reset,"\n"
112
+ print_h2 "Backups", options
113
+ if backups.empty?
114
+ print yellow,"This job has no backups associated with it.",reset,"\n"
115
+ else
116
+ print as_pretty_table(backups, [:id, :name], options)
117
+ end
105
118
  print reset,"\n"
106
119
  end
107
120
  return 0, nil
@@ -111,7 +124,7 @@ EOT
111
124
  options = {}
112
125
  params = {}
113
126
  optparse = Morpheus::Cli::OptionParser.new do |opts|
114
- opts.banner = subcommand_usage("[name] [options]")
127
+ opts.banner = "Usage: #{prog_name} backups add-job [name]"
115
128
  build_option_type_options(opts, options, add_backup_job_option_types)
116
129
  build_option_type_options(opts, options, add_backup_job_advanced_option_types)
117
130
  build_standard_add_options(opts, options)
@@ -131,6 +144,9 @@ EOT
131
144
  payload.deep_merge!({'job' => parse_passed_options(options)})
132
145
  v_prompt = Morpheus::Cli::OptionTypes.prompt(add_backup_job_option_types(), options[:options], @api_client, options[:params])
133
146
  params.deep_merge!(v_prompt)
147
+ if params['scheduleId'] == 'manual' || params['scheduleId'] == ''
148
+ params['scheduleId'] = nil
149
+ end
134
150
  advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_backup_job_advanced_option_types, options[:options], @api_client, options[:params])
135
151
  advanced_config.deep_compact!
136
152
  params.deep_merge!(advanced_config)
@@ -155,7 +171,7 @@ EOT
155
171
  params = {}
156
172
  payload = {}
157
173
  optparse = Morpheus::Cli::OptionParser.new do |opts|
158
- opts.banner = subcommand_usage("[job] [options]")
174
+ opts.banner = "Usage: #{prog_name} backups update-job [job]"
159
175
  build_option_type_options(opts, options, update_backup_job_option_types)
160
176
  build_option_type_options(opts, options, update_backup_job_advanced_option_types)
161
177
  build_standard_update_options(opts, options)
@@ -177,6 +193,9 @@ EOT
177
193
  payload.deep_merge!({'job' => parse_passed_options(options)})
178
194
  v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_backup_job_option_types, options[:options], @api_client, options[:params])
179
195
  v_prompt.deep_compact!
196
+ if v_prompt['scheduleId'] == 'manual' || v_prompt['scheduleId'] == ''
197
+ v_prompt['scheduleId'] = nil
198
+ end
180
199
  params.deep_merge!(v_prompt)
181
200
  advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_backup_job_advanced_option_types, options[:options], @api_client, options[:params])
182
201
  advanced_config.deep_compact!
@@ -204,7 +223,7 @@ EOT
204
223
  options = {}
205
224
  params = {}
206
225
  optparse = Morpheus::Cli::OptionParser.new do |opts|
207
- opts.banner = subcommand_usage("[job] [options]")
226
+ opts.banner = "Usage: #{prog_name} backups remove-job [job]"
208
227
  build_standard_remove_options(opts, options)
209
228
  opts.footer = <<-EOT
210
229
  Delete a backup job.
@@ -216,28 +235,64 @@ EOT
216
235
  connect(options)
217
236
  backup_job = find_backup_job_by_name_or_id(args[0])
218
237
  return 1 if backup_job.nil?
219
- @backup_jobs_interface.setopts(options)
220
- if options[:dry_run]
221
- print_dry_run @backup_jobs_interface.dry.destroy(backup_job['id'], params)
222
- return
238
+ parse_options(options, params)
239
+ confirm!("Are you sure you want to delete the backup job #{backup_job['name']}?", options)
240
+ execute_api(@backup_jobs_interface, :destroy, [backup_job['id']], options) do |json_response|
241
+ print_green_success "Removed backup job #{backup_job['name']}"
242
+ end
243
+ end
244
+
245
+ def execute(args)
246
+ options = {}
247
+ params = {}
248
+ payload = {}
249
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
250
+ opts.banner = "Usage: #{prog_name} backups execute-job [job]"
251
+ build_standard_post_options(opts, options)
252
+ opts.footer = <<-EOT
253
+ Execute a backup job to create a new backup result for all the backups in the job.
254
+ [job] is required. This is the name or id of a backup job.
255
+ EOT
223
256
  end
224
- unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the backup #{backup['name']}?")
225
- return 9, "aborted command"
257
+ optparse.parse!(args)
258
+ verify_args!(args:args, optparse:optparse, count:1)
259
+ connect(options)
260
+ backup_job = find_backup_job_by_name_or_id(args[0])
261
+ return 1 if backup_job.nil?
262
+ parse_payload(options) do |payload|
226
263
  end
227
- json_response = @backup_jobs_interface.destroy(backup_job['id'], params)
228
- render_response(json_response, options) do
229
- print_green_success "Removed backup job #{backup_job['name']}"
264
+ execute_api(@backup_jobs_interface, :execute_job, [backup_job['id']], options, 'job') do |json_response|
265
+ print_green_success "Executing backup job #{backup_job['name']}"
266
+ # should get the result maybe, or could even support refreshing until it is complete...
267
+ # return _get(backup_job["id"], {}, options)
230
268
  end
231
- return 0, nil
232
269
  end
233
270
 
234
271
  private
235
272
 
236
273
  def backup_job_column_definitions()
274
+ {
275
+ "ID" => 'id',
276
+ "Name" => 'name',
277
+ "Code" => 'code',
278
+ "Schedule" => lambda {|it| it['schedule']['name'] rescue '' },
279
+ "Next" => lambda {|it| format_local_dt(it['nextFire']) },
280
+ "Retention Count" => lambda {|it| it['retentionCount'] rescue '' },
281
+ "Provider" => lambda {|it| it['backupProvider']['name'] rescue '' },
282
+ "Repository" => lambda {|it| it['backupRepository']['name'] rescue '' },
283
+ "Source" => lambda {|it| it['source'] },
284
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
285
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
286
+ }
287
+ end
288
+
289
+ def backup_job_list_column_definitions()
237
290
  {
238
291
  "ID" => 'id',
239
292
  "Name" => 'name',
240
293
  "Schedule" => lambda {|it| it['schedule']['name'] rescue '' },
294
+ "Next" => lambda {|it| format_local_dt(it['nextFire']) },
295
+ "Retention Count" => lambda {|it| it['retentionCount'] rescue '' },
241
296
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
242
297
  "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
243
298
  }
@@ -246,9 +301,12 @@ EOT
246
301
  def add_backup_job_option_types
247
302
  [
248
303
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
249
- #{'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
304
+ {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
250
305
  {'fieldName' => 'retentionCount', 'fieldLabel' => 'Retention Count', 'type' => 'number', 'displayOrder' => 3},
251
- {'fieldName' => 'scheduleId', 'fieldLabel' => 'Schedule', 'type' => 'select', 'optionSource' => 'executeSchedules', 'displayOrder' => 4}, # should use jobSchedules instead maybe? do we support manual schedules for backups?
306
+ {'fieldName' => 'scheduleId', 'fieldLabel' => 'Schedule', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
307
+ schedules = api_client.options.options_for_source('executeSchedules',{})['data']
308
+ [{"name" => "Manual", "value" => "manual"}] + schedules
309
+ }, 'displayOrder' => 4},
252
310
  ]
253
311
  end
254
312
 
@@ -0,0 +1,144 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::BackupRestoresCommand
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::BackupsHelper
6
+ # include Morpheus::Cli::ProvisioningHelper
7
+ # include Morpheus::Cli::OptionSourceHelper
8
+
9
+ set_command_hidden # hide until ready
10
+
11
+ set_command_name :'backup-restores'
12
+
13
+ register_subcommands :list, :get, :remove
14
+
15
+ def connect(opts)
16
+ @api_client = establish_remote_appliance_connection(opts)
17
+ @backups_interface = @api_client.backups
18
+ @backup_restores_interface = @api_client.backup_restores
19
+ end
20
+
21
+ def handle(args)
22
+ handle_subcommand(args)
23
+ end
24
+
25
+ def list(args)
26
+ options = {}
27
+ params = {}
28
+ ref_ids = []
29
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
30
+ opts.banner = "Usage: #{prog_name} backups list-restores [search]"
31
+ build_standard_list_options(opts, options)
32
+ opts.footer = "List backup restores."
33
+ end
34
+ optparse.parse!(args)
35
+ connect(options)
36
+ # verify_args!(args:args, optparse:optparse, count:0)
37
+ if args.count > 0
38
+ options[:phrase] = args.join(" ")
39
+ end
40
+ params.merge!(parse_list_options(options))
41
+ @backup_restores_interface.setopts(options)
42
+ if options[:dry_run]
43
+ print_dry_run @backup_restores_interface.dry.list(params)
44
+ return
45
+ end
46
+ json_response = @backup_restores_interface.list(params)
47
+ backup_restores = json_response['restores']
48
+ render_response(json_response, options, 'restores') do
49
+ print_h1 "Morpheus Backup Restores", parse_list_subtitles(options), options
50
+ if backup_restores.empty?
51
+ print yellow,"No backup restores found.",reset,"\n"
52
+ else
53
+ print as_pretty_table(backup_restores, backup_restore_list_column_definitions.upcase_keys!, options)
54
+ print_results_pagination(json_response)
55
+ end
56
+ print reset,"\n"
57
+ end
58
+ return 0, nil
59
+ end
60
+
61
+ def get(args)
62
+ params = {}
63
+ options = {}
64
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
65
+ opts.banner = "Usage: #{prog_name} backups get-restore [restore]"
66
+ build_standard_get_options(opts, options)
67
+ opts.footer = <<-EOT
68
+ Get details about a specific backup restore.
69
+ [restore] is required. This is the id of a backup restore.
70
+ EOT
71
+ end
72
+ optparse.parse!(args)
73
+ verify_args!(args:args, optparse:optparse, min:1)
74
+ connect(options)
75
+ id_list = parse_id_list(args)
76
+ id_list = id_list.collect do |id|
77
+ if id.to_s =~ /\A\d{1,}\Z/
78
+ id
79
+ else
80
+ backup_restore = find_backup_restore_by_name(id)
81
+ if backup_restore
82
+ backup_restore['id']
83
+ else
84
+ return 1, "backup restore not found for name '#{id}'"
85
+ end
86
+ end
87
+ end
88
+ return run_command_for_each_arg(id_list) do |arg|
89
+ _get(arg, params, options)
90
+ end
91
+ end
92
+
93
+ def _get(id, params, options)
94
+ @backup_restores_interface.setopts(options)
95
+ if options[:dry_run]
96
+ print_dry_run @backup_restores_interface.dry.get(id, params)
97
+ return
98
+ end
99
+ json_response = @backup_restores_interface.get(id, params)
100
+ backup_restore = json_response['restore']
101
+ render_response(json_response, options, 'restore') do
102
+ backup_restore = json_response['restore']
103
+ backups = backup_restore['backups'] || []
104
+ print_h1 "Backup Restore Details", [], options
105
+ print cyan
106
+ print_description_list(backup_restore_column_definitions, backup_restore)
107
+ if backup_restore['errorMessage']
108
+ print_h2 "Error Message", options
109
+ print red, backup_restore['errorMessage'], reset, "\n"
110
+ end
111
+ print reset,"\n"
112
+ end
113
+ return 0, nil
114
+ end
115
+
116
+ def remove(args)
117
+ options = {}
118
+ params = {}
119
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
120
+ opts.banner = "Usage: #{prog_name} backups remove-restore [restore]"
121
+ build_standard_remove_options(opts, options)
122
+ opts.footer = <<-EOT
123
+ Delete a backup restore.
124
+ [restore] is required. This is the id of a backup restore.
125
+ EOT
126
+ end
127
+ optparse.parse!(args)
128
+ verify_args!(args:args, optparse:optparse, count:1)
129
+ connect(options)
130
+ backup_restore = @backup_restores_interface.get(args[0])['restore']
131
+ #backup_restore = find_backup_restore_by_name_or_id(args[0])
132
+ #return 1 if backup_restore.nil?
133
+ parse_options(options, params)
134
+ confirm!("Are you sure you want to delete the backup restore #{backup_restore['id']}?", options)
135
+ execute_api(@backup_restores_interface, :destroy, [backup_restore['id']], options) do |json_response|
136
+ print_green_success "Removed backup restore #{backup_restore['name']}"
137
+ end
138
+ end
139
+
140
+ private
141
+
142
+ # helper methods are defined in BackupsHelper
143
+
144
+ end
@@ -0,0 +1,149 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::BackupResultsCommand
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::BackupsHelper
6
+ # include Morpheus::Cli::ProvisioningHelper
7
+ # include Morpheus::Cli::OptionSourceHelper
8
+
9
+ set_command_hidden # hide and prefer backups list-results, get-result, etc. for now
10
+
11
+ set_command_name :'backup-results'
12
+
13
+ register_subcommands :list, :get, :remove
14
+
15
+ def connect(opts)
16
+ @api_client = establish_remote_appliance_connection(opts)
17
+ @backups_interface = @api_client.backups
18
+ @backup_results_interface = @api_client.backup_results
19
+ end
20
+
21
+ def handle(args)
22
+ handle_subcommand(args)
23
+ end
24
+
25
+ def list(args)
26
+ options = {}
27
+ params = {}
28
+ ref_ids = []
29
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
30
+ opts.banner = "Usage: #{prog_name} backups list-results [search]"
31
+ opts.on('--backup BACKUP', String, "Backup Name or ID") do |val|
32
+ options[:backup] = val
33
+ end
34
+ opts.on('--instance INSTANCE', String, "Instance Name or ID") do |val|
35
+ options[:instance] = val
36
+ end
37
+ build_standard_list_options(opts, options)
38
+ opts.footer = "List backup results."
39
+ end
40
+ optparse.parse!(args)
41
+ connect(options)
42
+ # verify_args!(args:args, optparse:optparse, max:1)
43
+ parse_list_options!(args, options, params)
44
+ execute_api(@backup_results_interface, :list, [], options, 'results') do |json_response|
45
+ backup_results = json_response['results']
46
+ subtitles = []
47
+ subtitles << "Backup: #{options[:backup]}" if options[:backup]
48
+ subtitles += parse_list_subtitles(options)
49
+ print_h1 "Morpheus Backup Results", subtitles, options
50
+ if backup_results.empty?
51
+ print yellow,"No backup results found.",reset,"\n"
52
+ else
53
+ print as_pretty_table(backup_results, backup_result_list_column_definitions.upcase_keys!, options)
54
+ print_results_pagination(json_response)
55
+ end
56
+ print reset,"\n"
57
+ end
58
+ end
59
+
60
+ def get(args)
61
+ params = {}
62
+ options = {}
63
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
64
+ opts.banner = "Usage: #{prog_name} backups get-result [result]"
65
+ build_standard_get_options(opts, options)
66
+ opts.footer = <<-EOT
67
+ Get details about a specific backup result.
68
+ [result] is required. This is the id of a backup result.
69
+ EOT
70
+ end
71
+ optparse.parse!(args)
72
+ verify_args!(args:args, optparse:optparse, min:1)
73
+ connect(options)
74
+ id_list = parse_id_list(args)
75
+ id_list = id_list.collect do |id|
76
+ if id.to_s =~ /\A\d{1,}\Z/
77
+ id
78
+ else
79
+ backup_result = find_backup_result_by_name(id)
80
+ if backup_result
81
+ backup_result['id']
82
+ else
83
+ return 1, "backup result not found for name '#{id}'"
84
+ end
85
+ end
86
+ end
87
+ return run_command_for_each_arg(id_list) do |arg|
88
+ _get(arg, params, options)
89
+ end
90
+ end
91
+
92
+ def _get(id, params, options)
93
+ @backup_results_interface.setopts(options)
94
+ if options[:dry_run]
95
+ print_dry_run @backup_results_interface.dry.get(id, params)
96
+ return
97
+ end
98
+ json_response = @backup_results_interface.get(id, params)
99
+ backup_result = json_response['result']
100
+ render_response(json_response, options, 'result') do
101
+ backup_result = json_response['result']
102
+ backups = backup_result['backups'] || []
103
+ print_h1 "Backup Result Details", [], options
104
+ print cyan
105
+ print_description_list(backup_result_column_definitions, backup_result)
106
+ if backup_result['errorMessage']
107
+ print_h2 "Error Message", options
108
+ print red, backup_result['errorMessage'], reset, "\n"
109
+ end
110
+ print reset,"\n"
111
+ end
112
+ return 0, nil
113
+ end
114
+
115
+ def remove(args)
116
+ options = {}
117
+ params = {}
118
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
119
+ opts.banner = "Usage: #{prog_name} backups remove-result [result]"
120
+ build_standard_remove_options(opts, options)
121
+ opts.footer = <<-EOT
122
+ Delete a backup result.
123
+ [result] is required. This is the id of a backup result.
124
+ EOT
125
+ end
126
+ optparse.parse!(args)
127
+ verify_args!(args:args, optparse:optparse, count:1)
128
+ connect(options)
129
+ backup_result = @backup_results_interface.get(args[0])['result']
130
+ # backup_result = find_backup_result_by_name_or_id(args[0])
131
+ # return 1 if backup_result.nil?
132
+ parse_options(options, params)
133
+ confirm!("Are you sure you want to delete the backup result #{backup_result['id']}?", options)
134
+ execute_api(@backup_results_interface, :destroy, [backup_result['id']], options) do |json_response|
135
+ print_green_success "Removed backup result #{backup_result['name']}"
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ # helper methods are defined in BackupsHelper
142
+
143
+ def parse_list_options!(args, options, params)
144
+ parse_parameter_as_resource_id!(:backup, options, params, 'backupId')
145
+ parse_parameter_as_resource_id!(:instance, options, params, 'instanceId')
146
+ super
147
+ end
148
+
149
+ end