Add db api layer for CRUD operations
Add the DB layer Operations for server tags - set/unset server tags - get server tags - add/delete single tag - check whether server tag exists Change-Id: I2338ece8e4ae880835f6e20ef1e9e71a228a9703 Implements: blueprint server-tags-support
This commit is contained in:
parent
57fe9d796f
commit
ea83f4711a
@ -504,4 +504,8 @@ class NodeNotAllowedManaged(Forbidden):
|
||||
_msg_fmt = _("The bare metal node %(node_uuid)s is not allowed to "
|
||||
"be managed")
|
||||
|
||||
|
||||
class ServerTagNotFound(NotFound):
|
||||
_msg_fmt = _("Server %(server_id)s doesn't have a tag '%(tag)s'")
|
||||
|
||||
ObjectActionError = obj_exc.ObjectActionError
|
||||
|
@ -289,3 +289,70 @@ class Connection(object):
|
||||
def server_group_members_add(self, context, group_uuid, members):
|
||||
"""Add a list of members to a server group"""
|
||||
return IMPL.server_group_members_add(context, group_uuid, members)
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_server_tags(self, context, server_id, tags):
|
||||
"""Replace all of the server tags with specified list of tags.
|
||||
|
||||
This ignores duplicate tags in the specified list.
|
||||
|
||||
:param context: Request context
|
||||
:param server_id: The id of a server.
|
||||
:param tags: List of tags.
|
||||
:returns: A list of ServerTag objects.
|
||||
:raises: ServerNotFound if the server is not found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def unset_server_tags(self, context, server_id):
|
||||
"""Remove all tags of the server.
|
||||
|
||||
:param context: Request context
|
||||
:param server_id: The id of a server.
|
||||
:raises: ServerNotFound if the server is not found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_server_tags_by_server_id(self, context, server_id):
|
||||
"""Get server tags based on its id.
|
||||
|
||||
:param context: Request context
|
||||
:param server_id: The id of a server.
|
||||
:returns: A list of ServerTag objects.
|
||||
:raises: ServerNotFound if the server is not found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_server_tag(self, context, server_id, tag):
|
||||
"""Add tag to the server.
|
||||
|
||||
If the server_id and tag pair already exists, this should still
|
||||
succeed.
|
||||
|
||||
:param context: Request context
|
||||
:param server_id: The id of a server.
|
||||
:param tag: A tag string.
|
||||
:returns: the ServerTag object.
|
||||
:raises: ServerNotFound if the server is not found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_server_tag(self, context, server_id, tag):
|
||||
"""Delete specified tag from the server.
|
||||
|
||||
:param context: Request context
|
||||
:param server_id: The id of a server.
|
||||
:param tag: A tag string.
|
||||
:raises: ServerNotFound if the server is not found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def server_tag_exists(self, context, server_id, tag):
|
||||
"""Check if the specified tag exist on the server.
|
||||
|
||||
:param context: Request context
|
||||
:param server_id: The id of a server.
|
||||
:param tag: A tag string.
|
||||
:returns: True if the tag exists otherwise False.
|
||||
:raises: ServerTagNotFound if the tag is not found.
|
||||
"""
|
||||
|
@ -234,6 +234,7 @@ class Connection(api.Connection):
|
||||
nic_ref = models.ServerNic()
|
||||
nic_ref.update(nic)
|
||||
nic_refs.append(nic_ref)
|
||||
|
||||
with _session_for_write() as session:
|
||||
try:
|
||||
session.add(server)
|
||||
@ -1075,6 +1076,70 @@ class Connection(api.Connection):
|
||||
raise exception.ServerGroupNotFound(group_uuid=group_uuid)
|
||||
self._server_group_members_add(context, group.id, members)
|
||||
|
||||
def _check_server_exists(self, context, server_id):
|
||||
if not model_query(context, models.Server)\
|
||||
.filter_by(id=server_id).scalar():
|
||||
raise exception.ServerNotFound(server=server_id)
|
||||
|
||||
@oslo_db_api.retry_on_deadlock
|
||||
def set_server_tags(self, context, server_id, tags):
|
||||
# remove duplicate tags
|
||||
tags = set(tags)
|
||||
with _session_for_write() as session:
|
||||
self.unset_server_tags(context, server_id)
|
||||
server_tags = []
|
||||
for tag in tags:
|
||||
server_tag = models.ServerTag(tag=tag, server_id=server_id)
|
||||
session.add(server_tag)
|
||||
server_tags.append(server_tag)
|
||||
|
||||
return server_tags
|
||||
|
||||
@oslo_db_api.retry_on_deadlock
|
||||
def unset_server_tags(self, context, server_id):
|
||||
self._check_server_exists(context, server_id)
|
||||
with _session_for_write():
|
||||
model_query(context, models.ServerTag)\
|
||||
.filter_by(server_id=server_id).delete()
|
||||
|
||||
def get_server_tags_by_server_id(self, context, server_id):
|
||||
self._check_server_exists(context, server_id)
|
||||
result = (model_query(context, models.ServerTag)
|
||||
.filter_by(server_id=server_id)
|
||||
.all())
|
||||
return result
|
||||
|
||||
@oslo_db_api.retry_on_deadlock
|
||||
def add_server_tag(self, context, server_id, tag):
|
||||
self._check_server_exists(context, server_id)
|
||||
server_tag = models.ServerTag(tag=tag, server_id=server_id)
|
||||
try:
|
||||
with _session_for_write() as session:
|
||||
session.add(server_tag)
|
||||
session.flush()
|
||||
except db_exc.DBDuplicateEntry:
|
||||
# NOTE(litao): ignore tags duplicates
|
||||
pass
|
||||
|
||||
return server_tag
|
||||
|
||||
@oslo_db_api.retry_on_deadlock
|
||||
def delete_server_tag(self, context, server_id, tag):
|
||||
self._check_server_exists(context, server_id)
|
||||
with _session_for_write():
|
||||
result = model_query(context, models.ServerTag).filter_by(
|
||||
server_id=server_id, tag=tag).delete()
|
||||
|
||||
if not result:
|
||||
raise exception.ServerTagNotFound(server_id=server_id, tag=tag)
|
||||
|
||||
def server_tag_exists(self, context, server_id, tag):
|
||||
self._check_server_exists(context, server_id)
|
||||
q = model_query(context, models.ServerTag)\
|
||||
.filter_by(server_id=server_id, tag=tag)
|
||||
|
||||
return q.scalar()
|
||||
|
||||
|
||||
def _get_id_from_flavor_query(context, type_id):
|
||||
return model_query(context, models.Flavors). \
|
||||
|
@ -385,3 +385,10 @@ class ServerTag(Base):
|
||||
server_id = Column(Integer, ForeignKey('servers.id'),
|
||||
primary_key=True, nullable=False)
|
||||
tag = Column(String(255), primary_key=True, nullable=False)
|
||||
|
||||
server = orm.relationship(
|
||||
"Server",
|
||||
backref='tags',
|
||||
primaryjoin='and_(ServerTag.server_id == Server.id)',
|
||||
foreign_keys=server_id
|
||||
)
|
||||
|
130
mogan/tests/unit/db/test_server_tags.py
Normal file
130
mogan/tests/unit/db/test_server_tags.py
Normal file
@ -0,0 +1,130 @@
|
||||
# Copyright 2017 Fiberhome Integration Technologies Co.,LTD.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Tests for manipulating Server tags via the DB API"""
|
||||
|
||||
from mogan.common import exception
|
||||
from mogan.tests.unit.db import base
|
||||
from mogan.tests.unit.db import utils
|
||||
|
||||
|
||||
class DbServerTagTestCase(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(DbServerTagTestCase, self).setUp()
|
||||
self.server = utils.create_test_server()
|
||||
|
||||
def test_set_server_tags(self):
|
||||
tags = self.dbapi.set_server_tags(self.context, self.server.id,
|
||||
['tag1', 'tag2'])
|
||||
self.assertEqual(self.server.id, tags[0].server_id)
|
||||
self.assertItemsEqual(['tag1', 'tag2'], [tag.tag for tag in tags])
|
||||
|
||||
tags = self.dbapi.set_server_tags(self.context, self.server.id, [])
|
||||
self.assertEqual([], tags)
|
||||
|
||||
def test_set_server_tags_duplicate(self):
|
||||
tags = self.dbapi.set_server_tags(self.context, self.server.id,
|
||||
['tag1', 'tag2', 'tag2'])
|
||||
self.assertEqual(self.server.id, tags[0].server_id)
|
||||
self.assertItemsEqual(['tag1', 'tag2'], [tag.tag for tag in tags])
|
||||
|
||||
def test_set_server_tags_server_not_exist(self):
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.set_server_tags,
|
||||
self.context, '1234', ['tag1', 'tag2'])
|
||||
|
||||
def test_get_server_tags_by_server_id(self):
|
||||
self.dbapi.set_server_tags(self.context, self.server.id,
|
||||
['tag1', 'tag2'])
|
||||
tags = self.dbapi.get_server_tags_by_server_id(self.context,
|
||||
self.server.id)
|
||||
self.assertEqual(self.server.id, tags[0].server_id)
|
||||
self.assertItemsEqual(['tag1', 'tag2'], [tag.tag for tag in tags])
|
||||
|
||||
def test_get_server_tags_empty(self):
|
||||
tags = self.dbapi.get_server_tags_by_server_id(self.context,
|
||||
self.server.id)
|
||||
self.assertEqual([], tags)
|
||||
|
||||
def test_get_server_tags_server_not_exist(self):
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.get_server_tags_by_server_id,
|
||||
self.context, '123')
|
||||
|
||||
def test_unset_server_tags(self):
|
||||
self.dbapi.set_server_tags(self.context, self.server.id,
|
||||
['tag1', 'tag2'])
|
||||
self.dbapi.unset_server_tags(self.context, self.server.id)
|
||||
tags = self.dbapi.get_server_tags_by_server_id(self.context,
|
||||
self.server.id)
|
||||
self.assertEqual([], tags)
|
||||
|
||||
def test_unset_empty_server_tags(self):
|
||||
self.dbapi.unset_server_tags(self.context, self.server.id)
|
||||
tags = self.dbapi.get_server_tags_by_server_id(self.context,
|
||||
self.server.id)
|
||||
self.assertEqual([], tags)
|
||||
|
||||
def test_unset_server_tags_server_not_exist(self):
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.unset_server_tags, self.context, '123')
|
||||
|
||||
def test_add_server_tag(self):
|
||||
tag = self.dbapi.add_server_tag(self.context, self.server.id, 'tag1')
|
||||
self.assertEqual(self.server.id, tag.server_id)
|
||||
self.assertEqual('tag1', tag.tag)
|
||||
|
||||
def test_add_server_tag_duplicate(self):
|
||||
tag = self.dbapi.add_server_tag(self.context, self.server.id, 'tag1')
|
||||
tag = self.dbapi.add_server_tag(self.context, self.server.id, 'tag1')
|
||||
self.assertEqual(self.server.id, tag.server_id)
|
||||
self.assertEqual('tag1', tag.tag)
|
||||
|
||||
def test_add_server_tag_server_not_exist(self):
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.add_server_tag, self.context,
|
||||
'123', 'tag1')
|
||||
|
||||
def test_delete_server_tag(self):
|
||||
self.dbapi.set_server_tags(self.context, self.server.id,
|
||||
['tag1', 'tag2'])
|
||||
self.dbapi.delete_server_tag(self.context, self.server.id, 'tag1')
|
||||
tags = self.dbapi.get_server_tags_by_server_id(self.context,
|
||||
self.server.id)
|
||||
self.assertEqual(1, len(tags))
|
||||
self.assertEqual('tag2', tags[0].tag)
|
||||
|
||||
def test_delete_server_tag_not_found(self):
|
||||
self.assertRaises(exception.ServerTagNotFound,
|
||||
self.dbapi.delete_server_tag, self.context,
|
||||
self.server.id, 'tag1')
|
||||
|
||||
def test_delete_server_tag_server_not_found(self):
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.delete_server_tag, self.context,
|
||||
'123', 'tag1')
|
||||
|
||||
def test_server_tag_exists(self):
|
||||
self.dbapi.set_server_tags(self.context,
|
||||
self.server.id, ['tag1', 'tag2'])
|
||||
ret = self.dbapi.server_tag_exists(self.context,
|
||||
self.server.id, 'tag1')
|
||||
self.assertTrue(ret)
|
||||
|
||||
def test_server_tag_not_exists(self):
|
||||
ret = self.dbapi.server_tag_exists(self.context,
|
||||
self.server.id, 'tag1')
|
||||
self.assertFalse(ret)
|
@ -149,3 +149,25 @@ class DbServerTestCase(base.DbTestCase):
|
||||
self.context,
|
||||
server.uuid,
|
||||
{'uuid': '12345678-9999-0000-aaaa-123456789012'})
|
||||
|
||||
def test_tags_get_destroyed_after_destroying_a_server(self):
|
||||
server = utils.create_test_server(id=123)
|
||||
tag = utils.create_test_server_tag(self.context, server_id=server.id)
|
||||
|
||||
self.assertTrue(self.dbapi.server_tag_exists(self.context,
|
||||
server.id, tag.tag))
|
||||
self.dbapi.server_destroy(self.context, server.id)
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.server_tag_exists,
|
||||
self.context, server.id, tag.tag)
|
||||
|
||||
def test_tags_get_destroyed_after_destroying_a_server_by_uuid(self):
|
||||
server = utils.create_test_server(id=124)
|
||||
tag = utils.create_test_server_tag(self.context, server_id=server.id)
|
||||
|
||||
self.assertTrue(self.dbapi.server_tag_exists(self.context,
|
||||
server.id, tag.tag))
|
||||
self.dbapi.server_destroy(self.context, server.uuid)
|
||||
self.assertRaises(exception.ServerNotFound,
|
||||
self.dbapi.server_tag_exists,
|
||||
self.context, server.id, tag.tag)
|
||||
|
@ -243,3 +243,27 @@ def create_test_server_group(context={}, **kw):
|
||||
policies = server_fault.pop('policies')
|
||||
return dbapi.server_group_create(context, server_fault, policies=policies,
|
||||
members=members)
|
||||
|
||||
|
||||
def get_test_server_tag(**kw):
|
||||
return {
|
||||
"tag": kw.get("tag", "tag1"),
|
||||
"server_id": kw.get("server_id", "123"),
|
||||
'created_at': kw.get('created_at'),
|
||||
'updated_at': kw.get('updated_at'),
|
||||
}
|
||||
|
||||
|
||||
def create_test_server_tag(context, **kw):
|
||||
"""Create test node tag entry in DB and return NodeTag DB object.
|
||||
|
||||
Function to be used to create test NodeTag objects in the database.
|
||||
|
||||
:param context: Request context
|
||||
:param kw: kwargs with overriding values for tag's attributes.
|
||||
:returns: Test NodeTag DB object.
|
||||
|
||||
"""
|
||||
tag = get_test_server_tag(**kw)
|
||||
dbapi = db_api.get_instance()
|
||||
return dbapi.add_server_tag(context, tag['server_id'], tag['tag'])
|
||||
|
Loading…
Reference in New Issue
Block a user