Add field to release for storing valid deploy mode
Field is called `modes`. Cluster validation stops creating the environment with mode that is not in the `modes` field of cluster release. One cluster validation test seemed to have reversed logic (test_release_non_exists_validation). It is fixed now. Change-Id: Iafeb988a91f44e29ea0491422b8348997d950bc4 Closes-Bug: #1456540
This commit is contained in:
parent
1d59c270f5
commit
9e3f07bd92
|
@ -49,12 +49,21 @@ class ClusterValidator(BasicValidator):
|
|||
@classmethod
|
||||
def _validate_common(cls, data, instance=None):
|
||||
d = cls.validate_json(data)
|
||||
|
||||
release_id = d.get("release", d.get("release_id"))
|
||||
if release_id:
|
||||
if not objects.Release.get_by_uid(release_id):
|
||||
release = objects.Release.get_by_uid(release_id)
|
||||
if not release:
|
||||
raise errors.InvalidData(
|
||||
"Invalid release ID", log_message=True)
|
||||
mode = d.get('mode')
|
||||
if mode and mode not in release.modes:
|
||||
raise errors.InvalidData(
|
||||
"Cannot deploy in {0} mode in current release."
|
||||
" Need to be one of {1}".format(
|
||||
mode, release.modes),
|
||||
log_message=True
|
||||
)
|
||||
|
||||
pend_release_id = d.get("pending_release_id")
|
||||
if pend_release_id:
|
||||
pend_release = objects.Release.get_by_uid(pend_release_id,
|
||||
|
@ -75,6 +84,7 @@ class ClusterValidator(BasicValidator):
|
|||
"it cannot update current release",
|
||||
log_message=True
|
||||
)
|
||||
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -178,6 +178,9 @@ def upgrade_schema():
|
|||
op.add_column(
|
||||
'releases',
|
||||
sa.Column('vmware_attributes_metadata', fields.JSON(), nullable=True))
|
||||
op.add_column(
|
||||
'releases',
|
||||
sa.Column('modes', fields.JSON(), nullable=True))
|
||||
op.create_table(
|
||||
'vmware_attributes',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
|
@ -405,6 +408,7 @@ def downgrade_schema():
|
|||
op.drop_column('node_nic_interfaces', 'driver')
|
||||
op.drop_column('node_nic_interfaces', 'bus_info')
|
||||
op.drop_column('releases', 'deployment_tasks')
|
||||
op.drop_column('releases', 'modes')
|
||||
op.drop_constraint('node_roles_node_fkey', 'node_roles')
|
||||
op.create_foreign_key(
|
||||
'node_roles_node_fkey', 'node_roles', 'nodes', ['node'], ['id'])
|
||||
|
@ -462,6 +466,11 @@ def upgrade_data():
|
|||
networks=jsonutils.dumps(networks_meta),
|
||||
)
|
||||
|
||||
update_modes = text(
|
||||
'UPDATE releases SET modes = :modes')
|
||||
connection.execute(update_modes, modes=jsonutils.dumps(
|
||||
['ha_compact', 'multinode']))
|
||||
|
||||
upgrade_master_node_settings(connection)
|
||||
upgrade_6_0_to_6_1_plugins_cluster_attrs_use_ids_mapping(connection)
|
||||
upgrade_ubuntu_cobbler_profile_6_0_to_6_1(connection)
|
||||
|
|
|
@ -61,6 +61,7 @@ class Release(Base):
|
|||
is_deployable = Column(Boolean, default=True, nullable=False)
|
||||
deployment_tasks = Column(JSON, default=[])
|
||||
vmware_attributes_metadata = Column(JSON, default=[])
|
||||
modes = Column(JSON, default=[])
|
||||
|
||||
role_list = relationship(
|
||||
"Role",
|
||||
|
|
|
@ -1165,6 +1165,7 @@
|
|||
vcenter_password: ""
|
||||
datacenter: ""
|
||||
datastore: ""
|
||||
modes: ['ha_compact']
|
||||
- pk: 1
|
||||
extend: *base_release
|
||||
fields:
|
||||
|
|
|
@ -72,7 +72,8 @@ class Release(NailgunObject):
|
|||
"roles": {"type": "array"},
|
||||
"clusters": {"type": "array"},
|
||||
"is_deployable": {"type": "boolean"},
|
||||
"vmware_attributes_metadata": {"type": "object"}
|
||||
"vmware_attributes_metadata": {"type": "object"},
|
||||
"modes": {"type": "array"}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ class EnvironmentManager(object):
|
|||
'version': version,
|
||||
'description': u"release_desc" + version,
|
||||
'roles': self.get_default_roles(),
|
||||
'modes': ['ha_compact', 'multinode'],
|
||||
})
|
||||
|
||||
if kwargs.get('deployment_tasks') is None:
|
||||
|
|
|
@ -99,7 +99,7 @@ class TestInstallationInfo(BaseTestCase):
|
|||
self.env.create(
|
||||
cluster_kwargs={
|
||||
'release_id': release[0].id,
|
||||
'mode': consts.CLUSTER_MODES.ha_full,
|
||||
'mode': consts.CLUSTER_MODES.ha_compact,
|
||||
'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network},
|
||||
nodes_kwargs=nodes_params
|
||||
)
|
||||
|
@ -121,7 +121,7 @@ class TestInstallationInfo(BaseTestCase):
|
|||
self.env.create(
|
||||
cluster_kwargs={
|
||||
'release_id': release[0].id,
|
||||
'mode': consts.CLUSTER_MODES.ha_full,
|
||||
'mode': consts.CLUSTER_MODES.ha_compact,
|
||||
'net_provider': consts.CLUSTER_NET_PROVIDERS.nova_network},
|
||||
nodes_kwargs=nodes_params
|
||||
)
|
||||
|
@ -134,7 +134,7 @@ class TestInstallationInfo(BaseTestCase):
|
|||
self.assertEquals(len(nodes_params), len(cluster_info['nodes']))
|
||||
self.assertEquals(len(nodes_params), cluster_info['nodes_num'])
|
||||
|
||||
self.assertEquals(consts.CLUSTER_MODES.ha_full,
|
||||
self.assertEquals(consts.CLUSTER_MODES.ha_compact,
|
||||
cluster_info['mode'])
|
||||
self.assertEquals(consts.CLUSTER_NET_PROVIDERS.nova_network,
|
||||
cluster_info['net_provider'])
|
||||
|
@ -173,7 +173,7 @@ class TestInstallationInfo(BaseTestCase):
|
|||
# Checking nova network configuration
|
||||
nova = consts.CLUSTER_NET_PROVIDERS.nova_network
|
||||
self.env.create(cluster_kwargs={
|
||||
'mode': consts.CLUSTER_MODES.ha_full,
|
||||
'mode': consts.CLUSTER_MODES.ha_compact,
|
||||
'net_provider': nova
|
||||
})
|
||||
clusters_info = info.get_clusters_info()
|
||||
|
@ -188,7 +188,7 @@ class TestInstallationInfo(BaseTestCase):
|
|||
# Checking neutron network configuration
|
||||
neutron = consts.CLUSTER_NET_PROVIDERS.neutron
|
||||
self.env.create(cluster_kwargs={
|
||||
'mode': consts.CLUSTER_MODES.ha_full,
|
||||
'mode': consts.CLUSTER_MODES.ha_compact,
|
||||
'net_provider': neutron
|
||||
})
|
||||
clusters_info = info.get_clusters_info()
|
||||
|
|
|
@ -13,66 +13,60 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from contextlib import nested
|
||||
|
||||
from mock import Mock
|
||||
from mock import patch
|
||||
from oslo.serialization import jsonutils
|
||||
|
||||
from nailgun.api.v1.validators.cluster import ClusterValidator
|
||||
from nailgun import consts
|
||||
from nailgun.errors import errors
|
||||
from nailgun.test.base import BaseTestCase
|
||||
|
||||
|
||||
class TestClusterValidator(BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestClusterValidator, self).setUp()
|
||||
self.cluster_data = '{"name": "test", "release": 1}'
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestClusterValidator, cls).setUpClass()
|
||||
cls.cluster_data = jsonutils.dumps({
|
||||
"name": "test",
|
||||
"release": 1,
|
||||
"mode": consts.CLUSTER_MODES.ha_compact})
|
||||
|
||||
def test_cluster_exists_validation(self):
|
||||
with nested(
|
||||
patch('nailgun.api.v1.validators.cluster.objects.'
|
||||
'ClusterCollection'),
|
||||
patch('nailgun.api.v1.validators.cluster.objects.Release')
|
||||
) as (cc, r):
|
||||
r.get_by_uid.return_value = 'release'
|
||||
cc.filter_by.return_value.first.return_value = 'cluster'
|
||||
self.assertRaises(errors.AlreadyExists,
|
||||
ClusterValidator.validate, self.cluster_data)
|
||||
@patch('nailgun.api.v1.validators.cluster.objects'
|
||||
'.ClusterCollection.filter_by')
|
||||
@patch('nailgun.api.v1.validators.cluster.objects.Release.get_by_uid')
|
||||
def test_cluster_exists_validation(self, release_get_by_uid, cc_filter_by):
|
||||
release_get_by_uid.return_value = Mock(modes=['ha_compact'])
|
||||
cc_filter_by.return_value.first.return_value = 'cluster'
|
||||
self.assertRaises(errors.AlreadyExists,
|
||||
ClusterValidator.validate, self.cluster_data)
|
||||
|
||||
def test_cluster_non_exists_validation(self):
|
||||
with nested(
|
||||
patch(
|
||||
'nailgun.api.v1.validators.cluster.objects.ClusterCollection',
|
||||
Mock()
|
||||
),
|
||||
patch('nailgun.api.v1.validators.cluster.objects.Release', Mock())
|
||||
) as (cc, r):
|
||||
try:
|
||||
cc.filter_by.return_value.first.return_value = None
|
||||
r.get_by_uuid.return_value = 'release'
|
||||
ClusterValidator.validate(self.cluster_data)
|
||||
except errors.AlreadyExists as e:
|
||||
self.fail(
|
||||
'Cluster exists validation failed: {0}'.format(e)
|
||||
)
|
||||
@patch('nailgun.api.v1.validators.cluster.objects'
|
||||
'.ClusterCollection.filter_by')
|
||||
@patch('nailgun.api.v1.validators.cluster.objects.Release.get_by_uid')
|
||||
def test_cluster_does_not_exist_validation(self, release_get_by_uid,
|
||||
cc_filter_by):
|
||||
try:
|
||||
cc_filter_by.return_value.first.return_value = None
|
||||
release_get_by_uid.return_value = Mock(modes=['ha_compact'])
|
||||
ClusterValidator.validate(self.cluster_data)
|
||||
except errors.AlreadyExists as e:
|
||||
self.fail(
|
||||
'Cluster exists validation failed: {0}'.format(e)
|
||||
)
|
||||
|
||||
def test_release_exists_validation(self):
|
||||
with patch(
|
||||
'nailgun.api.v1.validators.cluster.objects.ClusterCollection',
|
||||
Mock()
|
||||
) as cc:
|
||||
cc.filter_by.return_value.first.return_value = None
|
||||
self.assertRaises(errors.InvalidData,
|
||||
ClusterValidator.validate, self.cluster_data)
|
||||
@patch('nailgun.api.v1.validators.cluster.objects'
|
||||
'.ClusterCollection.filter_by')
|
||||
def test_release_exists_validation(self, cc_filter_by):
|
||||
cc_filter_by.return_value.first.return_value = None
|
||||
self.assertRaises(errors.InvalidData,
|
||||
ClusterValidator.validate, self.cluster_data)
|
||||
|
||||
def test_release_non_exists_validation(self):
|
||||
with patch('nailgun.api.v1.validators.cluster.objects.Release',
|
||||
Mock()) as r:
|
||||
try:
|
||||
r.get_by_uuid.return_value = None
|
||||
ClusterValidator.validate(self.cluster_data)
|
||||
except errors.InvalidData as e:
|
||||
self.fail('Release exists validation failed: {0}'.format(e))
|
||||
@patch('nailgun.api.v1.validators.cluster.objects.Release.get_by_uid')
|
||||
def test_release_non_exists_validation(self, release_get_by_uid):
|
||||
release_get_by_uid.return_value = None
|
||||
self.assertRaises(errors.InvalidData,
|
||||
ClusterValidator.validate, self.cluster_data)
|
||||
|
||||
def test_pending_release_validation_success(self):
|
||||
curr_release = Mock(
|
||||
|
@ -154,3 +148,27 @@ class TestClusterValidator(BaseTestCase):
|
|||
pend_release, curr_release
|
||||
)
|
||||
)
|
||||
|
||||
@patch('nailgun.api.v1.validators.cluster.objects'
|
||||
'.ClusterCollection.filter_by')
|
||||
@patch('nailgun.api.v1.validators.cluster.objects.Release.get_by_uid')
|
||||
def test_mode_check_passes(self, release_get_by_uid, cc_filter_by):
|
||||
release_get_by_uid.return_value = Mock(modes=['ha_compact'])
|
||||
|
||||
cc_filter_by.return_value.first.return_value = None
|
||||
try:
|
||||
ClusterValidator.validate(self.cluster_data)
|
||||
except errors.InvalidData as e:
|
||||
self.fail('test_mode_check failed: {0}'.format(e))
|
||||
|
||||
@patch('nailgun.api.v1.validators.cluster.objects'
|
||||
'.ClusterCollection.filter_by')
|
||||
@patch('nailgun.api.v1.validators.cluster.objects.Release.get_by_uid')
|
||||
def test_mode_check_fails(self, release_get_by_uid, cc_filter_by):
|
||||
release_get_by_uid.return_value = Mock(modes=['trolomod', 'multinode'])
|
||||
|
||||
cc_filter_by.return_value.first.return_value = None
|
||||
self.assertRaisesRegexp(errors.InvalidData,
|
||||
"Cannot deploy in .* mode in current release",
|
||||
ClusterValidator.validate,
|
||||
self.cluster_data)
|
||||
|
|
|
@ -330,3 +330,14 @@ class TestOldReleasesAreNotDeployable(base.BaseAlembicMigrationTest):
|
|||
|
||||
for row in result:
|
||||
self.assertFalse(row['is_deployable'])
|
||||
|
||||
|
||||
class TestAddingModesToReleases(base.BaseAlembicMigrationTest):
|
||||
def test_release_modes_are_added(self):
|
||||
result = db.execute(
|
||||
sa.select([self.meta.tables['releases'].c.modes]))
|
||||
|
||||
for row in result:
|
||||
self.assertItemsEqual(
|
||||
jsonutils.loads(row['modes']),
|
||||
['ha_compact', 'multinode'])
|
||||
|
|
Loading…
Reference in New Issue