Add --force flag for `fuel deploy-changes` command
The flag allows to apply the changes to the cluster if the cluster is in the operational state. This allows you to deploy the changes without the reprovisioning procedure. Example: `fuel deploy-changes --env <env_id> --force` Partial-Bug: 1540558 Change-Id: Ibc89fdbfbd0a36a890412cd8e861d35bcf930690
This commit is contained in:
parent
b0cba9a677
commit
7e5607b376
|
@ -37,6 +37,7 @@ from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
|
|||
from nailgun.logger import logger
|
||||
from nailgun import objects
|
||||
|
||||
from nailgun.task.manager import ApplyChangesForceTaskManager
|
||||
from nailgun.task.manager import ApplyChangesTaskManager
|
||||
from nailgun.task.manager import ClusterDeletionManager
|
||||
from nailgun.task.manager import ResetEnvironmentTaskManager
|
||||
|
@ -87,6 +88,15 @@ class ClusterChangesHandler(DeferredTaskHandler):
|
|||
validator = ClusterChangesValidator
|
||||
|
||||
|
||||
class ClusterChangesForceRedeployHandler(DeferredTaskHandler):
|
||||
|
||||
log_message = u"Trying to force deployment of the environment '{env_id}'"
|
||||
log_error = u"Error during execution of a forced deployment task " \
|
||||
u"on environment '{env_id}': {error}"
|
||||
task_manager = ApplyChangesForceTaskManager
|
||||
validator = ClusterChangesValidator
|
||||
|
||||
|
||||
class ClusterStopDeploymentHandler(DeferredTaskHandler):
|
||||
|
||||
log_message = u"Trying to stop deployment on environment '{env_id}'"
|
||||
|
|
|
@ -26,6 +26,7 @@ from nailgun.api.v1.handlers.capacity import CapacityLogHandler
|
|||
|
||||
from nailgun.api.v1.handlers.cluster import ClusterAttributesDefaultsHandler
|
||||
from nailgun.api.v1.handlers.cluster import ClusterAttributesHandler
|
||||
from nailgun.api.v1.handlers.cluster import ClusterChangesForceRedeployHandler
|
||||
from nailgun.api.v1.handlers.cluster import ClusterChangesHandler
|
||||
from nailgun.api.v1.handlers.cluster import ClusterCollectionHandler
|
||||
from nailgun.api.v1.handlers.cluster import ClusterDeploymentTasksHandler
|
||||
|
@ -159,6 +160,8 @@ urls = (
|
|||
ClusterHandler,
|
||||
r'/clusters/(?P<cluster_id>\d+)/changes/?$',
|
||||
ClusterChangesHandler,
|
||||
r'/clusters/(?P<cluster_id>\d+)/changes/redeploy/?$',
|
||||
ClusterChangesForceRedeployHandler,
|
||||
r'/clusters/(?P<cluster_id>\d+)/attributes/?$',
|
||||
ClusterAttributesHandler,
|
||||
r'/clusters/(?P<cluster_id>\d+)/attributes/defaults/?$',
|
||||
|
|
|
@ -153,7 +153,7 @@ class TaskHelper(object):
|
|||
# TODO(aroma): considering moving this code to
|
||||
# nailgun Cluster object's methods
|
||||
@classmethod
|
||||
def nodes_to_deploy(cls, cluster):
|
||||
def nodes_to_deploy(cls, cluster, force=False):
|
||||
from nailgun import objects # preventing cycle import error
|
||||
|
||||
nodes_to_deploy = []
|
||||
|
@ -166,9 +166,9 @@ class TaskHelper(object):
|
|||
cluster_roles.update(node.roles)
|
||||
|
||||
for node in cluster.nodes:
|
||||
if any([node.pending_addition,
|
||||
node.needs_reprovision,
|
||||
node.needs_redeploy]):
|
||||
if force or any([node.pending_addition,
|
||||
node.needs_reprovision,
|
||||
node.needs_redeploy]):
|
||||
nodes_to_deploy.append(node)
|
||||
for role_name in node.pending_roles:
|
||||
update_required.update(
|
||||
|
|
|
@ -162,7 +162,8 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
db().delete(task)
|
||||
db().flush()
|
||||
|
||||
def execute(self, nodes_to_provision_deploy=None, deployment_tasks=None):
|
||||
def execute(self, nodes_to_provision_deploy=None, deployment_tasks=None,
|
||||
force=False):
|
||||
logger.info(
|
||||
u"Trying to start deployment at cluster '{0}'".format(
|
||||
self.cluster.name or self.cluster.id
|
||||
|
@ -178,7 +179,7 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
|
||||
nodes_to_delete = TaskHelper.nodes_to_delete(self.cluster)
|
||||
nodes_to_deploy = nodes_to_provision_deploy or \
|
||||
TaskHelper.nodes_to_deploy(self.cluster)
|
||||
TaskHelper.nodes_to_deploy(self.cluster, force)
|
||||
nodes_to_provision = TaskHelper.nodes_to_provision(self.cluster)
|
||||
|
||||
if not any([nodes_to_provision, nodes_to_deploy, nodes_to_delete]):
|
||||
|
@ -198,13 +199,14 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
self.cluster.id,
|
||||
supertask.id,
|
||||
nodes_to_provision_deploy=nodes_ids_to_deploy,
|
||||
deployment_tasks=deployment_tasks
|
||||
deployment_tasks=deployment_tasks,
|
||||
force=force
|
||||
)
|
||||
|
||||
return supertask
|
||||
|
||||
def _execute_async(self, supertask_id, deployment_tasks=None,
|
||||
nodes_to_provision_deploy=None):
|
||||
nodes_to_provision_deploy=None, force=False):
|
||||
"""Function for execute task in the mule
|
||||
|
||||
:param supertask_id: id of parent task
|
||||
|
@ -218,7 +220,8 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
self._execute_async_content(
|
||||
supertask,
|
||||
deployment_tasks=deployment_tasks,
|
||||
nodes_to_provision_deploy=nodes_to_provision_deploy)
|
||||
nodes_to_provision_deploy=nodes_to_provision_deploy,
|
||||
force=force)
|
||||
except Exception as e:
|
||||
logger.exception('Error occurred when running task')
|
||||
data = {
|
||||
|
@ -243,7 +246,7 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
return task_deletion
|
||||
|
||||
def _execute_async_content(self, supertask, deployment_tasks=None,
|
||||
nodes_to_provision_deploy=None):
|
||||
nodes_to_provision_deploy=None, force=False):
|
||||
"""Processes supertask async in mule
|
||||
|
||||
:param supertask: SqlAlchemy task object
|
||||
|
@ -260,7 +263,7 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
n.needs_reprovision]),
|
||||
nodes_to_deploy)
|
||||
else:
|
||||
nodes_to_deploy = TaskHelper.nodes_to_deploy(self.cluster)
|
||||
nodes_to_deploy = TaskHelper.nodes_to_deploy(self.cluster, force)
|
||||
nodes_to_provision = TaskHelper.nodes_to_provision(self.cluster)
|
||||
nodes_to_delete = TaskHelper.nodes_to_delete(self.cluster)
|
||||
|
||||
|
@ -543,6 +546,13 @@ class ApplyChangesTaskManager(TaskManager, DeploymentCheckMixin):
|
|||
db().flush()
|
||||
|
||||
|
||||
class ApplyChangesForceTaskManager(ApplyChangesTaskManager):
|
||||
|
||||
def execute(self, **kwargs):
|
||||
kwargs['force'] = True
|
||||
return super(ApplyChangesForceTaskManager, self).execute(**kwargs)
|
||||
|
||||
|
||||
class SpawnVMsTaskManager(ApplyChangesTaskManager):
|
||||
|
||||
deployment_type = consts.TASK_NAMES.spawn_vms
|
||||
|
|
|
@ -1824,3 +1824,36 @@ class TestHandlers(BaseIntegrationTest):
|
|||
|
||||
supertask = self.env.launch_deployment()
|
||||
self.env.wait_ready(supertask, timeout=60)
|
||||
|
||||
@fake_tasks()
|
||||
def test_force_redeploy_changes(self):
|
||||
self.env.create(
|
||||
nodes_kwargs=[{'name': '', 'pending_addition': True}]
|
||||
)
|
||||
|
||||
def _send_request(handler):
|
||||
return self.app.put(
|
||||
reverse(
|
||||
handler,
|
||||
kwargs={'cluster_id': self.env.clusters[0].id}
|
||||
),
|
||||
headers=self.default_headers,
|
||||
expect_errors=True
|
||||
)
|
||||
|
||||
# Initial deployment
|
||||
task = self.env.launch_deployment()
|
||||
self.env.wait_ready(task, timeout=60)
|
||||
|
||||
# Trying to redeploy on cluster in the operational state
|
||||
resp = _send_request('ClusterChangesHandler')
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
self.assertEqual(resp.json_body.get('message'), 'No changes to deploy')
|
||||
|
||||
# Trying to force redeploy on cluster in the operational state
|
||||
resp = _send_request('ClusterChangesForceRedeployHandler')
|
||||
self.assertEqual(resp.status_code, 202)
|
||||
self.assertEqual(resp.json_body.get('name'),
|
||||
consts.TASK_NAMES.deploy)
|
||||
self.assertEqual(resp.json_body.get('status'),
|
||||
consts.TASK_STATUSES.pending)
|
||||
|
|
|
@ -678,6 +678,22 @@ class TestTaskManagers(BaseIntegrationTest):
|
|||
manager_ = manager.ApplyChangesTaskManager(cluster_db.id)
|
||||
self.assertRaises(errors.WrongNodeStatus, manager_.execute)
|
||||
|
||||
@fake_tasks()
|
||||
def test_force_deploy_changes(self):
|
||||
self.env.create(
|
||||
nodes_kwargs=[
|
||||
{"status": NODE_STATUSES.ready}
|
||||
]
|
||||
)
|
||||
cluster_db = self.env.clusters[0]
|
||||
objects.Cluster.clear_pending_changes(cluster_db)
|
||||
manager_ = manager.ApplyChangesForceTaskManager(cluster_db.id)
|
||||
supertask = manager_.execute()
|
||||
self.assertEqual(supertask.name, TASK_NAMES.deploy)
|
||||
self.assertIn(supertask.status, (TASK_STATUSES.pending,
|
||||
TASK_STATUSES.running,
|
||||
TASK_STATUSES.ready))
|
||||
|
||||
@fake_tasks()
|
||||
@mock.patch('nailgun.task.manager.tasks.DeletionTask.execute')
|
||||
def test_apply_changes_exception_caught(self, mdeletion_execute):
|
||||
|
|
Loading…
Reference in New Issue