Add rally env cleanup command

This command should trigger cleanup of resources for the specified
environment.

Change-Id: I4c638d9a5ae5caadf0e5b9cdb78ec589e770cddf
This commit is contained in:
Andrey Kurilin 2018-07-12 18:11:43 +03:00
parent 760e926643
commit 0b110cb2c0
4 changed files with 137 additions and 6 deletions

View File

@ -20,6 +20,11 @@ Changelog
[Unreleased]
------------
Added
~~~~~
* Introducing ``rally env cleanup`` command for performing disaster cleanup.
Changed
~~~~~~~
@ -30,10 +35,11 @@ Changed
allows us to show only those workloads which we are interested in (see the
examples below).
Examples:
1. show only failed workloads
``rally task detailed --filter-by sla-failures``
2. show only those workloads which include the next scenario plugin(s)
``rally task detailed --filter-by scenarios=scenario1[,scenarios2...]``
1. show only failed workloads
``rally task detailed --filter-by sla-failures``
2. show only those workloads which include the next scenario plugin(s)
``rally task detailed --filter-by scenarios=scenario1[,scenarios2...]``
Removed
~~~~~~~

View File

@ -33,6 +33,7 @@ _rally()
OPTS["deployment_show"]="--deployment"
OPTS["deployment_use"]="--deployment"
OPTS["env_check"]="--env --json --detailed"
OPTS["env_cleanup"]="--json --env"
OPTS["env_create"]="--name --description --extras --from-sysenv --spec --json --no-use"
OPTS["env_delete"]="--env --force"
OPTS["env_destroy"]="--env --skip-cleanup --json --detailed"

View File

@ -101,6 +101,48 @@ class EnvCommands(object):
self._show(env.data, to_json=to_json, only_spec=False)
return 0
@cliutils.args("--json", action="store_true", dest="to_json",
help="Format output as JSON.")
@cliutils.args("--env", dest="env", type=str,
metavar="<uuid>", required=False,
help="UUID or name of the env.")
@envutils.with_default_env()
def cleanup(self, api, env=None, to_json=False):
"""Perform disaster cleanup for specified environment.
Cases when Rally can leave undeleted resources after performing
workload:
- Rally execution was interrupted and cleanup was not performed
- The environment or a particular platform became unreachable which
fail Rally execution of cleanup
"""
env = env_mgr.EnvManager.get(env)
_print("Cleaning up resources for %s" % env, to_json)
result = env.cleanup()
if to_json:
print(json.dumps(result, indent=2))
return int(any([p["errors"] for p in result.values()]))
print("Cleaning is finished. See the results bellow.")
return_code = 0
for platform in sorted(result):
cleanup_info = result[platform]
print("\nInformation for %s platform." % platform)
print("=" * 80)
print("Status: %s" % cleanup_info["message"])
for key in ("discovered", "deleted", "failed"):
print("Total %s: %s" % (key, cleanup_info[key]))
if cleanup_info["errors"]:
return_code = 1
errors = "\t- ".join(e["message"]
for e in cleanup_info["errors"])
print("Errors:\n\t- %s" % errors)
return return_code
@cliutils.args("--env", dest="env", type=str,
metavar="<uuid>", required=False,
help="UUID or name of the env.")
@ -124,6 +166,7 @@ class EnvCommands(object):
% (NO, env, result["destroy_info"]["message"]), to_json)
else:
_print("%s Successfully destroyed env %s" % (YES, env), to_json)
if detailed or to_json:
print(json.dumps(result, indent=2))
@ -136,7 +179,7 @@ class EnvCommands(object):
help="Delete DB records even if env is not destroyed.")
@envutils.with_default_env()
def delete(self, api, env=None, force=False):
"""Deletes all records related to Env from db."""
"""Deletes all records related to the environment from db."""
env_mgr.EnvManager.get(env).delete(force=force)
# TODO(boris-42): clear env variables if default one is deleted
@ -196,6 +239,7 @@ class EnvCommands(object):
@cliutils.suppress_warnings
@envutils.with_default_env()
def show(self, api, env=None, to_json=False, only_spec=False):
"""Show base information about the environment record."""
env_data = env_mgr.EnvManager.get(env).data
self._show(env_data, to_json=to_json, only_spec=only_spec)
@ -206,7 +250,7 @@ class EnvCommands(object):
help="Format output as JSON.")
@envutils.with_default_env()
def info(self, api, env=None, to_json=False):
"""Show environment information."""
"""Retrieve and show environment information."""
env = env_mgr.EnvManager.get(env)
env_info = env.get_info()
return_code = int(any(v.get("error") for v in env_info.values()))

View File

@ -153,6 +153,86 @@ class EnvCommandsTestCase(test.TestCase):
mock.call(mock.ANY)
])
@mock.patch("rally.env.env_mgr.EnvManager.get")
@mock.patch("rally.cli.commands.env.print")
def test_cleanup(self, mock_print, mock_env_manager_get):
env_ = mock.Mock()
env_inst = mock_env_manager_get.return_value
env_inst.cleanup.return_value = {
"existing@docker": {
"message": "Success",
"discovered": 5,
"deleted": 5,
"failed": 0,
"errors": []
},
"existing@openstack": {
"message": "It is OpenStack. several failures are ok :)",
"discovered": 10,
"deleted": 8,
"failed": 2,
"errors": [
{"message": "Port disappeared",
"traceback": "traceback"}
]
}
}
self.assertEqual(1, self.env.cleanup(self.api, env_))
mock_env_manager_get.assert_called_once_with(env_)
env_inst.cleanup.assert_called_once_with()
actual_print = "\n".join(
[call_args[0]
for call_args, _call_kwargs in mock_print.call_args_list])
expected_print = (
"Cleaning up resources for %(env)s\n"
"Cleaning is finished. See the results bellow.\n"
"\n"
"Information for existing@docker platform.\n"
"%(hr)s\n"
"Status: Success\n"
"Total discovered: 5\n"
"Total deleted: 5\n"
"Total failed: 0\n"
"\n"
"Information for existing@openstack platform.\n"
"%(hr)s\n"
"Status: It is OpenStack. several failures are ok :)\n"
"Total discovered: 10\n"
"Total deleted: 8\n"
"Total failed: 2\n"
"Errors:\n"
"\t- Port disappeared" % {"env": env_inst, "hr": "=" * 80})
self.assertEqual(expected_print, actual_print)
@mock.patch("rally.env.env_mgr.EnvManager.get")
@mock.patch("rally.cli.commands.env.print")
def test_cleanup_to_json(self, mock_print, mock_env_manager_get):
env_ = mock.Mock()
env_inst = mock_env_manager_get.return_value
env_inst.cleanup.return_value = {
"existing@docker": {
"message": "Success",
"discovered": 5,
"deleted": 5,
"failed": 0,
"errors": []
},
"existing@openstack": {
"message": "It is OpenStack. several failures are ok :)",
"discovered": 10,
"deleted": 8,
"failed": 2,
"errors": [
{"message": "Port disappeared",
"traceback": "traceback"}
]
}
}
self.assertEqual(1, self.env.cleanup(self.api, env_, to_json=True))
mock_print.assert_called_once_with(
json.dumps(env_inst.cleanup.return_value, indent=2))
@mock.patch("rally.env.env_mgr.EnvManager.get")
@mock.patch("rally.cli.commands.env.print")
def test_destroy(self, mock_print, mock_env_manager_get):