[CLI] Allow changing deployment config on recreate

* Added --filename option to deployment recreate that
  will update configuration from provided file.

Change-Id: Icefca03fd86ab8977d0910bf192187c713cb355f
This commit is contained in:
Anton Studenov 2017-01-25 21:06:06 +03:00
parent e70a75190f
commit 5ee6a18df2
8 changed files with 103 additions and 8 deletions

View File

@ -23,7 +23,7 @@ _rally()
OPTS["deployment_create"]="--name --fromenv --filename --no-use"
OPTS["deployment_destroy"]="--deployment"
OPTS["deployment_list"]=""
OPTS["deployment_recreate"]="--deployment"
OPTS["deployment_recreate"]="--filename --deployment"
OPTS["deployment_show"]="--deployment"
OPTS["deployment_use"]="--deployment"
OPTS["plugin_list"]="--name --namespace --plugin-base"

View File

@ -103,16 +103,33 @@ class _Deployment(object):
deployment.delete()
@classmethod
def recreate(cls, deployment):
def recreate(cls, deployment, config=None):
"""Performs a cleanup and then makes a deployment again.
:param deployment: UUID or name of the deployment
:param config: an optional dict with deployment config to update before
redeploy
"""
deployment = objects.Deployment.get(deployment)
deployer = deploy_engine.Engine.get_engine(
deployment["config"]["type"], deployment)
if config:
if deployment["config"]["type"] != config["type"]:
raise exceptions.RallyException(
"Can't change deployment type.")
try:
deployer.validate(config)
except jsonschema.ValidationError:
LOG.error(_LE("Config schema validation error."))
raise
with deployer:
deployer.make_cleanup()
if config:
deployment.update_config(config)
credentials = deployer.make_deploy()
deployment.update_credentials(credentials)

View File

@ -111,12 +111,14 @@ class DeploymentCommands(object):
if do_use:
self.use(api, deployment["uuid"])
@cliutils.args("--filename", type=str, required=False, metavar="<path>",
help="Path to the configuration file of the deployment.")
@cliutils.args("--deployment", dest="deployment", type=str,
metavar="<uuid>", required=False,
help="UUID or name of the deployment.")
@envutils.with_default_deployment()
@plugins.ensure_plugins_are_loaded
def recreate(self, api, deployment=None):
def recreate(self, api, deployment=None, filename=None):
"""Destroy and create an existing deployment.
Unlike 'deployment destroy', the deployment database record
@ -124,7 +126,12 @@ class DeploymentCommands(object):
:param deployment: UUID or name of the deployment
"""
api.deployment.recreate(deployment)
config = None
if filename:
with open(filename, "rb") as deploy_file:
config = yaml.safe_load(deploy_file.read())
api.deployment.recreate(deployment, config)
@cliutils.args("--deployment", dest="deployment", type=str,
metavar="<uuid>", required=False,

View File

@ -73,11 +73,11 @@ class Engine(plugin.Plugin):
self.deployment = deployment
self.config = deployment["config"]
def validate(self):
def validate(self, config=None):
# TODO(sskripnick): remove this checking when config schema
# is done for all available engines
if hasattr(self, "CONFIG_SCHEMA"):
jsonschema.validate(self.config, self.CONFIG_SCHEMA)
jsonschema.validate(config or self.config, self.CONFIG_SCHEMA)
# FIXME(boris-42): Get rid of this method
def get_provider(self):

View File

@ -83,6 +83,18 @@ class DeploymentTestCase(unittest.TestCase):
self.rally("deployment recreate --deployment t_create_env")
self.assertIn("t_create_env", self.rally("deployment list"))
def test_recreate_from_file(self):
self.rally.env.update(utils.TEST_ENV)
self.rally("deployment create --name t_create_env --fromenv")
config = json.loads(self.rally("deployment config"))
config["auth_url"] = "http://foo/"
file = utils.JsonTempFile(config)
self.rally("deployment recreate --deployment t_create_env "
"--filename %s" % file.filename)
self.assertIn("t_create_env", self.rally("deployment list"))
self.assertEqual(config,
json.loads(self.rally("deployment config")))
def test_use(self):
self.rally.env.update(utils.TEST_ENV)
output = self.rally(

View File

@ -53,7 +53,7 @@ class RallyCliError(Exception):
return self.msg
class TaskConfig(object):
class JsonTempFile(object):
def __init__(self, config):
config_file = tempfile.NamedTemporaryFile(delete=False)
@ -65,6 +65,10 @@ class TaskConfig(object):
os.unlink(self.filename)
class TaskConfig(JsonTempFile):
pass
class Rally(object):
"""Create and represent separate rally installation.

View File

@ -131,7 +131,17 @@ class DeploymentCommandsTestCase(test.TestCase):
deployment_id = "43924f8b-9371-4152-af9f-4cf02b4eced4"
self.deployment.recreate(self.fake_api, deployment_id)
self.fake_api.deployment.recreate.assert_called_once_with(
deployment_id)
deployment_id, None)
@mock.patch("rally.cli.commands.deployment.open",
side_effect=mock.mock_open(read_data="{\"some\": \"json\"}"),
create=True)
def test_recreate_config(self, mock_open):
deployment_id = "43924f8b-9371-4152-af9f-4cf02b4eced4"
self.deployment.recreate(self.fake_api, deployment_id,
filename="my.json")
self.fake_api.deployment.recreate.assert_called_once_with(
deployment_id, {"some": "json"})
@mock.patch("rally.cli.commands.deployment.envutils.get_global")
def test_recreate_no_deployment_id(self, mock_get_global):

View File

@ -15,6 +15,7 @@
"""Test for api."""
import copy
import os
import ddt
@ -421,6 +422,50 @@ class DeploymentAPITestCase(BaseDeploymentTestCase):
})
])
@mock.patch("rally.common.objects.deploy.db.deployment_update")
@mock.patch("rally.common.objects.deploy.db.deployment_get")
def test_recreate_config(self, mock_deployment_get,
mock_deployment_update):
mock_deployment_get.return_value = self.deployment
mock_deployment_update.return_value = self.deployment
config = copy.deepcopy(self.deployment_config)
config["admin"] = {"username": "admin",
"password": "pass1",
"tenant_name": "demo"}
config["users"] = [{"username": "user1",
"password": "pass2",
"tenant_name": "demo"}]
api._Deployment.recreate(self.deployment_uuid, config)
mock_deployment_get.assert_called_once_with(self.deployment_uuid)
mock_deployment_update.assert_has_calls([
mock.call(self.deployment_uuid, {"config": config}),
])
@mock.patch("rally.common.objects.deploy.db.deployment_update")
@mock.patch("rally.common.objects.deploy.db.deployment_get")
def test_recreate_config_invalid(self, mock_deployment_get,
mock_deployment_update):
mock_deployment_get.return_value = self.deployment
mock_deployment_update.return_value = self.deployment
config = copy.deepcopy(self.deployment_config)
config["admin"] = {"foo": "bar"}
self.assertRaises(jsonschema.ValidationError, api._Deployment.recreate,
self.deployment_uuid, config)
@mock.patch("rally.common.objects.deploy.db.deployment_update")
@mock.patch("rally.common.objects.deploy.db.deployment_get")
def test_recreate_config_wrong_type(self, mock_deployment_get,
mock_deployment_update):
mock_deployment_get.return_value = self.deployment
mock_deployment_update.return_value = self.deployment
config = copy.deepcopy(self.deployment_config)
config["type"] = "foo"
self.assertRaises(exceptions.RallyException, api._Deployment.recreate,
self.deployment_uuid, config)
@mock.patch("rally.common.objects.deploy.db.deployment_get")
def test_get(self, mock_deployment_get):
deployment_id = "aaaa-bbbb-cccc-dddd"