blob: 8d06f930cf6f7b39d8f8cebb989e57a6e2ab668c [file] [log] [blame]
David Patersonce781492014-09-18 01:07:01 -04001# Copyright 2014 Dell Inc.
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
David Patersond6babc52014-10-14 00:11:56 -040010# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
David Patersonce781492014-09-18 01:07:01 -040011# License for the specific language governing permissions and limitations
12# under the License.
David Patersonce781492014-09-18 01:07:01 -040013
14"""
Dustin Schoenbrund4d83462017-03-09 18:54:03 -050015Utility for cleaning up environment after Tempest test run
16
17**Usage:** ``tempest cleanup [--help] [OPTIONS]``
18
19If run with no arguments, ``tempest cleanup`` will query your OpenStack
20deployment and build a list of resources to delete and destroy them. This list
21will exclude the resources from ``saved_state.json`` and will include the
22configured admin account if the ``--delete-tempest-conf-objects`` flag is
23specified. By default the admin project is not deleted and the admin user
24specified in ``tempest.conf`` is never deleted.
25
26Example Run
27-----------
28
Masayuki Igawabbbaad62017-11-21 16:04:03 +090029.. warning::
Dustin Schoenbrund4d83462017-03-09 18:54:03 -050030
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +000031 We advice not to run tempest cleanup on production environments.
32
33.. warning::
34
Masayuki Igawabbbaad62017-11-21 16:04:03 +090035 If step 1 is skipped in the example below, the cleanup procedure
36 may delete resources that existed in the cloud before the test run. This
37 may cause an unwanted destruction of cloud resources, so use caution with
38 this command.
Dustin Schoenbrund4d83462017-03-09 18:54:03 -050039
Masayuki Igawabbbaad62017-11-21 16:04:03 +090040 Examples::
Dustin Schoenbrund4d83462017-03-09 18:54:03 -050041
Masayuki Igawabbbaad62017-11-21 16:04:03 +090042 $ tempest cleanup --init-saved-state
43 $ # Actual running of Tempest tests
44 $ tempest cleanup
David Patersonce781492014-09-18 01:07:01 -040045
46Runtime Arguments
47-----------------
48
Masayuki Igawabbbaad62017-11-21 16:04:03 +090049* ``--init-saved-state``: Initializes the saved state of the OpenStack
50 deployment and will output a ``saved_state.json`` file containing resources
51 from your deployment that will be preserved from the cleanup command. This
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +000052 should be done prior to running Tempest tests. Note, that if other users of
53 your cloud could have created resources after running ``--init-saved-state``,
54 it would not protect those resources as they wouldn't be present in the
55 saved_state.json file.
David Patersonce781492014-09-18 01:07:01 -040056
Masayuki Igawabbbaad62017-11-21 16:04:03 +090057* ``--delete-tempest-conf-objects``: If option is present, then the command
58 will delete the admin project in addition to the resources associated with
59 them on clean up. If option is not present, the command will delete the
60 resources associated with the Tempest and alternate Tempest users and
61 projects but will not delete the projects themselves.
David Patersonce781492014-09-18 01:07:01 -040062
Masayuki Igawabbbaad62017-11-21 16:04:03 +090063* ``--dry-run``: Creates a report (``./dry_run.json``) of the projects that
64 will be cleaned up (in the ``_projects_to_clean`` dictionary [1]_) and the
65 global objects that will be removed (domains, flavors, images, roles,
66 projects, and users). Once the cleanup command is executed (e.g. run without
67 parameters), running it again with ``--dry-run`` should yield an empty
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +000068 report. We STRONGLY ENCOURAGE to run ``tempest cleanup`` with ``--dry-run``
69 first and then verify that the resources listed in the ``dry_run.json`` file
70 are meant to be deleted.
71
72* ``--prefix``: Only resources that match the prefix will be deleted. When this
73 option is used, ``saved_state.json`` file is not needed (no need to run with
74 ``--init-saved-state`` first).
75
76 All tempest resources are created with the prefix value from the config
77 option ``resource_name_prefix`` in tempest.conf. To cleanup only the
78 resources created by tempest, you should use the prefix set in your
79 tempest.conf (the default value of ``resource_name_prefix`` is ``tempest``.
80
81 Note, that some resources are not named thus they will not be deleted when
82 filtering based on the prefix. This option will be ignored when
83 ``--init-saved-state`` is used so that it can capture the true init state -
84 all resources present at that moment. If there is any ``saved_state.json``
85 file present (e.g. if you ran the tempest cleanup with ``--init-saved-state``
86 before) and you run the tempest cleanup with ``--prefix``, the
87 ``saved_state.json`` file will be ignored and cleanup will be done based on
88 the passed prefix only.
David Patersonce781492014-09-18 01:07:01 -040089
Katarina Strenkovaf999b152023-10-10 15:16:15 +000090* ``--resource-list``: Allows the use of file ``./resource_list.json``, which
91 contains all resources created by Tempest during all Tempest runs, to
92 create another method for removing only resources created by Tempest.
93 List of these resources is created when config option ``record_resources``
94 in default section is set to true. After using this option for cleanup,
95 the existing ``./resource_list.json`` is cleared from deleted resources.
96
97 When this option is used, ``saved_state.json`` file is not needed (no
98 need to run with ``--init-saved-state`` first). If there is any
99 ``saved_state.json`` file present and you run the tempest cleanup with
100 ``--resource-list``, the ``saved_state.json`` file will be ignored and
101 cleanup will be done based on the ``resource_list.json`` only.
102
103 If you run tempest cleanup with both ``--prefix`` and ``--resource-list``,
104 the ``--resource-list`` option will be ignored and cleanup will be done
105 based on the ``--prefix`` option only.
106
Masayuki Igawabbbaad62017-11-21 16:04:03 +0900107* ``--help``: Print the help text for the command and parameters.
David Patersonce781492014-09-18 01:07:01 -0400108
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200109.. [1] The ``_projects_to_clean`` dictionary in ``dry_run.json`` lists the
Dustin Schoenbrund4d83462017-03-09 18:54:03 -0500110 projects that ``tempest cleanup`` will loop through to delete child
111 objects, but the command will, by default, not delete the projects
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200112 themselves. This may differ from the ``projects`` list as you can clean
Dustin Schoenbrund4d83462017-03-09 18:54:03 -0500113 the Tempest and alternate Tempest users and projects but they will not be
Masayuki Igawabbbaad62017-11-21 16:04:03 +0900114 deleted unless the ``--delete-tempest-conf-objects`` flag is used to
Dustin Schoenbrund4d83462017-03-09 18:54:03 -0500115 force their deletion.
David Patersonce781492014-09-18 01:07:01 -0400116
Martin Kopec219e3222019-08-05 20:02:20 +0000117.. note::
118
119 If during execution of ``tempest cleanup`` NotImplemented exception
120 occurres, ``tempest cleanup`` won't fail on that, it will be logged only.
121 NotImplemented errors are ignored because they are an outcome of some
122 extensions being disabled and ``tempest cleanup`` is not checking their
123 availability as it tries to clean up as much as possible without any
124 complicated logic.
125
David Patersonce781492014-09-18 01:07:01 -0400126"""
David Patersonce781492014-09-18 01:07:01 -0400127import sys
Marc Kodererf3397942015-12-21 11:17:09 +0100128import traceback
David Patersonce781492014-09-18 01:07:01 -0400129
David Paterson07661de2015-10-29 20:15:04 -0700130from cliff import command
Doug Hellmann583ce2c2015-03-11 14:55:46 +0000131from oslo_log import log as logging
Matthew Treinish21905512015-07-13 10:33:35 -0400132from oslo_serialization import jsonutils as json
Doug Hellmann583ce2c2015-03-11 14:55:46 +0000133
David Patersonce781492014-09-18 01:07:01 -0400134from tempest import clients
135from tempest.cmd import cleanup_service
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100136from tempest.common import credentials_factory as credentials
David Patersonce781492014-09-18 01:07:01 -0400137from tempest import config
Martin Kopec219e3222019-08-05 20:02:20 +0000138from tempest.lib import exceptions
David Patersonce781492014-09-18 01:07:01 -0400139
140SAVED_STATE_JSON = "saved_state.json"
141DRY_RUN_JSON = "dry_run.json"
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000142RESOURCE_LIST_JSON = "resource_list.json"
David Patersonce781492014-09-18 01:07:01 -0400143LOG = logging.getLogger(__name__)
144CONF = config.CONF
145
146
David Paterson07661de2015-10-29 20:15:04 -0700147class TempestCleanup(command.Command):
David Patersonce781492014-09-18 01:07:01 -0400148
Martin Kopec97857942019-06-12 15:23:21 +0000149 GOT_EXCEPTIONS = []
150
David Paterson07661de2015-10-29 20:15:04 -0700151 def take_action(self, parsed_args):
Marc Kodererf3397942015-12-21 11:17:09 +0100152 try:
153 self.init(parsed_args)
Ghanshyam41711d32016-02-17 17:11:22 +0900154 if not parsed_args.init_saved_state:
155 self._cleanup()
Marc Kodererf3397942015-12-21 11:17:09 +0100156 except Exception:
157 LOG.exception("Failure during cleanup")
158 traceback.print_exc()
159 raise
Martin Kopec219e3222019-08-05 20:02:20 +0000160 # ignore NotImplemented errors as those are an outcome of some
161 # extensions being disabled and cleanup is not checking their
162 # availability as it tries to clean up as much as possible without
163 # any complicated logic
164 critical_exceptions = [ex for ex in self.GOT_EXCEPTIONS if
165 not isinstance(ex, exceptions.NotImplemented)]
166 if critical_exceptions:
Martin Kopec97857942019-06-12 15:23:21 +0000167 raise Exception(self.GOT_EXCEPTIONS)
Marc Kodererf3397942015-12-21 11:17:09 +0100168
169 def init(self, parsed_args):
Martin Kopeca8578802020-04-07 08:19:14 +0000170 # set new handler for logging to stdout, by default only INFO messages
171 # are logged to stdout
172 stdout_handler = logging.logging.StreamHandler()
173 # debug argument is defined in cliff already
174 if self.app_args.debug:
175 stdout_handler.level = logging.DEBUG
176 else:
177 stdout_handler.level = logging.INFO
178 LOG.handlers.append(stdout_handler)
179
David Paterson07661de2015-10-29 20:15:04 -0700180 cleanup_service.init_conf()
181 self.options = parsed_args
ghanshyam009a1f62017-08-08 10:22:57 +0300182 self.admin_mgr = clients.Manager(
183 credentials.get_configured_admin_credentials())
David Patersonce781492014-09-18 01:07:01 -0400184 self.dry_run_data = {}
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000185 self.resource_data = {}
David Patersonce781492014-09-18 01:07:01 -0400186 self.json_data = {}
David Patersonce781492014-09-18 01:07:01 -0400187
David Patersonce781492014-09-18 01:07:01 -0400188 # available services
Martin Kopec56c0b2b2019-11-13 12:50:07 +0000189 self.project_associated_services = (
190 cleanup_service.get_project_associated_cleanup_services())
191 self.resource_cleanup_services = (
192 cleanup_service.get_resource_cleanup_services())
David Patersonce781492014-09-18 01:07:01 -0400193 self.global_services = cleanup_service.get_global_cleanup_services()
David Patersonce781492014-09-18 01:07:01 -0400194
David Paterson07661de2015-10-29 20:15:04 -0700195 if parsed_args.init_saved_state:
David Patersonce781492014-09-18 01:07:01 -0400196 self._init_state()
197 return
198
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000199 if parsed_args.prefix:
200 return
201
202 if parsed_args.resource_list:
203 self._load_resource_list()
204 return
205
206 self._load_saved_state()
David Patersonce781492014-09-18 01:07:01 -0400207
208 def _cleanup(self):
Martin Kopeca8578802020-04-07 08:19:14 +0000209 LOG.info("Begin cleanup")
David Patersonce781492014-09-18 01:07:01 -0400210 is_dry_run = self.options.dry_run
David Patersond6babc52014-10-14 00:11:56 -0400211 is_preserve = not self.options.delete_tempest_conf_objects
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000212 is_resource_list = self.options.resource_list
David Patersonce781492014-09-18 01:07:01 -0400213 is_save_state = False
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000214 cleanup_prefix = self.options.prefix
David Patersonce781492014-09-18 01:07:01 -0400215
216 if is_dry_run:
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200217 self.dry_run_data["_projects_to_clean"] = {}
David Patersonce781492014-09-18 01:07:01 -0400218
219 admin_mgr = self.admin_mgr
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200220 # Always cleanup tempest and alt tempest projects unless
David Patersonce781492014-09-18 01:07:01 -0400221 # they are in saved state json. Therefore is_preserve is False
222 kwargs = {'data': self.dry_run_data,
223 'is_dry_run': is_dry_run,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000224 'resource_list_json': self.resource_data,
David Patersonce781492014-09-18 01:07:01 -0400225 'saved_state_json': self.json_data,
226 'is_preserve': False,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000227 'is_resource_list': is_resource_list,
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000228 'is_save_state': is_save_state,
229 'prefix': cleanup_prefix}
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200230 project_service = cleanup_service.ProjectService(admin_mgr, **kwargs)
231 projects = project_service.list()
Martin Kopeca8578802020-04-07 08:19:14 +0000232 LOG.info("Processing %s projects", len(projects))
David Patersonce781492014-09-18 01:07:01 -0400233
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200234 # Loop through list of projects and clean them up.
235 for project in projects:
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200236 self._clean_project(project)
David Patersonce781492014-09-18 01:07:01 -0400237
238 kwargs = {'data': self.dry_run_data,
239 'is_dry_run': is_dry_run,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000240 'resource_list_json': self.resource_data,
David Patersonce781492014-09-18 01:07:01 -0400241 'saved_state_json': self.json_data,
242 'is_preserve': is_preserve,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000243 'is_resource_list': is_resource_list,
Martin Kopec97857942019-06-12 15:23:21 +0000244 'is_save_state': is_save_state,
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000245 'prefix': cleanup_prefix,
Martin Kopec97857942019-06-12 15:23:21 +0000246 'got_exceptions': self.GOT_EXCEPTIONS}
Martin Kopeca8578802020-04-07 08:19:14 +0000247 LOG.info("Processing global services")
David Patersonce781492014-09-18 01:07:01 -0400248 for service in self.global_services:
249 svc = service(admin_mgr, **kwargs)
250 svc.run()
251
Martin Kopeca8578802020-04-07 08:19:14 +0000252 LOG.info("Processing services")
Martin Kopec56c0b2b2019-11-13 12:50:07 +0000253 for service in self.resource_cleanup_services:
254 svc = service(self.admin_mgr, **kwargs)
255 svc.run()
256
David Patersonce781492014-09-18 01:07:01 -0400257 if is_dry_run:
zhang.leia4b1cef2016-03-01 10:50:01 +0800258 with open(DRY_RUN_JSON, 'w+') as f:
259 f.write(json.dumps(self.dry_run_data, sort_keys=True,
260 indent=2, separators=(',', ': ')))
David Patersonce781492014-09-18 01:07:01 -0400261
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000262 if is_resource_list:
263 LOG.info("Clearing 'resource_list.json' file.")
264 with open(RESOURCE_LIST_JSON, 'w') as f:
265 f.write('{}')
266
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200267 def _clean_project(self, project):
Martin Kopeca8578802020-04-07 08:19:14 +0000268 LOG.debug("Cleaning project: %s ", project['name'])
David Patersonce781492014-09-18 01:07:01 -0400269 is_dry_run = self.options.dry_run
270 dry_run_data = self.dry_run_data
David Patersond6babc52014-10-14 00:11:56 -0400271 is_preserve = not self.options.delete_tempest_conf_objects
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000272 is_resource_list = self.options.resource_list
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200273 project_id = project['id']
274 project_name = project['name']
275 project_data = None
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000276 cleanup_prefix = self.options.prefix
David Patersonce781492014-09-18 01:07:01 -0400277 if is_dry_run:
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200278 project_data = dry_run_data["_projects_to_clean"][project_id] = {}
279 project_data['name'] = project_name
David Patersonce781492014-09-18 01:07:01 -0400280
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200281 kwargs = {'data': project_data,
David Patersonce781492014-09-18 01:07:01 -0400282 'is_dry_run': is_dry_run,
Martin Kopec5a884bf2019-02-11 18:10:55 +0000283 'saved_state_json': self.json_data,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000284 'resource_list_json': self.resource_data,
David Patersonce781492014-09-18 01:07:01 -0400285 'is_preserve': is_preserve,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000286 'is_resource_list': is_resource_list,
David Patersonce781492014-09-18 01:07:01 -0400287 'is_save_state': False,
Martin Kopec97857942019-06-12 15:23:21 +0000288 'project_id': project_id,
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000289 'prefix': cleanup_prefix,
Martin Kopec97857942019-06-12 15:23:21 +0000290 'got_exceptions': self.GOT_EXCEPTIONS}
Martin Kopec56c0b2b2019-11-13 12:50:07 +0000291 for service in self.project_associated_services:
Martin Kopec7ca86022019-10-04 14:13:59 +0000292 svc = service(self.admin_mgr, **kwargs)
David Patersonce781492014-09-18 01:07:01 -0400293 svc.run()
294
David Paterson07661de2015-10-29 20:15:04 -0700295 def get_parser(self, prog_name):
296 parser = super(TempestCleanup, self).get_parser(prog_name)
David Patersonce781492014-09-18 01:07:01 -0400297 parser.add_argument('--init-saved-state', action="store_true",
298 dest='init_saved_state', default=False,
299 help="Creates JSON file: " + SAVED_STATE_JSON +
300 ", representing the current state of your "
David Patersond6babc52014-10-14 00:11:56 -0400301 "deployment, specifically object types "
302 "tempest creates and destroys during a run. "
David Patersonce781492014-09-18 01:07:01 -0400303 "You must run with this flag prior to "
David Patersond6babc52014-10-14 00:11:56 -0400304 "executing cleanup in normal mode, which is with "
305 "no arguments.")
David Patersonce781492014-09-18 01:07:01 -0400306 parser.add_argument('--delete-tempest-conf-objects',
David Patersond6babc52014-10-14 00:11:56 -0400307 action="store_true",
308 dest='delete_tempest_conf_objects',
David Patersonce781492014-09-18 01:07:01 -0400309 default=False,
David Patersond6babc52014-10-14 00:11:56 -0400310 help="Force deletion of the tempest and "
Arx Cruz05fe4bc2017-10-20 10:48:28 +0200311 "alternate tempest users and projects.")
David Patersonce781492014-09-18 01:07:01 -0400312 parser.add_argument('--dry-run', action="store_true",
313 dest='dry_run', default=False,
314 help="Generate JSON file:" + DRY_RUN_JSON +
315 ", that reports the objects that would have "
316 "been deleted had a full cleanup been run.")
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000317 parser.add_argument('--prefix', dest='prefix', default=None,
318 help="Only resources that match the prefix will "
319 "be deleted (resources in saved_state.json are "
320 "not taken into account). All tempest resources "
321 "are created with the prefix value set by "
322 "resource_name_prefix in tempest.conf, default "
323 "prefix is tempest. Note that some resources are "
324 "not named thus they will not be deleted when "
325 "filtering based on the prefix. This opt will be "
326 "ignored when --init-saved-state is used so that "
327 "it can capture the true init state - all "
328 "resources present at that moment.")
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000329 parser.add_argument('--resource-list', action="store_true",
330 dest='resource_list', default=False,
331 help="Runs tempest cleanup with generated "
332 "JSON file: " + RESOURCE_LIST_JSON + " to "
333 "erase resources created during Tempest run. "
334 "NOTE: To create " + RESOURCE_LIST_JSON + " "
335 "set config option record_resources under default "
336 "section in tempest.conf file to true. This "
337 "option will be ignored when --init-saved-state "
338 "is used so that it can capture the true init "
339 "state - all resources present at that moment. "
340 "This option will be ignored if passed with "
341 "--prefix.")
David Paterson07661de2015-10-29 20:15:04 -0700342 return parser
David Patersonce781492014-09-18 01:07:01 -0400343
David Paterson07661de2015-10-29 20:15:04 -0700344 def get_description(self):
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000345 return ('tempest cleanup tool, read the full documentation before '
346 'using this tool. We advice not to run it on production '
347 'environments. On environments where also other users may '
348 'create resources, we strongly advice using --dry-run '
349 'argument first and verify the content of dry_run.json file.')
David Patersonce781492014-09-18 01:07:01 -0400350
David Patersonce781492014-09-18 01:07:01 -0400351 def _init_state(self):
Martin Kopeca8578802020-04-07 08:19:14 +0000352 LOG.info("Initializing saved state.")
David Patersonce781492014-09-18 01:07:01 -0400353 data = {}
354 admin_mgr = self.admin_mgr
355 kwargs = {'data': data,
356 'is_dry_run': False,
357 'saved_state_json': data,
358 'is_preserve': False,
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000359 'is_resource_list': False,
Martin Kopec97857942019-06-12 15:23:21 +0000360 'is_save_state': True,
Luigi Dino Tamagnone9052dfc2023-04-09 15:24:45 +0000361 # must be None as we want to capture true init state
362 # (all resources present) thus no filtering based
363 # on the prefix
364 'prefix': None,
Martin Kopec97857942019-06-12 15:23:21 +0000365 'got_exceptions': self.GOT_EXCEPTIONS}
David Patersonce781492014-09-18 01:07:01 -0400366 for service in self.global_services:
367 svc = service(admin_mgr, **kwargs)
368 svc.run()
369
Martin Kopec56c0b2b2019-11-13 12:50:07 +0000370 for service in self.project_associated_services:
371 svc = service(admin_mgr, **kwargs)
372 svc.run()
373
374 for service in self.resource_cleanup_services:
Martin Kopec5a884bf2019-02-11 18:10:55 +0000375 svc = service(admin_mgr, **kwargs)
376 svc.run()
377
zhang.leia4b1cef2016-03-01 10:50:01 +0800378 with open(SAVED_STATE_JSON, 'w+') as f:
afazekas40fcb9b2019-03-08 11:25:11 +0100379 f.write(json.dumps(data, sort_keys=True,
380 indent=2, separators=(',', ': ')))
David Patersonce781492014-09-18 01:07:01 -0400381
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000382 def _load_resource_list(self, resource_list_json=RESOURCE_LIST_JSON):
383 try:
384 with open(resource_list_json, 'rb') as json_file:
385 self.resource_data = json.load(json_file)
386 except IOError as ex:
387 LOG.exception(
388 "Failed loading 'resource_list.json', please "
389 "be sure you created this file by setting config "
390 "option record_resources in default section to true "
391 "prior to running tempest. Exception: %s", ex)
392 sys.exit(ex)
393 except Exception as ex:
394 LOG.exception(
395 "Exception parsing 'resource_list.json' : %s", ex)
396 sys.exit(ex)
397
398 def _load_saved_state(self, saved_state_json=SAVED_STATE_JSON):
David Patersonce781492014-09-18 01:07:01 -0400399 try:
Martin Kopec6caf3fa2019-01-20 15:24:10 +0000400 with open(saved_state_json, 'rb') as json_file:
zhang.leia4b1cef2016-03-01 10:50:01 +0800401 self.json_data = json.load(json_file)
David Patersonce781492014-09-18 01:07:01 -0400402 except IOError as ex:
Katarina Strenkovaf999b152023-10-10 15:16:15 +0000403 LOG.exception(
404 "Failed loading saved state, please be sure you"
405 " have first run cleanup with --init-saved-state "
406 "flag prior to running tempest. Exception: %s", ex)
David Patersonce781492014-09-18 01:07:01 -0400407 sys.exit(ex)
408 except Exception as ex:
Jordan Pittier525ec712016-12-07 17:51:26 +0100409 LOG.exception("Exception parsing saved state json : %s", ex)
David Patersonce781492014-09-18 01:07:01 -0400410 sys.exit(ex)