Merge "Add Node.driver_internal_info"

This commit is contained in:
Jenkins 2015-02-03 12:32:21 +00:00 committed by Gerrit Code Review
commit d7f15f2bec
10 changed files with 90 additions and 7 deletions

View File

@ -38,7 +38,7 @@ from ironic.common.i18n import _
MIN_VER = 0
MAX_VER = 1
MAX_VER = 2
class MediaType(base.APIBase):

View File

@ -60,6 +60,12 @@ def assert_juno_provision_state_name(obj):
obj.provision_state = ir_states.NOSTATE
def hide_driver_internal_info(obj):
# if requested version is < 1.2, hide driver_internal_info
if pecan.request.version.minor < 2:
obj.driver_internal_info = wsme.Unset
class NodePatchType(types.JsonPatchType):
@staticmethod
@ -70,7 +76,8 @@ class NodePatchType(types.JsonPatchType):
return defaults + ['/console_enabled', '/last_error',
'/power_state', '/provision_state', '/reservation',
'/target_power_state', '/target_provision_state',
'/provision_updated_at', '/maintenance_reason']
'/provision_updated_at', '/maintenance_reason',
'/driver_internal_info']
@staticmethod
def mandatory_attrs():
@ -459,6 +466,10 @@ class Node(base.APIBase):
driver_info = {wtypes.text: types.jsontype}
"""This node's driver configuration"""
driver_internal_info = wsme.wsattr({wtypes.text: types.jsontype},
readonly=True)
"""This driver's internal configuration"""
extra = {wtypes.text: types.jsontype}
"""This node's meta data"""
@ -529,6 +540,7 @@ class Node(base.APIBase):
def convert_with_links(cls, rpc_node, expand=True):
node = Node(**rpc_node.as_dict())
assert_juno_provision_state_name(node)
hide_driver_internal_info(node)
return cls._convert_with_links(node, pecan.request.host_url,
expand)
@ -542,7 +554,8 @@ class Node(base.APIBase):
target_power_state=ir_states.NOSTATE,
last_error=None, provision_state=ir_states.ACTIVE,
target_provision_state=ir_states.NOSTATE,
reservation=None, driver='fake', driver_info={}, extra={},
reservation=None, driver='fake', driver_info={},
driver_internal_info={}, extra={},
properties={'memory_mb': '1024', 'local_gb': '10',
'cpus': '1'}, updated_at=time, created_at=time,
provision_updated_at=time, instance_info={},

View File

@ -167,7 +167,8 @@ class JsonPatchType(wtypes.Base):
@staticmethod
def validate(patch):
if patch.path in patch.internal_attrs():
_path = '/' + patch.path.split('/')[1]
if _path in patch.internal_attrs():
msg = _("'%s' is an internal attribute and can not be updated")
raise wsme.exc.ClientSideError(msg % patch.path)

View File

@ -0,0 +1,36 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""add_node_driver_internal_info
Revision ID: bb59b63f55a
Revises: 5674c57409b9
Create Date: 2015-01-28 14:28:22.212790
"""
# revision identifiers, used by Alembic.
revision = 'bb59b63f55a'
down_revision = '5674c57409b9'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('nodes', sa.Column('driver_internal_info',
sa.Text(),
nullable=True))
def downgrade():
op.drop_column('nodes', 'driver_internal_info')

View File

@ -164,6 +164,7 @@ class Node(Base):
properties = Column(JSONEncodedDict)
driver = Column(String(15))
driver_info = Column(JSONEncodedDict)
driver_internal_info = Column(JSONEncodedDict)
# NOTE(deva): this is the host name of the conductor which has
# acquired a TaskManager lock on the node.

View File

@ -31,7 +31,8 @@ class Node(base.IronicObject):
# Version 1.6: Add reserve() and release()
# Version 1.7: Add conductor_affinity
# Version 1.8: Add maintenance_reason
VERSION = '1.8'
# Version 1.9: Add driver_internal_info
VERSION = '1.9'
dbapi = db_api.get_instance()
@ -44,6 +45,7 @@ class Node(base.IronicObject):
'driver': obj_utils.str_or_none,
'driver_info': obj_utils.dict_or_none,
'driver_internal_info': obj_utils.dict_or_none,
'instance_info': obj_utils.dict_or_none,
'properties': obj_utils.dict_or_none,

View File

@ -93,7 +93,8 @@ class TestListNodes(test_api_base.FunctionalTest):
def test_one(self):
node = obj_utils.create_test_node(self.context)
data = self.get_json('/nodes')
data = self.get_json('/nodes',
headers={api_base.Version.string: "1.2"})
self.assertIn('instance_uuid', data['nodes'][0])
self.assertIn('maintenance', data['nodes'][0])
self.assertIn('power_state', data['nodes'][0])
@ -102,6 +103,7 @@ class TestListNodes(test_api_base.FunctionalTest):
self.assertEqual(node['uuid'], data['nodes'][0]["uuid"])
self.assertNotIn('driver', data['nodes'][0])
self.assertNotIn('driver_info', data['nodes'][0])
self.assertNotIn('driver_internal_info', data['nodes'][0])
self.assertNotIn('extra', data['nodes'][0])
self.assertNotIn('properties', data['nodes'][0])
self.assertNotIn('chassis_uuid', data['nodes'][0])
@ -116,10 +118,12 @@ class TestListNodes(test_api_base.FunctionalTest):
def test_get_one(self):
node = obj_utils.create_test_node(self.context)
data = self.get_json('/nodes/%s' % node['uuid'])
data = self.get_json('/nodes/%s' % node['uuid'],
headers={api_base.Version.string: "1.2"})
self.assertEqual(node.uuid, data['uuid'])
self.assertIn('driver', data)
self.assertIn('driver_info', data)
self.assertIn('driver_internal_info', data)
self.assertIn('extra', data)
self.assertIn('properties', data)
self.assertIn('chassis_uuid', data)
@ -164,6 +168,17 @@ class TestListNodes(test_api_base.FunctionalTest):
headers={api_base.Version.string: "1.1"})
self.assertEqual(states.AVAILABLE, data['provision_state'])
def test_hide_driver_internal_info(self):
node = obj_utils.create_test_node(self.context,
driver_internal_info={"foo": "bar"})
data = self.get_json('/nodes/%s' % node['uuid'],
headers={api_base.Version.string: "1.0"})
self.assertNotIn('driver_internal_info', data)
data = self.get_json('/nodes/%s' % node['uuid'],
headers={api_base.Version.string: "1.2"})
self.assertEqual({"foo": "bar"}, data['driver_internal_info'])
def test_many(self):
nodes = []
for id in range(5):

View File

@ -107,6 +107,13 @@ class TestJsonPatchType(base.TestCase):
self.assertEqual(400, ret.status_int)
self.assertTrue(ret.json['faultstring'])
def test_cannot_update_internal_dict_attr(self):
patch = [{'path': '/internal/test', 'op': 'replace',
'value': 'foo'}]
ret = self._patch_json(patch, True)
self.assertEqual(400, ret.status_int)
self.assertTrue(ret.json['faultstring'])
def test_mandatory_attr(self):
patch = [{'op': 'replace', 'path': '/mandatory', 'value': 'foo'}]
ret = self._patch_json(patch, False)

View File

@ -360,6 +360,13 @@ class MigrationCheckersMixin(object):
else:
self.assertEqual(old, new)
def _check_bb59b63f55a(self, engine, data):
nodes = db_utils.get_table(engine, 'nodes')
col_names = [column.name for column in nodes.c]
self.assertIn('driver_internal_info', col_names)
self.assertIsInstance(nodes.c.driver_internal_info.type,
sqlalchemy.types.TEXT)
def test_upgrade_and_version(self):
with patch_with_engine(self.engine):
self.migration_api.upgrade('head')

View File

@ -179,6 +179,7 @@ def get_test_node(**kw):
'instance_info': kw.get('instance_info', fake_info),
'driver': kw.get('driver', 'fake'),
'driver_info': kw.get('driver_info', fake_info),
'driver_internal_info': kw.get('driver_internal_info', fake_info),
'properties': kw.get('properties', properties),
'reservation': kw.get('reservation'),
'maintenance': kw.get('maintenance', False),