Add 'deployed_before' flag to cluster that forbids stop deployment
When cluster is successfuly deployed, that is, has 'operational' status,
'deployed_before' key is added to generated attributes of the cluster.
This flag then is used to determine whether stop action is allowed for
the cluster.
Conflicts:
nailgun/nailgun/objects/cluster.py
nailgun/nailgun/test/unit/test_objects.py
Change-Id: I8ecfca5819352ac27d7cec91e22f8006d8c3d8de
Closes-Bug: #1529691
(cherry picked from commit e969206448
)
This commit is contained in:
parent
9e2823cb44
commit
a961ebc251
|
@ -551,6 +551,7 @@ class DeferredTaskHandler(BaseHandler):
|
|||
errors.NoDeploymentTasks,
|
||||
errors.WrongNodeStatus,
|
||||
errors.UnavailableRelease,
|
||||
errors.CannotBeStopped,
|
||||
) as exc:
|
||||
raise self.http(400, exc.message)
|
||||
except Exception as exc:
|
||||
|
|
|
@ -33,6 +33,7 @@ from nailgun.api.v1.handlers.base import content
|
|||
|
||||
from nailgun.api.v1.validators.cluster import AttributesValidator
|
||||
from nailgun.api.v1.validators.cluster import ClusterChangesValidator
|
||||
from nailgun.api.v1.validators.cluster import ClusterStopDeploymentValidator
|
||||
from nailgun.api.v1.validators.cluster import ClusterValidator
|
||||
from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
|
||||
|
||||
|
@ -95,6 +96,7 @@ class ClusterStopDeploymentHandler(DeferredTaskHandler):
|
|||
log_error = u"Error during execution of deployment " \
|
||||
u"stopping task on environment '{env_id}': {error}"
|
||||
task_manager = StopDeploymentTaskManager
|
||||
validator = ClusterStopDeploymentValidator
|
||||
|
||||
|
||||
class ClusterResetHandler(DeferredTaskHandler):
|
||||
|
|
|
@ -238,6 +238,19 @@ class ClusterChangesValidator(BaseDefferedTaskValidator):
|
|||
ProvisionSelectedNodesValidator.validate_provision(None, cluster)
|
||||
|
||||
|
||||
class ClusterStopDeploymentValidator(BaseDefferedTaskValidator):
|
||||
|
||||
@classmethod
|
||||
def validate(cls, cluster):
|
||||
super(ClusterStopDeploymentValidator, cls).validate(cluster)
|
||||
|
||||
# FIXME(aroma): remove when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
if cluster.attributes.generated['deployed_before']['value']:
|
||||
raise errors.CannotBeStopped()
|
||||
|
||||
|
||||
class VmwareAttributesValidator(BasicValidator):
|
||||
|
||||
single_schema = cluster_schema.vmware_attributes_schema
|
||||
|
|
|
@ -41,6 +41,7 @@ default_messages = {
|
|||
"NoDeploymentTasks": "Deployment tasks not found for specific release in the database",
|
||||
"DeletionAlreadyStarted": "Environment removal already started",
|
||||
"StopAlreadyRunning": "Stopping deployment already initiated",
|
||||
"CannotBeStopped": "Stop action is forbidden for the cluster",
|
||||
"FailedProvisioning": "Failed to start provisioning",
|
||||
"WrongNodeStatus": "Wrong node status",
|
||||
"NodeOffline": "Node is offline",
|
||||
|
|
|
@ -907,6 +907,8 @@
|
|||
puppet:
|
||||
manifests: "rsync://{settings.MASTER_IP}:/puppet/{cluster.release.version}/manifests/"
|
||||
modules: "rsync://{settings.MASTER_IP}:/puppet/{cluster.release.version}/modules/"
|
||||
deployed_before:
|
||||
value: false
|
||||
wizard_metadata:
|
||||
Mode:
|
||||
metadata:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
Cluster-related objects and collections
|
||||
"""
|
||||
|
||||
import copy
|
||||
from sqlalchemy import or_
|
||||
import yaml
|
||||
|
||||
|
@ -856,6 +857,29 @@ class Cluster(NailgunObject):
|
|||
repos = instance.attributes.editable['repo_setup']['repos']['value']
|
||||
return tuple(set([r['uri'] for r in repos]))
|
||||
|
||||
# FIXME(aroma): remove updating of 'deployed_before'
|
||||
# when stop action is reworked. 'deployed_before'
|
||||
# flag identifies whether stop action is allowed for the
|
||||
# cluster. Please, refer to [1] for more details.
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
@classmethod
|
||||
def set_deployed_before_flag(cls, instance, value):
|
||||
"""Change value for before_deployed if needed
|
||||
|
||||
:param instance: nailgun.db.sqlalchemy.models.Cluster instance
|
||||
:param value: new value for flag
|
||||
:type value: bool
|
||||
"""
|
||||
if instance.attributes.generated['deployed_before']['value'] != value:
|
||||
# TODO(aroma): remove unnecessary copying when enhancement
|
||||
# of Mutable types will be introduced for corresponding
|
||||
# fields of ORM models
|
||||
generated_attrs = copy.deepcopy(instance.attributes.generated)
|
||||
generated_attrs['deployed_before']['value'] = value
|
||||
instance.attributes.generated = generated_attrs
|
||||
|
||||
db.flush()
|
||||
|
||||
|
||||
class ClusterCollection(NailgunCollection):
|
||||
"""Cluster collection
|
||||
|
|
|
@ -183,7 +183,18 @@ class Task(NailgunObject):
|
|||
logger.debug(
|
||||
"Updating cluster (%s) status: from %s to %s",
|
||||
cluster.full_name, cluster.status, status)
|
||||
Cluster.update(cluster, data={'status': status})
|
||||
|
||||
data = {'status': status}
|
||||
|
||||
# FIXME(aroma): remove updating of 'deployed_before'
|
||||
# when stop action is reworked. 'deployed_before'
|
||||
# flag identifies whether stop action is allowed for the
|
||||
# cluster. Please, refer to [1] for more details.
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
if status == consts.CLUSTER_STATUSES.operational:
|
||||
Cluster.set_deployed_before_flag(cluster, value=True)
|
||||
|
||||
Cluster.update(cluster, data)
|
||||
|
||||
@classmethod
|
||||
def _update_cluster_data(cls, instance):
|
||||
|
@ -191,7 +202,7 @@ class Task(NailgunObject):
|
|||
|
||||
if instance.name == 'deploy':
|
||||
if instance.status == 'ready':
|
||||
# If for some reasosns orchestrator
|
||||
# If for some reasons orchestrator
|
||||
# didn't send ready status for node
|
||||
# we should set it explicitly
|
||||
for n in cluster.nodes:
|
||||
|
|
|
@ -627,6 +627,14 @@ class StopDeploymentTaskManager(TaskManager):
|
|||
class ResetEnvironmentTaskManager(TaskManager):
|
||||
|
||||
def execute(self):
|
||||
|
||||
# FIXME(aroma): remove updating of 'deployed_before'
|
||||
# when stop action is reworked. 'deployed_before'
|
||||
# flag identifies whether stop action is allowed for the
|
||||
# cluster. Please, refer to [1] for more details.
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
objects.Cluster.set_deployed_before_flag(self.cluster, value=False)
|
||||
|
||||
deploy_running = db().query(Task).filter_by(
|
||||
cluster=self.cluster,
|
||||
name=consts.TASK_NAMES.deploy,
|
||||
|
|
|
@ -58,6 +58,12 @@ class TestResetEnvironment(BaseIntegrationTest):
|
|||
|
||||
self.assertEqual(cluster_db.status, "new")
|
||||
|
||||
# FIXME(aroma): remove when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
self.assertFalse(
|
||||
cluster_db.attributes.generated['deployed_before']['value'])
|
||||
|
||||
for n in cluster_db.nodes:
|
||||
self.assertEqual(n.online, False)
|
||||
self.assertEqual(n.status, "discover")
|
||||
|
|
|
@ -25,6 +25,7 @@ from nailgun.db.sqlalchemy.models.task import Task
|
|||
|
||||
from nailgun.test.base import BaseIntegrationTest
|
||||
from nailgun.test.base import fake_tasks
|
||||
from nailgun.test.base import reverse
|
||||
|
||||
|
||||
class TestStopDeployment(BaseIntegrationTest):
|
||||
|
@ -78,6 +79,42 @@ class TestStopDeployment(BaseIntegrationTest):
|
|||
notification.message,
|
||||
'Please reset the environment if you want to redeploy it.')
|
||||
|
||||
# FIXME(aroma): remove when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
@fake_tasks(tick_interval=1)
|
||||
def test_stop_deployment_fail_if_deployed_before(self):
|
||||
deploy_task = self.env.launch_deployment()
|
||||
self.env.wait_ready(deploy_task)
|
||||
|
||||
# changes to deploy
|
||||
self.env.create_node(
|
||||
cluster_id=self.cluster.id,
|
||||
roles=["controller"],
|
||||
pending_addition=True
|
||||
)
|
||||
|
||||
redeploy_task = self.env.launch_deployment()
|
||||
self.env.wait_ready(redeploy_task)
|
||||
|
||||
# stop task will not be created as in this situation
|
||||
# the error will be raised by validator thus we cannot use
|
||||
# self.env.stop_deployment to check the result
|
||||
resp = self.app.put(
|
||||
reverse(
|
||||
'ClusterStopDeploymentHandler',
|
||||
kwargs={'cluster_id': self.cluster.id}),
|
||||
expect_errors=True,
|
||||
headers=self.default_headers
|
||||
)
|
||||
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
self.assertEqual(resp.json_body['message'],
|
||||
'Stop action is forbidden for the cluster')
|
||||
|
||||
# wait that redeployment end successfully
|
||||
self.env.wait_ready(redeploy_task)
|
||||
|
||||
@fake_tasks(fake_rpc=False, mock_rpc=False)
|
||||
@patch('nailgun.rpc.cast')
|
||||
def test_admin_ip_in_args(self, mocked_rpc):
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from mock import patch
|
||||
|
||||
from nailgun.test.base import BaseIntegrationTest
|
||||
|
@ -158,6 +157,13 @@ class TestTasksLogging(BaseIntegrationTest):
|
|||
]
|
||||
)
|
||||
self.env.launch_deployment()
|
||||
|
||||
# FIXME(aroma): remove when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
cluster = self.env.clusters[0]
|
||||
objects.Cluster.set_deployed_before_flag(cluster, value=False)
|
||||
|
||||
self.env.stop_deployment()
|
||||
|
||||
self.assertGreaterEqual(len(logger.call_args_list), 1)
|
||||
|
@ -279,6 +285,12 @@ class TestTasksLogging(BaseIntegrationTest):
|
|||
deploy_uuid = deploy.uuid
|
||||
self.simulate_running_deployment(deploy)
|
||||
|
||||
# FIXME(aroma): remove when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
cluster = self.env.clusters[0]
|
||||
objects.Cluster.set_deployed_before_flag(cluster, value=False)
|
||||
|
||||
# Stopping deployment
|
||||
self.env.stop_deployment()
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ from six.moves import range
|
|||
import unittest2
|
||||
|
||||
from nailgun import consts
|
||||
from nailgun import objects
|
||||
from nailgun.test.base import BaseIntegrationTest
|
||||
from nailgun.test.base import fake_tasks
|
||||
from nailgun.utils import reverse
|
||||
|
@ -523,6 +524,12 @@ class TestVerifyNeutronVlan(BaseIntegrationTest):
|
|||
def test_verify_networks_after_stop(self):
|
||||
self.cluster = self.env.clusters[0]
|
||||
self.env.launch_deployment()
|
||||
|
||||
# FIXME(aroma): remove when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
objects.Cluster.set_deployed_before_flag(self.cluster, value=False)
|
||||
|
||||
stop_task = self.env.stop_deployment()
|
||||
self.env.wait_ready(stop_task, 60)
|
||||
self.assertEqual(self.cluster.status, consts.CLUSTER_STATUSES.stopped)
|
||||
|
|
|
@ -17,9 +17,11 @@ from mock import Mock
|
|||
from mock import patch
|
||||
from oslo.serialization import jsonutils
|
||||
|
||||
from nailgun.api.v1.validators.cluster import ClusterStopDeploymentValidator
|
||||
from nailgun.api.v1.validators.cluster import ClusterValidator
|
||||
from nailgun import consts
|
||||
from nailgun.errors import errors
|
||||
from nailgun import objects
|
||||
from nailgun.test.base import BaseTestCase
|
||||
|
||||
|
||||
|
@ -206,3 +208,20 @@ class TestClusterValidator(BaseTestCase):
|
|||
ClusterValidator.validate_update,
|
||||
self.cluster_data,
|
||||
cluster_mock)
|
||||
|
||||
|
||||
class TestClusterStopDeploymentValidator(BaseTestCase):
|
||||
|
||||
# FIXME(aroma): remove this test when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
def test_stop_deployment_failed_for_once_deployed_cluster(self):
|
||||
cluster = self.env.create_cluster(api=False)
|
||||
|
||||
objects.Cluster.set_deployed_before_flag(cluster, value=True)
|
||||
|
||||
self.assertRaises(
|
||||
errors.CannotBeStopped,
|
||||
ClusterStopDeploymentValidator.validate,
|
||||
cluster
|
||||
)
|
||||
|
|
|
@ -18,6 +18,7 @@ import copy
|
|||
import datetime
|
||||
import hashlib
|
||||
import jsonschema
|
||||
import mock
|
||||
import six
|
||||
import uuid
|
||||
|
||||
|
@ -508,7 +509,10 @@ class TestTaskObject(BaseIntegrationTest):
|
|||
objects.Task._update_cluster_data(task)
|
||||
self.db.flush()
|
||||
|
||||
self.assertEquals(self.cluster.status, 'operational')
|
||||
self.assertEqual(self.cluster.status,
|
||||
consts.CLUSTER_STATUSES.operational)
|
||||
self.assertTrue(
|
||||
self.cluster.attributes.generated['deployed_before']['value'])
|
||||
|
||||
def test_update_if_parent_task_is_ready_all_nodes_should_be_ready(self):
|
||||
for node in self.cluster.nodes:
|
||||
|
@ -716,6 +720,34 @@ class TestClusterObject(BaseTestCase):
|
|||
{'roles': ['compute']},
|
||||
{'roles': ['cinder']}])
|
||||
|
||||
# FIXME(aroma): remove this test when stop action will be reworked for ha
|
||||
# cluster. To get more details, please, refer to [1]
|
||||
# [1]: https://bugs.launchpad.net/fuel/+bug/1529691
|
||||
def test_set_deployed_before_flag(self):
|
||||
self.cluster = self.env.clusters[0]
|
||||
self.assertFalse(
|
||||
self.cluster.attributes.generated['deployed_before']['value'])
|
||||
|
||||
# check that the flags is set to true if was false
|
||||
objects.Cluster.set_deployed_before_flag(self.cluster, value=True)
|
||||
self.assertTrue(
|
||||
self.cluster.attributes.generated['deployed_before']['value'])
|
||||
|
||||
# check that flag is set to false if was true
|
||||
objects.Cluster.set_deployed_before_flag(self.cluster, value=False)
|
||||
self.assertFalse(
|
||||
self.cluster.attributes.generated['deployed_before']['value'])
|
||||
|
||||
# check that flag is not changed when same value is given
|
||||
# and interaction w/ db is not performed
|
||||
with mock.patch.object(self.db, 'flush') as m_flush:
|
||||
objects.Cluster.set_deployed_before_flag(self.cluster,
|
||||
value=False)
|
||||
self.assertFalse(
|
||||
self.cluster.attributes.generated['deployed_before']['value'])
|
||||
|
||||
m_flush.assert_not_called()
|
||||
|
||||
def test_all_controllers(self):
|
||||
self.assertEqual(len(objects.Cluster.get_nodes_by_role(
|
||||
self.env.clusters[0], 'controller')), 2)
|
||||
|
|
Loading…
Reference in New Issue