Add support for dry-run and noop deployment for deploy changes commands
This commit adds an additional options to fuel client to support dry-run and noop modes of deployment which are really useful for debugging and day-to day operations and life cycle management of clusters Partial-bug: #1569839 Change-Id: I77d0a8257a97a9f40e3cfd1a630c95b7800fe1e6
This commit is contained in:
parent
60c7f90ffa
commit
7597187095
|
@ -15,6 +15,7 @@
|
|||
|
||||
from fuelclient.cli.actions.base import Action
|
||||
import fuelclient.cli.arguments as Args
|
||||
from fuelclient.cli.arguments import group
|
||||
from fuelclient.cli.formatting import print_deploy_progress
|
||||
from fuelclient.objects.environment import Environment
|
||||
|
||||
|
@ -28,6 +29,9 @@ class ChangesAction(Action):
|
|||
super(ChangesAction, self).__init__()
|
||||
self.args = (
|
||||
Args.get_env_arg(required=True),
|
||||
group(
|
||||
Args.get_dry_run_deployment_arg(),
|
||||
Args.get_noop_deployment_arg())
|
||||
)
|
||||
self.flag_func_map = (
|
||||
(None, self.deploy_changes),
|
||||
|
@ -38,7 +42,10 @@ class ChangesAction(Action):
|
|||
fuel --env 1 {action_name}
|
||||
"""
|
||||
env = Environment(params.env)
|
||||
deploy_task = getattr(env, self.actions_func_map[self.action_name])()
|
||||
|
||||
deploy_task = getattr(
|
||||
env, self.actions_func_map[self.action_name])(
|
||||
dry_run=params.dry_run, noop=params.noop)
|
||||
self.serializer.print_to_output(
|
||||
deploy_task.data,
|
||||
deploy_task,
|
||||
|
|
|
@ -258,6 +258,22 @@ def get_sync_deployment_tasks_arg():
|
|||
help="Update tasks for each release.")
|
||||
|
||||
|
||||
def get_dry_run_deployment_arg():
|
||||
return get_boolean_arg(
|
||||
"dry-run",
|
||||
dest='dry_run',
|
||||
help="Specifies to dry-run a deployment by configuring task executor"
|
||||
"to dump the deployment graph to a dot file.")
|
||||
|
||||
|
||||
def get_noop_deployment_arg():
|
||||
return get_boolean_arg(
|
||||
"noop",
|
||||
help="Specifies for task executor to do noop deployment "
|
||||
"which will ask task executor to run noop drivers"
|
||||
"for each task (e.g. puppet apply --noop)")
|
||||
|
||||
|
||||
def get_file_pattern_arg():
|
||||
return get_str_arg(
|
||||
"filepattern",
|
||||
|
|
|
@ -203,10 +203,31 @@ class EnvDeploy(EnvMixIn, base.BaseCommand):
|
|||
type=int,
|
||||
help='Id of the environment to be deployed.')
|
||||
|
||||
dry_run_help_string = 'Specifies to dry-run a deployment by' \
|
||||
'configuring task executor to dump the' \
|
||||
'deployment graph to a dot file.' \
|
||||
'Store cluster settings and serialized ' \
|
||||
'data in the db and ask the task executor ' \
|
||||
'to dump the resulting graph into a dot file'
|
||||
|
||||
noop_help_string = 'Perform noop run of the deployment by asking the' \
|
||||
'task executor to run noop drivers of each task'
|
||||
|
||||
dryrun_noop_group = parser.add_mutually_exclusive_group(required=False)
|
||||
|
||||
dryrun_noop_group.add_argument(
|
||||
'-d', '--dry-run', dest="dry_run",
|
||||
action='store_true', help=dry_run_help_string)
|
||||
dryrun_noop_group.add_argument(
|
||||
'-n', '--noop', action='store_true',
|
||||
help=noop_help_string)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
task_id = self.client.deploy_changes(parsed_args.id)
|
||||
task_id = self.client.deploy_changes(parsed_args.id,
|
||||
dry_run=parsed_args.dry_run,
|
||||
noop=parsed_args.noop)
|
||||
|
||||
msg = 'Deployment task with id {t} for the environment {e} '\
|
||||
'has been started.\n'.format(t=task_id, e=parsed_args.id)
|
||||
|
@ -214,20 +235,13 @@ class EnvDeploy(EnvMixIn, base.BaseCommand):
|
|||
self.app.stdout.write(msg)
|
||||
|
||||
|
||||
class EnvRedeploy(EnvMixIn, base.BaseCommand):
|
||||
class EnvRedeploy(EnvDeploy):
|
||||
"""Redeploys changes on the specified environment."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(EnvRedeploy, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('id',
|
||||
type=int,
|
||||
help='Id of the environment to be redeployed.')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
task_id = self.client.redeploy_changes(parsed_args.id)
|
||||
task_id = self.client.redeploy_changes(parsed_args.id,
|
||||
dry_run=parsed_args.dry_run,
|
||||
noop=parsed_args.noop)
|
||||
|
||||
msg = 'Deployment task with id {t} for the environment {e} '\
|
||||
'has been started.\n'.format(t=task_id, e=parsed_args.id)
|
||||
|
|
|
@ -93,17 +93,17 @@ class Environment(BaseObject):
|
|||
[{"id": n.id} for n in nodes]
|
||||
)
|
||||
|
||||
def deploy_changes(self):
|
||||
def deploy_changes(self, dry_run=False, noop=False):
|
||||
deploy_data = self.connection.put_request(
|
||||
"clusters/{0}/changes".format(self.id),
|
||||
{}
|
||||
{}, dry_run=int(dry_run), noop=int(noop)
|
||||
)
|
||||
return DeployTask.init_with_data(deploy_data)
|
||||
|
||||
def redeploy_changes(self):
|
||||
def redeploy_changes(self, dry_run=False, noop=False):
|
||||
deploy_data = self.connection.put_request(
|
||||
"clusters/{0}/changes/redeploy".format(self.id),
|
||||
{}
|
||||
{}, dry_run=int(dry_run), noop=int(noop)
|
||||
)
|
||||
return DeployTask.init_with_data(deploy_data)
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import mock
|
||||
import requests_mock as rm
|
||||
from six import moves
|
||||
|
@ -60,6 +59,110 @@ class TestEnvironment(base.UnitTestCase):
|
|||
"deprecated since 7.0 release.",
|
||||
m_stderr.getvalue())
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_deploy_changes(self, task_data):
|
||||
dry_run = False
|
||||
noop = False
|
||||
mdeploy = self.m_request.put('/api/v1/clusters/1/changes'
|
||||
'?dry_run={0}&noop={1}'.format(
|
||||
int(dry_run), int(noop)), json={})
|
||||
|
||||
cmd = ['fuel', 'deploy-changes', '--env', '1']
|
||||
self.execute(cmd)
|
||||
self.check_deploy_redeploy_changes(dry_run, mdeploy, noop)
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_deploy_changes_dry_run(self, task_data):
|
||||
dry_run = True
|
||||
noop = False
|
||||
mdeploy = self.m_request.put('/api/v1/clusters/1/changes'
|
||||
'?dry_run={0}&noop={1}'.format(
|
||||
int(dry_run), int(noop)), json={})
|
||||
|
||||
cmd = ['fuel', 'deploy-changes', '--env', '1']
|
||||
|
||||
cmd.append('--dry-run')
|
||||
self.execute(cmd)
|
||||
self.check_deploy_redeploy_changes(dry_run, mdeploy, noop)
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_deploy_changes_noop(self, task_data):
|
||||
dry_run = False
|
||||
noop = True
|
||||
mdeploy = self.m_request.put('/api/v1/clusters/1/changes'
|
||||
'?dry_run={0}&noop={1}'.format(
|
||||
int(dry_run), int(noop)), json={})
|
||||
|
||||
cmd = ['fuel', 'deploy-changes', '--env', '1']
|
||||
|
||||
cmd.append('--noop')
|
||||
self.execute(cmd)
|
||||
self.check_deploy_redeploy_changes(dry_run, mdeploy, noop)
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_deploy_changes_noop_dry_run(self, task_data):
|
||||
cmd = ['fuel', 'deploy-changes', '--env', '1']
|
||||
|
||||
cmd.append('--dry-run')
|
||||
cmd.append('--noop')
|
||||
self.assertRaises(SystemExit, self.execute, cmd)
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_redeploy_changes(self, task_data):
|
||||
dry_run = False
|
||||
noop = False
|
||||
mdeploy = self.m_request.put('/api/v1/clusters/1/changes/redeploy'
|
||||
'?dry_run={0}&noop={1}'.format(
|
||||
int(dry_run), int(noop)), json={})
|
||||
|
||||
cmd = ['fuel', 'redeploy-changes', '--env', '1']
|
||||
|
||||
self.execute(cmd)
|
||||
self.check_deploy_redeploy_changes(dry_run, mdeploy, noop)
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_redeploy_changes_dry_run(self, task_data):
|
||||
dry_run = True
|
||||
noop = False
|
||||
mdeploy = self.m_request.put('/api/v1/clusters/1/changes/redeploy'
|
||||
'?dry_run={0}&noop={1}'.format(
|
||||
int(dry_run), int(noop)), json={})
|
||||
|
||||
cmd = ['fuel', 'redeploy-changes', '--env', '1']
|
||||
|
||||
cmd.append('--dry-run')
|
||||
self.execute(cmd)
|
||||
self.check_deploy_redeploy_changes(dry_run, mdeploy, noop)
|
||||
|
||||
def check_deploy_redeploy_changes(self, dry_run, mdeploy, noop):
|
||||
self.assertEqual(mdeploy.last_request.qs['dry_run'][0],
|
||||
str(int(dry_run)))
|
||||
self.assertEqual(mdeploy.last_request.qs['noop'][0],
|
||||
str(int(noop)))
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_redeploy_changes_noop(self, task_data):
|
||||
dry_run = False
|
||||
noop = True
|
||||
mdeploy = self.m_request.put('/api/v1/clusters/1/changes/redeploy'
|
||||
'?dry_run={0}&noop={1}'.format(
|
||||
int(dry_run), int(noop)), json={})
|
||||
|
||||
cmd = ['fuel', 'redeploy-changes', '--env', '1']
|
||||
if dry_run:
|
||||
cmd.append('--dry-run')
|
||||
if noop:
|
||||
cmd.append('--noop')
|
||||
self.execute(cmd)
|
||||
self.check_deploy_redeploy_changes(dry_run, mdeploy, noop)
|
||||
|
||||
@mock.patch('fuelclient.objects.task.DeployTask.init_with_data')
|
||||
def test_redeploy_changes_noop_dry_run(self, task_data):
|
||||
cmd = ['fuel', 'redeploy-changes', '--env', '1']
|
||||
cmd.append('--dry-run')
|
||||
cmd.append('--noop')
|
||||
self.assertRaises(SystemExit, self.execute, cmd)
|
||||
|
||||
|
||||
class TestEnvironmentOstf(base.UnitTestCase):
|
||||
|
||||
|
|
|
@ -89,18 +89,120 @@ class TestEnvCommand(test_engine.BaseCLITest):
|
|||
self.assertIn('--force', m_stdout.getvalue())
|
||||
|
||||
def test_env_deploy(self):
|
||||
args = 'env deploy 42'
|
||||
dry_run = False
|
||||
noop = False
|
||||
args = 'env deploy'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('environment', mock.ANY)
|
||||
self.m_client.deploy_changes.assert_called_once_with(42)
|
||||
calls = list()
|
||||
calls.append(mock.call.deploy_changes(42,
|
||||
dry_run=dry_run,
|
||||
noop=noop))
|
||||
|
||||
self.m_get_client.assert_called_with('environment', mock.ANY)
|
||||
self.m_client.assert_has_calls(calls)
|
||||
|
||||
def test_env_deploy_dry_run(self):
|
||||
dry_run = True
|
||||
noop = False
|
||||
|
||||
args = 'env deploy -d'
|
||||
args += ' 42'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
calls = list()
|
||||
calls.append(mock.call.deploy_changes(42,
|
||||
dry_run=dry_run,
|
||||
noop=noop))
|
||||
|
||||
self.m_get_client.assert_called_with('environment', mock.ANY)
|
||||
self.m_client.assert_has_calls(calls)
|
||||
|
||||
def test_env_deploy_noop(self):
|
||||
dry_run = False
|
||||
noop = True
|
||||
args = 'env deploy -n'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
calls = list()
|
||||
calls.append(mock.call.deploy_changes(42,
|
||||
dry_run=dry_run,
|
||||
noop=noop))
|
||||
|
||||
self.m_get_client.assert_called_with('environment', mock.ANY)
|
||||
self.m_client.assert_has_calls(calls)
|
||||
|
||||
def test_env_deploy_noop_dry_run(self):
|
||||
args = 'env deploy -d -n'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.assertRaises(SystemExit, self.exec_command, args)
|
||||
|
||||
def test_env_redeploy(self):
|
||||
args = 'env redeploy 42'
|
||||
dry_run = False
|
||||
noop = False
|
||||
args = 'env redeploy'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('environment', mock.ANY)
|
||||
self.m_client.redeploy_changes.assert_called_once_with(42)
|
||||
calls = list()
|
||||
calls.append(mock.call.redeploy_changes(42,
|
||||
dry_run=dry_run,
|
||||
noop=noop))
|
||||
|
||||
self.m_get_client.assert_called_with('environment', mock.ANY)
|
||||
self.m_client.assert_has_calls(calls)
|
||||
|
||||
def test_env_redeploy_dry_run(self):
|
||||
dry_run = True
|
||||
noop = False
|
||||
args = 'env redeploy -d'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
calls = list()
|
||||
calls.append(mock.call.redeploy_changes(42,
|
||||
dry_run=dry_run,
|
||||
noop=noop))
|
||||
|
||||
self.m_get_client.assert_called_with('environment', mock.ANY)
|
||||
self.m_client.assert_has_calls(calls)
|
||||
|
||||
def test_env_redeploy_noop(self):
|
||||
dry_run = False
|
||||
noop = True
|
||||
args = 'env redeploy -n'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.exec_command(args)
|
||||
|
||||
calls = list()
|
||||
calls.append(mock.call.redeploy_changes(42,
|
||||
dry_run=dry_run,
|
||||
noop=noop))
|
||||
|
||||
self.m_get_client.assert_called_with('environment', mock.ANY)
|
||||
self.m_client.assert_has_calls(calls)
|
||||
|
||||
def test_env_redeploy_noop_dry_run(self):
|
||||
args = 'env redeploy -d -n'
|
||||
|
||||
args += ' 42'
|
||||
|
||||
self.assertRaises(SystemExit, self.exec_command, args)
|
||||
|
||||
def test_env_add_nodes(self):
|
||||
args = 'env add nodes -e 42 -n 24 25 -r compute cinder'
|
||||
|
|
|
@ -116,10 +116,100 @@ class TestEnvFacade(test_api.BaseLibTest):
|
|||
env_id = 42
|
||||
expected_uri = self.get_object_uri(self.res_uri, env_id, '/changes')
|
||||
matcher = self.m_request.put(expected_uri, json={})
|
||||
dry_run = False
|
||||
noop = False
|
||||
|
||||
self.client.deploy_changes(env_id)
|
||||
self.client.deploy_changes(env_id, dry_run=dry_run, noop=noop)
|
||||
self.check_deploy_redeploy_changes(dry_run, matcher, noop)
|
||||
|
||||
def check_deploy_redeploy_changes(self, dry_run, matcher, noop):
|
||||
self.assertTrue(matcher.called)
|
||||
self.assertEqual(matcher.last_request.qs['dry_run'][0],
|
||||
str(int(dry_run)))
|
||||
self.assertEqual(matcher.last_request.qs['noop'][0],
|
||||
str(int(noop)))
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_deploy_dry_run(self, m_init):
|
||||
env_id = 42
|
||||
expected_uri = self.get_object_uri(self.res_uri, env_id, '/changes')
|
||||
matcher = self.m_request.put(expected_uri, json={})
|
||||
|
||||
dry_run = True
|
||||
noop = False
|
||||
|
||||
self.client.deploy_changes(env_id, dry_run=dry_run, noop=noop)
|
||||
self.check_deploy_redeploy_changes(dry_run, matcher, noop)
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_deploy_noop(self, m_init):
|
||||
env_id = 42
|
||||
expected_uri = self.get_object_uri(self.res_uri, env_id, '/changes')
|
||||
matcher = self.m_request.put(expected_uri, json={})
|
||||
|
||||
dry_run = False
|
||||
noop = True
|
||||
|
||||
self.client.deploy_changes(env_id, dry_run=dry_run, noop=noop)
|
||||
self.check_deploy_redeploy_changes(dry_run, matcher, noop)
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_deploy_noop_dry_run(self, m_init):
|
||||
env_id = 42
|
||||
|
||||
dry_run = True
|
||||
noop = True
|
||||
|
||||
self.assertRaises(error.ActionException, self.client.deploy_changes,
|
||||
env_id, dry_run=dry_run, noop=noop)
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_redeploy(self, m_init):
|
||||
env_id = 42
|
||||
expected_uri = self.get_object_uri(self.res_uri, env_id,
|
||||
'/changes/redeploy')
|
||||
matcher = self.m_request.put(expected_uri, json={})
|
||||
dry_run = False
|
||||
noop = False
|
||||
|
||||
self.client.redeploy_changes(env_id, dry_run=dry_run, noop=noop)
|
||||
self.check_deploy_redeploy_changes(dry_run, matcher, noop)
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_redeploy_dry_run(self, m_init):
|
||||
env_id = 42
|
||||
expected_uri = self.get_object_uri(self.res_uri, env_id,
|
||||
'/changes/redeploy')
|
||||
matcher = self.m_request.put(expected_uri, json={})
|
||||
|
||||
dry_run = True
|
||||
noop = False
|
||||
|
||||
self.client.redeploy_changes(env_id, dry_run=dry_run, noop=noop)
|
||||
self.check_deploy_redeploy_changes(dry_run, matcher, noop)
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_redeploy_noop(self, m_init):
|
||||
env_id = 42
|
||||
expected_uri = self.get_object_uri(self.res_uri, env_id,
|
||||
'/changes/redeploy')
|
||||
matcher = self.m_request.put(expected_uri, json={})
|
||||
|
||||
dry_run = False
|
||||
noop = True
|
||||
|
||||
self.client.redeploy_changes(env_id, dry_run=dry_run, noop=noop)
|
||||
self.check_deploy_redeploy_changes(dry_run, matcher, noop)
|
||||
|
||||
@mock.patch.object(task_object.DeployTask, 'init_with_data')
|
||||
def test_env_redeploy_noop_dry_run(self, m_init):
|
||||
env_id = 42
|
||||
|
||||
dry_run = True
|
||||
noop = True
|
||||
|
||||
self.assertRaises(error.ActionException, self.client.redeploy_changes,
|
||||
env_id, dry_run=dry_run, noop=noop)
|
||||
|
||||
@mock.patch.object(base_object.BaseObject, 'init_with_data')
|
||||
def test_env_update(self, m_init):
|
||||
|
|
|
@ -65,16 +65,22 @@ class EnvironmentClient(base_v1.BaseV1Client):
|
|||
|
||||
env.assign(nodes, roles)
|
||||
|
||||
def deploy_changes(self, environment_id):
|
||||
def deploy_changes(self, environment_id, dry_run=False, noop=False):
|
||||
env = self._entity_wrapper(obj_id=environment_id)
|
||||
deploy_task = env.deploy_changes()
|
||||
|
||||
if dry_run and noop:
|
||||
raise error.ActionException("Dry run and noop actions are"
|
||||
"not allowed together")
|
||||
deploy_task = env.deploy_changes(dry_run=dry_run, noop=noop)
|
||||
return deploy_task.id
|
||||
|
||||
def redeploy_changes(self, environment_id):
|
||||
def redeploy_changes(self, environment_id, dry_run=False, noop=False):
|
||||
env = self._entity_wrapper(obj_id=environment_id)
|
||||
redeploy_task = env.redeploy_changes()
|
||||
|
||||
if dry_run and noop:
|
||||
raise error.ActionException("Dry run and noop actions are"
|
||||
"not allowed together")
|
||||
redeploy_task = env.redeploy_changes(dry_run=dry_run, noop=noop)
|
||||
return redeploy_task.id
|
||||
|
||||
def spawn_vms(self, environment_id):
|
||||
|
|
Loading…
Reference in New Issue