summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTao Li <litao3721@126.com>2017-10-11 10:50:38 +0800
committerTao Li <litao3721@126.com>2017-10-19 14:33:58 +0800
commitea83f4711a70fffe7a4da9d39f0afb51624e26f0 (patch)
treef33e2361d2e804589c97fd826f37190d4dc0fdbf
parent57fe9d796fde6f8403c1b326512b90e68e44d631 (diff)
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
Notes
Notes (review): Code-Review+1: zhangjl <luoyan_cn@outlook.com> Code-Review+2: Zhenguo Niu <Niu.ZGlinux@gmail.com> Code-Review+1: wanghao <sxmatch1986@gmail.com> Code-Review+1: Xinran WANG <xin-ran.wang@intel.com> Code-Review+2: liusheng <liusheng2048@gmail.com> Workflow+1: liusheng <liusheng2048@gmail.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Sat, 28 Oct 2017 03:58:23 +0000 Reviewed-on: https://review.openstack.org/513215 Project: openstack/mogan Branch: refs/heads/master
-rw-r--r--mogan/common/exception.py4
-rw-r--r--mogan/db/api.py67
-rw-r--r--mogan/db/sqlalchemy/api.py65
-rw-r--r--mogan/db/sqlalchemy/models.py7
-rw-r--r--mogan/tests/unit/db/test_server_tags.py130
-rw-r--r--mogan/tests/unit/db/test_servers.py22
-rw-r--r--mogan/tests/unit/db/utils.py24
7 files changed, 319 insertions, 0 deletions
diff --git a/mogan/common/exception.py b/mogan/common/exception.py
index c935612..71178d5 100644
--- a/mogan/common/exception.py
+++ b/mogan/common/exception.py
@@ -504,4 +504,8 @@ class NodeNotAllowedManaged(Forbidden):
504 _msg_fmt = _("The bare metal node %(node_uuid)s is not allowed to " 504 _msg_fmt = _("The bare metal node %(node_uuid)s is not allowed to "
505 "be managed") 505 "be managed")
506 506
507
508class ServerTagNotFound(NotFound):
509 _msg_fmt = _("Server %(server_id)s doesn't have a tag '%(tag)s'")
510
507ObjectActionError = obj_exc.ObjectActionError 511ObjectActionError = obj_exc.ObjectActionError
diff --git a/mogan/db/api.py b/mogan/db/api.py
index 33af720..329f14f 100644
--- a/mogan/db/api.py
+++ b/mogan/db/api.py
@@ -289,3 +289,70 @@ class Connection(object):
289 def server_group_members_add(self, context, group_uuid, members): 289 def server_group_members_add(self, context, group_uuid, members):
290 """Add a list of members to a server group""" 290 """Add a list of members to a server group"""
291 return IMPL.server_group_members_add(context, group_uuid, members) 291 return IMPL.server_group_members_add(context, group_uuid, members)
292
293 @abc.abstractmethod
294 def set_server_tags(self, context, server_id, tags):
295 """Replace all of the server tags with specified list of tags.
296
297 This ignores duplicate tags in the specified list.
298
299 :param context: Request context
300 :param server_id: The id of a server.
301 :param tags: List of tags.
302 :returns: A list of ServerTag objects.
303 :raises: ServerNotFound if the server is not found.
304 """
305
306 @abc.abstractmethod
307 def unset_server_tags(self, context, server_id):
308 """Remove all tags of the server.
309
310 :param context: Request context
311 :param server_id: The id of a server.
312 :raises: ServerNotFound if the server is not found.
313 """
314
315 @abc.abstractmethod
316 def get_server_tags_by_server_id(self, context, server_id):
317 """Get server tags based on its id.
318
319 :param context: Request context
320 :param server_id: The id of a server.
321 :returns: A list of ServerTag objects.
322 :raises: ServerNotFound if the server is not found.
323 """
324
325 @abc.abstractmethod
326 def add_server_tag(self, context, server_id, tag):
327 """Add tag to the server.
328
329 If the server_id and tag pair already exists, this should still
330 succeed.
331
332 :param context: Request context
333 :param server_id: The id of a server.
334 :param tag: A tag string.
335 :returns: the ServerTag object.
336 :raises: ServerNotFound if the server is not found.
337 """
338
339 @abc.abstractmethod
340 def delete_server_tag(self, context, server_id, tag):
341 """Delete specified tag from the server.
342
343 :param context: Request context
344 :param server_id: The id of a server.
345 :param tag: A tag string.
346 :raises: ServerNotFound if the server is not found.
347 """
348
349 @abc.abstractmethod
350 def server_tag_exists(self, context, server_id, tag):
351 """Check if the specified tag exist on the server.
352
353 :param context: Request context
354 :param server_id: The id of a server.
355 :param tag: A tag string.
356 :returns: True if the tag exists otherwise False.
357 :raises: ServerTagNotFound if the tag is not found.
358 """
diff --git a/mogan/db/sqlalchemy/api.py b/mogan/db/sqlalchemy/api.py
index 1399ffc..23bf1c2 100644
--- a/mogan/db/sqlalchemy/api.py
+++ b/mogan/db/sqlalchemy/api.py
@@ -234,6 +234,7 @@ class Connection(api.Connection):
234 nic_ref = models.ServerNic() 234 nic_ref = models.ServerNic()
235 nic_ref.update(nic) 235 nic_ref.update(nic)
236 nic_refs.append(nic_ref) 236 nic_refs.append(nic_ref)
237
237 with _session_for_write() as session: 238 with _session_for_write() as session:
238 try: 239 try:
239 session.add(server) 240 session.add(server)
@@ -1075,6 +1076,70 @@ class Connection(api.Connection):
1075 raise exception.ServerGroupNotFound(group_uuid=group_uuid) 1076 raise exception.ServerGroupNotFound(group_uuid=group_uuid)
1076 self._server_group_members_add(context, group.id, members) 1077 self._server_group_members_add(context, group.id, members)
1077 1078
1079 def _check_server_exists(self, context, server_id):
1080 if not model_query(context, models.Server)\
1081 .filter_by(id=server_id).scalar():
1082 raise exception.ServerNotFound(server=server_id)
1083
1084 @oslo_db_api.retry_on_deadlock
1085 def set_server_tags(self, context, server_id, tags):
1086 # remove duplicate tags
1087 tags = set(tags)
1088 with _session_for_write() as session:
1089 self.unset_server_tags(context, server_id)
1090 server_tags = []
1091 for tag in tags:
1092 server_tag = models.ServerTag(tag=tag, server_id=server_id)
1093 session.add(server_tag)
1094 server_tags.append(server_tag)
1095
1096 return server_tags
1097
1098 @oslo_db_api.retry_on_deadlock
1099 def unset_server_tags(self, context, server_id):
1100 self._check_server_exists(context, server_id)
1101 with _session_for_write():
1102 model_query(context, models.ServerTag)\
1103 .filter_by(server_id=server_id).delete()
1104
1105 def get_server_tags_by_server_id(self, context, server_id):
1106 self._check_server_exists(context, server_id)
1107 result = (model_query(context, models.ServerTag)
1108 .filter_by(server_id=server_id)
1109 .all())
1110 return result
1111
1112 @oslo_db_api.retry_on_deadlock
1113 def add_server_tag(self, context, server_id, tag):
1114 self._check_server_exists(context, server_id)
1115 server_tag = models.ServerTag(tag=tag, server_id=server_id)
1116 try:
1117 with _session_for_write() as session:
1118 session.add(server_tag)
1119 session.flush()
1120 except db_exc.DBDuplicateEntry:
1121 # NOTE(litao): ignore tags duplicates
1122 pass
1123
1124 return server_tag
1125
1126 @oslo_db_api.retry_on_deadlock
1127 def delete_server_tag(self, context, server_id, tag):
1128 self._check_server_exists(context, server_id)
1129 with _session_for_write():
1130 result = model_query(context, models.ServerTag).filter_by(
1131 server_id=server_id, tag=tag).delete()
1132
1133 if not result:
1134 raise exception.ServerTagNotFound(server_id=server_id, tag=tag)
1135
1136 def server_tag_exists(self, context, server_id, tag):
1137 self._check_server_exists(context, server_id)
1138 q = model_query(context, models.ServerTag)\
1139 .filter_by(server_id=server_id, tag=tag)
1140
1141 return q.scalar()
1142
1078 1143
1079def _get_id_from_flavor_query(context, type_id): 1144def _get_id_from_flavor_query(context, type_id):
1080 return model_query(context, models.Flavors). \ 1145 return model_query(context, models.Flavors). \
diff --git a/mogan/db/sqlalchemy/models.py b/mogan/db/sqlalchemy/models.py
index 3148e61..ac2f524 100644
--- a/mogan/db/sqlalchemy/models.py
+++ b/mogan/db/sqlalchemy/models.py
@@ -385,3 +385,10 @@ class ServerTag(Base):
385 server_id = Column(Integer, ForeignKey('servers.id'), 385 server_id = Column(Integer, ForeignKey('servers.id'),
386 primary_key=True, nullable=False) 386 primary_key=True, nullable=False)
387 tag = Column(String(255), primary_key=True, nullable=False) 387 tag = Column(String(255), primary_key=True, nullable=False)
388
389 server = orm.relationship(
390 "Server",
391 backref='tags',
392 primaryjoin='and_(ServerTag.server_id == Server.id)',
393 foreign_keys=server_id
394 )
diff --git a/mogan/tests/unit/db/test_server_tags.py b/mogan/tests/unit/db/test_server_tags.py
new file mode 100644
index 0000000..a76e6de
--- /dev/null
+++ b/mogan/tests/unit/db/test_server_tags.py
@@ -0,0 +1,130 @@
1# Copyright 2017 Fiberhome Integration Technologies Co.,LTD.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16"""Tests for manipulating Server tags via the DB API"""
17
18from mogan.common import exception
19from mogan.tests.unit.db import base
20from mogan.tests.unit.db import utils
21
22
23class DbServerTagTestCase(base.DbTestCase):
24
25 def setUp(self):
26 super(DbServerTagTestCase, self).setUp()
27 self.server = utils.create_test_server()
28
29 def test_set_server_tags(self):
30 tags = self.dbapi.set_server_tags(self.context, self.server.id,
31 ['tag1', 'tag2'])
32 self.assertEqual(self.server.id, tags[0].server_id)
33 self.assertItemsEqual(['tag1', 'tag2'], [tag.tag for tag in tags])
34
35 tags = self.dbapi.set_server_tags(self.context, self.server.id, [])
36 self.assertEqual([], tags)
37
38 def test_set_server_tags_duplicate(self):
39 tags = self.dbapi.set_server_tags(self.context, self.server.id,
40 ['tag1', 'tag2', 'tag2'])
41 self.assertEqual(self.server.id, tags[0].server_id)
42 self.assertItemsEqual(['tag1', 'tag2'], [tag.tag for tag in tags])
43
44 def test_set_server_tags_server_not_exist(self):
45 self.assertRaises(exception.ServerNotFound,
46 self.dbapi.set_server_tags,
47 self.context, '1234', ['tag1', 'tag2'])
48
49 def test_get_server_tags_by_server_id(self):
50 self.dbapi.set_server_tags(self.context, self.server.id,
51 ['tag1', 'tag2'])
52 tags = self.dbapi.get_server_tags_by_server_id(self.context,
53 self.server.id)
54 self.assertEqual(self.server.id, tags[0].server_id)
55 self.assertItemsEqual(['tag1', 'tag2'], [tag.tag for tag in tags])
56
57 def test_get_server_tags_empty(self):
58 tags = self.dbapi.get_server_tags_by_server_id(self.context,
59 self.server.id)
60 self.assertEqual([], tags)
61
62 def test_get_server_tags_server_not_exist(self):
63 self.assertRaises(exception.ServerNotFound,
64 self.dbapi.get_server_tags_by_server_id,
65 self.context, '123')
66
67 def test_unset_server_tags(self):
68 self.dbapi.set_server_tags(self.context, self.server.id,
69 ['tag1', 'tag2'])
70 self.dbapi.unset_server_tags(self.context, self.server.id)
71 tags = self.dbapi.get_server_tags_by_server_id(self.context,
72 self.server.id)
73 self.assertEqual([], tags)
74
75 def test_unset_empty_server_tags(self):
76 self.dbapi.unset_server_tags(self.context, self.server.id)
77 tags = self.dbapi.get_server_tags_by_server_id(self.context,
78 self.server.id)
79 self.assertEqual([], tags)
80
81 def test_unset_server_tags_server_not_exist(self):
82 self.assertRaises(exception.ServerNotFound,
83 self.dbapi.unset_server_tags, self.context, '123')
84
85 def test_add_server_tag(self):
86 tag = self.dbapi.add_server_tag(self.context, self.server.id, 'tag1')
87 self.assertEqual(self.server.id, tag.server_id)
88 self.assertEqual('tag1', tag.tag)
89
90 def test_add_server_tag_duplicate(self):
91 tag = self.dbapi.add_server_tag(self.context, self.server.id, 'tag1')
92 tag = self.dbapi.add_server_tag(self.context, self.server.id, 'tag1')
93 self.assertEqual(self.server.id, tag.server_id)
94 self.assertEqual('tag1', tag.tag)
95
96 def test_add_server_tag_server_not_exist(self):
97 self.assertRaises(exception.ServerNotFound,
98 self.dbapi.add_server_tag, self.context,
99 '123', 'tag1')
100
101 def test_delete_server_tag(self):
102 self.dbapi.set_server_tags(self.context, self.server.id,
103 ['tag1', 'tag2'])
104 self.dbapi.delete_server_tag(self.context, self.server.id, 'tag1')
105 tags = self.dbapi.get_server_tags_by_server_id(self.context,
106 self.server.id)
107 self.assertEqual(1, len(tags))
108 self.assertEqual('tag2', tags[0].tag)
109
110 def test_delete_server_tag_not_found(self):
111 self.assertRaises(exception.ServerTagNotFound,
112 self.dbapi.delete_server_tag, self.context,
113 self.server.id, 'tag1')
114
115 def test_delete_server_tag_server_not_found(self):
116 self.assertRaises(exception.ServerNotFound,
117 self.dbapi.delete_server_tag, self.context,
118 '123', 'tag1')
119
120 def test_server_tag_exists(self):
121 self.dbapi.set_server_tags(self.context,
122 self.server.id, ['tag1', 'tag2'])
123 ret = self.dbapi.server_tag_exists(self.context,
124 self.server.id, 'tag1')
125 self.assertTrue(ret)
126
127 def test_server_tag_not_exists(self):
128 ret = self.dbapi.server_tag_exists(self.context,
129 self.server.id, 'tag1')
130 self.assertFalse(ret)
diff --git a/mogan/tests/unit/db/test_servers.py b/mogan/tests/unit/db/test_servers.py
index 7ffed78..b780644 100644
--- a/mogan/tests/unit/db/test_servers.py
+++ b/mogan/tests/unit/db/test_servers.py
@@ -149,3 +149,25 @@ class DbServerTestCase(base.DbTestCase):
149 self.context, 149 self.context,
150 server.uuid, 150 server.uuid,
151 {'uuid': '12345678-9999-0000-aaaa-123456789012'}) 151 {'uuid': '12345678-9999-0000-aaaa-123456789012'})
152
153 def test_tags_get_destroyed_after_destroying_a_server(self):
154 server = utils.create_test_server(id=123)
155 tag = utils.create_test_server_tag(self.context, server_id=server.id)
156
157 self.assertTrue(self.dbapi.server_tag_exists(self.context,
158 server.id, tag.tag))
159 self.dbapi.server_destroy(self.context, server.id)
160 self.assertRaises(exception.ServerNotFound,
161 self.dbapi.server_tag_exists,
162 self.context, server.id, tag.tag)
163
164 def test_tags_get_destroyed_after_destroying_a_server_by_uuid(self):
165 server = utils.create_test_server(id=124)
166 tag = utils.create_test_server_tag(self.context, server_id=server.id)
167
168 self.assertTrue(self.dbapi.server_tag_exists(self.context,
169 server.id, tag.tag))
170 self.dbapi.server_destroy(self.context, server.uuid)
171 self.assertRaises(exception.ServerNotFound,
172 self.dbapi.server_tag_exists,
173 self.context, server.id, tag.tag)
diff --git a/mogan/tests/unit/db/utils.py b/mogan/tests/unit/db/utils.py
index 133188d..b03af43 100644
--- a/mogan/tests/unit/db/utils.py
+++ b/mogan/tests/unit/db/utils.py
@@ -243,3 +243,27 @@ def create_test_server_group(context={}, **kw):
243 policies = server_fault.pop('policies') 243 policies = server_fault.pop('policies')
244 return dbapi.server_group_create(context, server_fault, policies=policies, 244 return dbapi.server_group_create(context, server_fault, policies=policies,
245 members=members) 245 members=members)
246
247
248def get_test_server_tag(**kw):
249 return {
250 "tag": kw.get("tag", "tag1"),
251 "server_id": kw.get("server_id", "123"),
252 'created_at': kw.get('created_at'),
253 'updated_at': kw.get('updated_at'),
254 }
255
256
257def create_test_server_tag(context, **kw):
258 """Create test node tag entry in DB and return NodeTag DB object.
259
260 Function to be used to create test NodeTag objects in the database.
261
262 :param context: Request context
263 :param kw: kwargs with overriding values for tag's attributes.
264 :returns: Test NodeTag DB object.
265
266 """
267 tag = get_test_server_tag(**kw)
268 dbapi = db_api.get_instance()
269 return dbapi.add_server_tag(context, tag['server_id'], tag['tag'])