Replace release.is_deployable with release.state

is_deployable doesn't really give any additional information for a
release, it is removed. To make change API-backward-compatible, it is
retained as a property dependent on release.state.

New state is added - manageonly, for environments that are not able to
be deployed, but can still be managed.

Change-Id: I518a0114730a2f227c9ef035a376f9a90d3d5bbd
Closes-bug: #1503303
DocImpact
This commit is contained in:
Maciej Kwiek 2015-10-20 11:40:25 +02:00
parent 24b00023b4
commit 3d42dae017
18 changed files with 99 additions and 25 deletions

1
.gitignore vendored
View File

@ -23,6 +23,7 @@ lock
node_modules
nailgun/static/vendor/npm/*
nailgun/built-static/
*.egg
.testrepository

View File

@ -28,7 +28,6 @@ def make_release(**overrides):
'name': 'Kilo on Ubuntu 14.04.1',
'operating_system': 'Ubuntu',
'version': '2015.1.0-7.0',
'is_deployable': True,
'state': 'available',
'attributes_metadata': {},
'can_update_from_versions': [],

View File

@ -124,7 +124,7 @@ class OpenStackUpgrader(UpgradeEngine):
self._rollback_ids['release'].append(response['id'])
self.upload_release_deployment_tasks(response)
if not release.get('is_deployable', True):
if not release.get('state', 'available') == 'available':
continue
# add notification abot successfull releases

View File

@ -205,7 +205,7 @@ class TestOpenStackUpgrader(BaseTestCase):
"name": "Undeployable releases name",
"version": "2014.1",
"operating_system": "CentOS",
"is_deployable": False,
"state": "unavailable",
}
}
]

View File

@ -26,6 +26,7 @@ def Enum(*values, **kwargs):
RELEASE_STATES = Enum(
'available',
'unavailable',
'manageonly'
)
RELEASE_OS = Enum(

View File

@ -30,20 +30,50 @@ from sqlalchemy.dialects import postgresql as psql
from nailgun.utils.migration import drop_enum
from nailgun.utils.migration import upgrade_enum
release_states_old = (
'available',
'unavailable',
)
release_states_new = (
'available',
'unavailable',
'manageonly',
)
def upgrade():
create_components_table()
create_release_components_table()
upgrade_nodegroups_name_cluster_constraint()
upgrade_release_state()
def downgrade():
downgrade_release_state()
op.drop_constraint('_name_cluster_uc', 'nodegroups',)
op.drop_table('release_components')
op.drop_table('components')
drop_enum('component_types')
def upgrade_release_state():
connection = op.get_bind()
op.drop_column('releases', 'is_deployable')
upgrade_enum(
'releases',
'state',
'release_state',
release_states_old,
release_states_new,
)
connection.execute(sa.sql.text(
"UPDATE releases SET state='manageonly' WHERE state!='unavailable'"))
def upgrade_nodegroups_name_cluster_constraint():
connection = op.get_bind()
select_query = sa.sql.text(
@ -104,3 +134,27 @@ def create_release_components_table():
['release_id'], ['releases.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
def downgrade_release_state():
connection = op.get_bind()
connection.execute(sa.sql.text(
"UPDATE releases SET state='available' WHERE state!='unavailable'"))
op.add_column(
'releases',
sa.Column(
'is_deployable',
sa.Boolean(),
nullable=False,
server_default='true',
)
)
upgrade_enum(
'releases',
'state',
'release_state',
release_states_new,
release_states_old,
)

View File

@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import Enum
from sqlalchemy import Integer
@ -57,7 +56,6 @@ class Release(Base):
roles_metadata = Column(JSON, default={})
network_roles_metadata = Column(JSON, default=[], server_default='[]')
wizard_metadata = Column(JSON, default={})
is_deployable = Column(Boolean, default=True, nullable=False)
deployment_tasks = Column(JSON, default=[])
vmware_attributes_metadata = Column(JSON, default=[])
modes = Column(JSON, default=[])

View File

@ -95,7 +95,7 @@ class NailgunReleaseAdapter(object):
@property
def is_deployable(self):
return self.release.is_deployable
return objects.Release.is_deployable(self.release)
@property
def environment_version(self):

View File

@ -29,7 +29,7 @@ class BaseCloneClusterTest(nailgun_test_base.BaseIntegrationTest):
self.release_61 = self.env.create_release(
operating_system=consts.RELEASE_OS.ubuntu,
version="2014.2.2-6.1",
is_deployable=False,
state=consts.RELEASE_STATES.manageonly
)
self.release_70 = self.env.create_release(
operating_system=consts.RELEASE_OS.ubuntu,

View File

@ -20,6 +20,7 @@ from oslo_serialization import jsonutils
from nailgun import consts
from nailgun.errors import errors
from nailgun.settings import settings
from nailgun.test import base
from .. import validators
@ -35,11 +36,12 @@ class TestClusterUpgradeValidator(tests_base.BaseCloneClusterTest):
self.validator.validate_release_upgrade(self.release_61,
self.release_70)
@mock.patch.dict(settings.VERSION, {'feature_groups': ['mirantis']})
def test_validate_release_upgrade_deprecated_release(self):
release_511 = self.env.create_release(
operating_system=consts.RELEASE_OS.ubuntu,
version="2014.1.3-5.1.1",
is_deployable=False,
state=consts.RELEASE_STATES.manageonly
)
msg = "^Upgrade to the given release \({0}\).*is deprecated and " \
"cannot be installed\.$".format(self.release_61.id)
@ -48,7 +50,7 @@ class TestClusterUpgradeValidator(tests_base.BaseCloneClusterTest):
self.release_61)
def test_validate_release_upgrade_to_older_release(self):
self.release_61.is_deployable = True
self.release_61.state = consts.RELEASE_STATES.available
msg = "^Upgrade to the given release \({0}\).*release is equal or " \
"lower than the release of the original cluster\.$" \
.format(self.release_61.id)

View File

@ -49,7 +49,7 @@ class ClusterUpgradeValidator(base.BasicValidator):
@classmethod
def validate_release_upgrade(cls, orig_release, new_release):
if not new_release.is_deployable:
if not objects.Release.is_deployable(new_release):
raise errors.InvalidData(
"Upgrade to the given release ({0}) is not possible because "
"this release is deprecated and cannot be installed."

View File

@ -1524,7 +1524,6 @@
name: "Kilo on CentOS 6.5"
state: "unavailable"
version: "2015.1.0-8.0"
is_deployable: false
can_update_from_versions: []
operating_system: "CentOS"
description: "This option will install the OpenStack Kilo packages using a CentOS based operating system. With high availability features built in, you are getting a robust, enterprise-grade OpenStack deployment."

View File

@ -111,7 +111,8 @@ class Release(NailgunObject):
# in experimental mode we deploy all releases
if 'experimental' in settings.VERSION['feature_groups']:
return True
return instance.is_deployable
return instance.state == consts.RELEASE_STATES.available
@classmethod
def is_granular_enabled(cls, instance):

View File

@ -258,6 +258,20 @@ class TestNodeGroupsMigration(base.BaseAlembicMigrationTest):
nodegroup = db.execute(
sa.select([self.meta.tables['nodegroups'].c.cluster_id,
self.meta.tables['nodegroups'].c.name])).fetchone()
insert_table_row(self.meta.tables['nodegroups'],
{'cluster_id': nodegroup['cluster_id'],
'name': uuid.uuid4()})
db.execute(self.meta.tables['nodegroups'].insert(),
[{'cluster_id': nodegroup['cluster_id'],
'name': uuid.uuid4()}])
class TestReleaseMigrations(base.BaseAlembicMigrationTest):
def test_release_is_deployable_deleted(self):
self.assertNotIn('is_deployable',
[c.name for c in self.meta.tables['releases'].c])
def test_releases_are_manageonly(self):
states = [r[0] for r in db.execute(
sa.select([self.meta.tables['releases'].c.state])).fetchall()]
for state in states:
self.assertEqual(state, 'manageonly')

View File

@ -71,11 +71,15 @@ class TestHandlers(BaseIntegrationTest):
def test_release_put_deployable(self):
release = self.env.create_release(api=False)
for deployable in (False, True):
for state, deployable in (
('available', True),
('unavailable', False),
('manageonly', False)
):
resp = self.app.put(
reverse('ReleaseHandler', kwargs={'obj_id': release.id}),
params=jsonutils.dumps({
'is_deployable': deployable,
'state': state,
}),
headers=self.default_headers)
self.assertEqual(200, resp.status_code)
@ -88,7 +92,7 @@ class TestHandlers(BaseIntegrationTest):
resp = self.app.put(
reverse('ReleaseHandler', kwargs={'obj_id': release.id}),
params=jsonutils.dumps({
'is_deployable': False,
'state': consts.RELEASE_STATES.manageonly,
}),
headers=self.default_headers)
self.assertEqual(200, resp.status_code)
@ -108,7 +112,6 @@ class TestHandlers(BaseIntegrationTest):
resp = self.app.put(
reverse('ReleaseHandler', kwargs={'obj_id': release.id}),
params=jsonutils.dumps({
'is_deployable': False,
'state': consts.RELEASE_STATES.unavailable
}),
headers=self.default_headers)

View File

@ -258,12 +258,14 @@
"title": "Releases",
"name": "OpenStack Release",
"version": "Version",
"is_deployable": "Available for New Deployments",
"state": "Available for New Deployments",
"no_releases_message": "There are no releases available.",
"release": {
"available": "Available",
"error": "Error",
"not_available": "Not available"
"not_available": "Not available",
"unavailable": "Not available",
"manageonly": "Manage only"
}
},
"plugins_page": {

View File

@ -28,7 +28,7 @@ function(_, i18n, React, models, controls, componentMixins) {
var ReleasesPage = React.createClass({
mixins: [componentMixins.backboneMixin('releases')],
getDefaultProps: function() {
return {columns: ['name', 'version', 'is_deployable']};
return {columns: ['name', 'version', 'state']};
},
statics: {
title: i18n('release_page.title'),
@ -43,8 +43,8 @@ function(_, i18n, React, models, controls, componentMixins) {
},
getReleaseData: function(release) {
return _.map(this.props.columns, function(attr) {
if (attr == 'is_deployable') {
return i18n('release_page.release.' + (release.get(attr) ? 'available' : 'not_available'));
if (attr == 'state') {
return i18n('release_page.release.' + (release.get(attr)));
}
return release.get(attr) || i18n('common.not_available');
});

View File

@ -633,7 +633,7 @@ function(require, $, _, i18n, Backbone, utils, models, createClusterWizardTempla
this.addPasswordToggle();
if (!_.isUndefined(this.releases) && this.releases.length) {
this.releases = new Backbone.Collection(this.releases.where({is_deployable: true}));
this.releases = new Backbone.Collection(this.releases.where({state: 'available'}));
}
this.composePaneBindings();
return this;