morpheus-cli 6.1.2 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -560,27 +560,17 @@ EOT
560
560
  # fetch current cart
561
561
  # cart = @service_catalog_interface.get_cart()['cart']
562
562
  update_cart_object_key = 'order'
563
- payloads = parse_payloads(options, update_cart_object_key) do |payload|
563
+ parse_payload(options, update_cart_object_key) do |payload|
564
564
  payload.deep_merge!({update_cart_object_key => parse_passed_options(options)})
565
565
  if payload[update_cart_object_key].empty? # || options[:no_prompt]
566
566
  raise_command_error "Specify at least one option to update.\n#{optparse}"
567
567
  end
568
568
  end
569
- process_payloads(payloads, options) do |payload|
570
- @service_catalog_interface.setopts(options)
571
- if options[:dry_run]
572
- print_dry_run @service_catalog_interface.dry.update_cart(payload)
573
- next
574
- end
575
- json_response = @service_catalog_interface.update_cart(payload)
576
- #cart = json_response['cart']
577
- #cart = @service_catalog_interface.get_cart()['cart']
578
- render_response(json_response, options, 'cart') do
579
- print_green_success "Updated cart"
580
- get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
581
- end
569
+ execute_api(@service_catalog_interface, :update_cart, [params], options, "cart") do |json_response|
570
+ #cart = json_response["cart"]
571
+ print_green_success "Updated cart"
572
+ get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
582
573
  end
583
- return 0, nil
584
574
  end
585
575
 
586
576
  def add(args)
@@ -600,6 +590,7 @@ EOT
600
590
  end
601
591
  opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips adding the item.") do
602
592
  options[:validate_only] = true
593
+ params['validate'] = true
603
594
  end
604
595
  opts.on('--context [instance|server]', String, "Context Type for operational workflow types") do |val|
605
596
  workflow_context = val.to_s
@@ -608,7 +599,7 @@ EOT
608
599
  workflow_target = val.to_s
609
600
  end
610
601
  opts.add_hidden_option('--sigdig')
611
- build_standard_update_options(opts, options, [:payloads, :sigdig])
602
+ build_standard_add_many_options(opts, options, [:sigdig])
612
603
  opts.footer = <<-EOT
613
604
  Add an item to your cart
614
605
  [type] is required, this is name or id of a catalog item type.
@@ -622,7 +613,7 @@ EOT
622
613
  type_id = args.join(" ")
623
614
  end
624
615
  add_item_object_key = 'item'
625
- payloads = parse_payloads(options, add_item_object_key) do |payload|
616
+ parse_payload(options, add_item_object_key) do |payload|
626
617
  payload.deep_merge!({add_item_object_key => parse_passed_options(options)})
627
618
  # prompt for Type
628
619
  if type_id
@@ -712,46 +703,35 @@ EOT
712
703
  end
713
704
  end
714
705
  end
715
- if options[:validate_only]
716
- params['validate'] = true
717
- end
718
- process_payloads(payloads, options) do |payload|
719
- @service_catalog_interface.setopts(options)
720
- if options[:dry_run]
721
- print_dry_run @service_catalog_interface.dry.create_cart_item(payload, params)
722
- next
723
- end
724
- json_response = @service_catalog_interface.create_cart_item(payload, params)
706
+ execute_api(@service_catalog_interface, :create_cart_item, [params], options, 'item') do |json_response|
725
707
  cart_item = json_response['item']
726
- render_response(json_response, options) do
727
- if options[:validate_only]
728
- if json_response['success']
729
- print_h2 "Validated Cart Item", [], options
730
- cart_item_columns = {
731
- "Type" => lambda {|it| it['type']['name'] rescue '' },
732
- #"Qty" => lambda {|it| it['quantity'] },
733
- "Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" },
734
- "Status" => lambda {|it|
735
- status_string = format_catalog_item_status(it)
736
- if it['errorMessage'].to_s != ""
737
- status_string << " - #{it['errorMessage']}"
738
- end
739
- status_string
740
- },
741
- #"Config" => lambda {|it| truncate_string(format_name_values(it['config']), 50) }
742
- }
743
- print as_pretty_table([cart_item], cart_item_columns.upcase_keys!)
744
- print reset, "\n"
745
- print_green_success(json_response['msg'] || "Item is valid")
746
- print reset, "\n"
747
- else
748
- # not needed because it will be http 400
749
- print_rest_errors(json_response, options)
750
- end
708
+ if options[:validate_only]
709
+ if json_response['success']
710
+ print_h2 "Validated Cart Item", [], options
711
+ cart_item_columns = {
712
+ "Type" => lambda {|it| it['type']['name'] rescue '' },
713
+ #"Qty" => lambda {|it| it['quantity'] },
714
+ "Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" },
715
+ "Status" => lambda {|it|
716
+ status_string = format_catalog_item_status(it)
717
+ if it['errorMessage'].to_s != ""
718
+ status_string << " - #{it['errorMessage']}"
719
+ end
720
+ status_string
721
+ },
722
+ #"Config" => lambda {|it| truncate_string(format_name_values(it['config']), 50) }
723
+ }
724
+ print as_pretty_table([cart_item], cart_item_columns.upcase_keys!)
725
+ print reset, "\n"
726
+ print_green_success(json_response['msg'] || "Item is valid")
727
+ print reset, "\n"
751
728
  else
752
- print_green_success "Added item to cart"
753
- get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
729
+ # not needed because it will be http 400
730
+ print_rest_errors(json_response, options)
754
731
  end
732
+ else
733
+ print_green_success "Added item to cart"
734
+ get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
755
735
  end
756
736
  end
757
737
  end
@@ -935,6 +915,7 @@ EOT
935
915
  end
936
916
  opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips creating the order.") do
937
917
  options[:validate_only] = true
918
+ params['validate'] = true
938
919
  end
939
920
  opts.on('-a', '--details', "Display all details: item configuration." ) do
940
921
  options[:details] = true
@@ -962,7 +943,7 @@ EOT
962
943
  end
963
944
  payload = {}
964
945
  order_object_key = 'order'
965
- payloads = parse_payloads(options, order_object_key) do |payload|
946
+ parse_payload(options, order_object_key) do |payload|
966
947
  payload.deep_merge!({order_object_key => {}})
967
948
  # Prompt for 1-N Types
968
949
  # still_prompting = options[:no_prompt] != true
@@ -1076,38 +1057,24 @@ EOT
1076
1057
  end
1077
1058
  end
1078
1059
 
1079
- end
1080
-
1081
-
1060
+ end
1082
1061
  end
1083
- if options[:validate_only]
1084
- params['validate'] = true
1085
- #payload['validate'] = true
1086
- end
1087
- process_payloads(payloads, options) do |payload|
1088
- @service_catalog_interface.setopts(options)
1089
- if options[:dry_run]
1090
- print_dry_run @service_catalog_interface.dry.create_order(payload, params)
1091
- next
1092
- end
1093
- json_response = @service_catalog_interface.create_order(payload, params)
1062
+ execute_api(@service_catalog_interface, :create_order, [params], options, "order") do |json_response|
1094
1063
  order = json_response['order'] || json_response['cart']
1095
- render_response(json_response, options) do
1096
- if options[:validate_only]
1097
- if json_response['success']
1098
- print_h2 "Review Order", [], options
1099
- print_order_details(order, options)
1100
- print_green_success(json_response['msg'] || "Order is valid")
1101
- print reset, "\n"
1102
- else
1103
- # not needed because it will be http 400
1104
- print_rest_errors(json_response, options)
1105
- end
1106
- else
1107
- print_green_success "Order placed"
1108
- print_h2 "Order Details", [], options
1064
+ if options[:validate_only]
1065
+ if json_response['success']
1066
+ print_h2 "Review Order", [], options
1109
1067
  print_order_details(order, options)
1068
+ print_green_success(json_response['msg'] || "Order is valid")
1069
+ print reset, "\n"
1070
+ else
1071
+ # not needed because it will be http 400
1072
+ print_rest_errors(json_response, options)
1110
1073
  end
1074
+ else
1075
+ print_green_success "Order placed"
1076
+ print_h2 "Order Details", [], options
1077
+ print_order_details(order, options)
1111
1078
  end
1112
1079
  end
1113
1080
  end
@@ -46,20 +46,22 @@ Examples:
46
46
  EOT
47
47
  end
48
48
  optparse.parse!(args)
49
- # verify_args!(args:args, optparse:optparse, min: 0, max: 2)
49
+ verify_args!(args:args, optparse:optparse, min: 0, max: 2)
50
50
  connect(options)
51
51
  # todo: it would actually be cool to use the params and include them on the path..
52
52
  # params.merge!(parse_query_options(options))
53
- path, *ids = args
53
+ # input, *ids = args
54
+ input = args[0]
55
+ id = args[1]
54
56
  # default to index page "/"
55
- path = path || "/"
57
+ path = input || "/"
56
58
  if options[:absolute_path] != true
57
59
  if path.start_with?("/")
58
60
  # treat like absolute path, no lookup
59
61
  else
60
62
  # lookup best matching route from sitemap
61
63
  # lookup plural routes first, so 'app' finds apps and not approvals
62
- found_route = Morpheus::Routes.lookup(path)
64
+ found_route = Morpheus::Routes.lookup(path, id)
63
65
  if found_route
64
66
  # Morpheus::Logging::DarkPrinter.puts "Found matching route: '#{path}' => '#{found_route}'" if Morpheus::Logging.debug?
65
67
  path = found_route
@@ -69,26 +71,24 @@ EOT
69
71
  end
70
72
  # always add a leading slash
71
73
  path = path.start_with?("/") ? path : "/#{path}"
72
- # append id(s) to path if passed
73
- if ids.size > 0
74
- # convert names to ids
74
+ # append id to path if passed
75
+ if id
76
+ # convert name to id
75
77
  # assume the last part of path is the type and use generic finder
76
78
  # only lookup names, and allow any id
77
- ids = ids.collect do |id|
78
- if id.to_s !~ /\A\d{1,}\Z/
79
- # assume the last part of path is the type
80
- record_type = path.split("/").last
81
- record_type.sub!('#!', '')
82
- record = find_by_name(record_type, id)
83
- if record.nil?
84
- raise_command_error("[id] is invalid. No #{record_type} found for '#{id}'", args, optparse)
85
- end
86
- record['id'].to_s
87
- else
88
- id
79
+ if id.to_s !~ /\A\d{1,}\Z/
80
+ # record type is just args[0]
81
+ record_type = input
82
+ # assume the last part of path is the type
83
+ # record_type = path.split("/").last
84
+ # record_type.sub!('#!', '')
85
+ record = find_by_name(record_type, id)
86
+ if record.nil?
87
+ raise_command_error("[id] is invalid. No #{record_type} found for '#{id}'", args, optparse)
89
88
  end
89
+ id = record['id'].to_s
90
90
  end
91
- path = "#{path}/" + ids.join("/")
91
+ path = "#{path}/#{id}"
92
92
  end
93
93
  end
94
94
  # build the link to use, either our path or oauth-redirect to that path
@@ -110,4 +110,62 @@ module Morpheus::Cli::BackupsHelper
110
110
  return backup_jobs[0]
111
111
  end
112
112
  end
113
+
114
+ ## Backup Results
115
+
116
+ def backup_result_list_column_definitions()
117
+ {
118
+ "ID" => 'id',
119
+ "Backup" => lambda {|it| it['backup']['name'] rescue '' },
120
+ "Status" => lambda {|it| format_backup_result_status(it) },
121
+ #"Duration" => lambda {|it| format_duration(it['startDate'], it['endDate']) },
122
+ "Duration" => lambda {|it| format_duration_milliseconds(it['durationMillis']) },
123
+ "Start Date" => lambda {|it| format_local_dt(it['startDate']) },
124
+ "End Date" => lambda {|it| format_local_dt(it['endDate']) },
125
+ "Size" => lambda {|it| format_bytes(it['sizeInMb'], 'MB') },
126
+ }
127
+ end
128
+
129
+ def backup_result_column_definitions()
130
+ backup_result_list_column_definitions()
131
+ end
132
+
133
+ def format_backup_result_status(backup_result, return_color=cyan)
134
+ out = ""
135
+ status_string = backup_result['status'].to_s.upcase
136
+ if status_string == 'SUCCEEDED' || status_string == 'SUCCESS'
137
+ out << "#{green}#{status_string.upcase}#{return_color}"
138
+ elsif status_string == 'FAILED'
139
+ out << "#{red}#{status_string.upcase}#{return_color}"
140
+ elsif status_string
141
+ out << "#{cyan}#{status_string.upcase}#{return_color}"
142
+ else
143
+ out << ""
144
+ end
145
+ out
146
+ end
147
+
148
+ ## Backup Restores
149
+
150
+ def backup_restore_list_column_definitions()
151
+ {
152
+ "ID" => 'id',
153
+ "Backup" => lambda {|it| it['backup']['name'] rescue '' },
154
+ "Backup Result ID" => lambda {|it| it['backupResultId'] rescue '' },
155
+ "Target" => lambda {|it| it['instance']['name'] rescue '' },
156
+ "Status" => lambda {|it| format_backup_result_status(it) },
157
+ #"Duration" => lambda {|it| format_duration(it['startDate'], it['endDate']) },
158
+ "Duration" => lambda {|it| format_duration_milliseconds(it['durationMillis']) },
159
+ "Start Date" => lambda {|it| format_local_dt(it['startDate']) },
160
+ "End Date" => lambda {|it| format_local_dt(it['endDate']) },
161
+ }
162
+ end
163
+
164
+ def backup_restore_column_definitions()
165
+ backup_restore_list_column_definitions()
166
+ end
167
+
168
+ def format_backup_restore_status(backup_restore, return_color=cyan)
169
+ format_backup_result_status(backup_restore, return_color)
170
+ end
113
171
  end
@@ -191,7 +191,24 @@ module Morpheus::Cli::PrintHelper
191
191
  output = ""
192
192
  if api_request[:curl] || options[:curl]
193
193
  output = format_curl_command(http_method, url, headers, payload, options)
194
+ elsif options[:json]
195
+ # --dry --json should print the payload only
196
+ payload_object = payload.is_a?(String) ? JSON.parse(payload) : payload
197
+ output = as_json(payload_object, options)
198
+ elsif options[:yaml]
199
+ # --dry --yaml should print the payload only as yaml
200
+ payload_object = payload.is_a?(String) ? JSON.parse(payload) : payload
201
+ output = as_yaml(payload_object, options)
194
202
  else
203
+ # default format is
204
+ # DRY RUN
205
+ # REQUEST
206
+ # GET https://server/api/things
207
+ #
208
+ # JSON
209
+ # {
210
+ # "thing": { ... }
211
+ # }
195
212
  output = format_api_request(http_method, url, headers, payload, options)
196
213
  end
197
214
  # this is an extra scrub, should remove
@@ -210,14 +227,20 @@ module Morpheus::Cli::PrintHelper
210
227
  if api_request[:curl] || options[:curl]
211
228
  print "\n"
212
229
  print "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}\n"
230
+ print output
231
+ print reset, "\n"
232
+ print reset
233
+ elsif options[:json] || options[:yaml]
234
+ # print just the just payload
235
+ print output, "\n"
213
236
  else
214
237
  print "\n"
215
238
  print "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
239
+ print output
240
+ print reset, "\n"
241
+ print reset
216
242
  end
217
- print output
218
- print reset, "\n"
219
- print reset
220
- return
243
+ return output
221
244
  end
222
245
 
223
246
  def print_system_command_dry_run(cmd, options={})
@@ -48,6 +48,7 @@ module Morpheus
48
48
 
49
49
  # supresses prompting unless --prompt has been passed
50
50
  def self.no_prompt(option_types, options={}, api_client=nil,api_params={})
51
+ options[:edit_mode] = true # hack used for updates to avoid default values being used
51
52
  if options[:always_prompt]
52
53
  prompt(option_types, options, api_client, api_params)
53
54
  else
@@ -218,7 +219,7 @@ module Morpheus
218
219
 
219
220
  # credential type
220
221
  handle_credential_type = -> {
221
- credential_type = select_prompt(option_type.merge({'defaultValue' => value}), api_client, option_params.merge({'credentialTypes' => option_type['config']['credentialTypes']}), !value.nil?, nil, paging_enabled, ignore_empty)
222
+ credential_type = select_prompt(option_type.merge({'defaultValue' => value}), api_client, option_params.merge({'credentialTypes' => option_type['config']['credentialTypes']}), !value.nil?, nil, paging_enabled, ignore_empty, options[:edit_mode])
222
223
  # continue prompting for local creds
223
224
  if credential_type == 'local'
224
225
  parent_context_map.reject! {|k,v| k == 'credential'}
@@ -247,14 +248,14 @@ module Morpheus
247
248
  end
248
249
  # these select prompts should just fall down through below, with the extra params no_prompt, use_value
249
250
  elsif option_type['type'] == 'select'
250
- value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true, nil, false, ignore_empty)
251
+ value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true, nil, false, ignore_empty, options[:edit_mode])
251
252
  elsif option_type['type'] == 'multiSelect'
252
253
  # support value as csv like "thing1, thing2"
253
254
  value_list = value.is_a?(String) ? value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [value].flatten
254
255
  input_value_list = input_value.is_a?(String) ? input_value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [input_value].flatten
255
256
  select_value_list = []
256
257
  value_list.each_with_index do |v, i|
257
- select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true, nil, false, ignore_empty)
258
+ select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true, nil, false, ignore_empty, options[:edit_mode])
258
259
  end
259
260
  value = select_value_list
260
261
  elsif option_type['type'] == 'typeahead'
@@ -302,7 +303,7 @@ module Morpheus
302
303
  next
303
304
  end
304
305
  if ['select', 'multiSelect'].include?(option_type['type'])
305
- value = select_prompt(option_type, api_client, option_params, true, nil, false, ignore_empty)
306
+ value = select_prompt(option_type, api_client, option_params, true, nil, false, ignore_empty, options[:edit_mode])
306
307
  value_found = !!value
307
308
  end
308
309
  if ['typeahead', 'multiTypeahead'].include?(option_type['type'])
@@ -347,12 +348,12 @@ module Morpheus
347
348
  # I suppose the entered value should take precedence
348
349
  # api_params = api_params.merge(options) # this might be good enough
349
350
  # dup it
350
- value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
351
+ value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty, options[:edit_mode])
351
352
  if value && option_type['type'] == 'multiSelect'
352
353
  value = [value]
353
354
  recommended_count = (option_type['config'] || {})['recommendedCount'] || 0
354
355
  while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => recommended_count > value.count}) do
355
- if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
356
+ if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty, options[:edit_mode])
356
357
  value << addn_value
357
358
  else
358
359
  break
@@ -476,7 +477,7 @@ module Morpheus
476
477
  Thread.current[:_last_select]
477
478
  end
478
479
 
479
- def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false, ignore_empty=false)
480
+ def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false, ignore_empty=false, edit_mode=false)
480
481
  paging_enabled = false if Morpheus::Cli.windows?
481
482
  field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
482
483
  help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
@@ -550,6 +551,8 @@ module Morpheus
550
551
  print "\n"
551
552
  exit 1
552
553
  end
554
+ elsif edit_mode
555
+ # do not use a default value for edit mode
553
556
  # skipSingleOption is no longer supported
554
557
  # elsif !select_options.nil? && select_options.count == 1 && option_type['skipSingleOption'] == true
555
558
  # value_found = true
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "6.1.2"
4
+ VERSION = "6.2.0"
5
5
  end
6
6
  end
@@ -134,7 +134,7 @@ end
134
134
 
135
135
  def format_duration_milliseconds(milliseconds, format="human", ms_threshold=1000)
136
136
  out = ""
137
- milliseconds = milliseconds.abs.to_i
137
+ milliseconds = milliseconds.to_i.abs
138
138
  if ms_threshold && ms_threshold > milliseconds
139
139
  out = "#{milliseconds}ms"
140
140
  else
@@ -100,7 +100,13 @@ module Morpheus::Routes
100
100
  ],
101
101
  },
102
102
  backups: {
103
-
103
+ list: {},
104
+ show: {},
105
+ jobs: {},
106
+ history: [
107
+ "#!restores",
108
+ ],
109
+ services: {}
104
110
  },
105
111
  monitoring: {
106
112
  status: {},
@@ -162,9 +168,10 @@ module Morpheus::Routes
162
168
 
163
169
  # lookup a route in the morpheus UI
164
170
  # @param path [String] The input to lookup a route for eg. "dashboard"
171
+ # @param id [String] ID indicates the show route is needed for a resource for cases where it varies ie. backups
165
172
  # @return full path like "/operations/dashboard"
166
- def self.lookup(input)
167
- path = input.to_s
173
+ def self.lookup(path, id=nil)
174
+ path = path.to_s
168
175
  if path.start_with?("/")
169
176
  # absolute path is being looked up
170
177
  return path
@@ -174,6 +181,14 @@ module Morpheus::Routes
174
181
 
175
182
  # map well known aliases
176
183
  case(path.dasherize.pluralize)
184
+ when "backups"
185
+ path = id ? "/backups/show" : "/backups/list"
186
+ when "backup-jobs"
187
+ path = "/backups/jobs"
188
+ when "backup-results"
189
+ path = "/backups/history"
190
+ when "backup-restores", "restores"
191
+ path = "/backups/history/#!restores"
177
192
  when "servers","hosts","vms","virtual-machines"
178
193
  # actually should be "/infrastructure/inventory" unless id is passed, show route uses /servers though
179
194
  path = "/infrastructure/servers"
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: 6.1.2
4
+ version: 6.2.0
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: 2023-06-21 00:00:00.000000000 Z
14
+ date: 2023-07-17 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -199,6 +199,8 @@ files:
199
199
  - lib/morpheus/api/audit_interface.rb
200
200
  - lib/morpheus/api/auth_interface.rb
201
201
  - lib/morpheus/api/backup_jobs_interface.rb
202
+ - lib/morpheus/api/backup_restores_interface.rb
203
+ - lib/morpheus/api/backup_results_interface.rb
202
204
  - lib/morpheus/api/backup_service_types_interface.rb
203
205
  - lib/morpheus/api/backup_services_interface.rb
204
206
  - lib/morpheus/api/backup_settings_interface.rb
@@ -371,6 +373,8 @@ files:
371
373
  - lib/morpheus/cli/commands/archives_command.rb
372
374
  - lib/morpheus/cli/commands/audit.rb
373
375
  - lib/morpheus/cli/commands/backup_jobs_command.rb
376
+ - lib/morpheus/cli/commands/backup_restores_command.rb
377
+ - lib/morpheus/cli/commands/backup_results_command.rb
374
378
  - lib/morpheus/cli/commands/backup_services_command.rb
375
379
  - lib/morpheus/cli/commands/backup_settings_command.rb
376
380
  - lib/morpheus/cli/commands/backups_command.rb