Browse Source

Add volume_targets table to database

This patch adds a "volume_targets" DB table in order to save
the volume target information of physical nodes. With this patch,
Ironic can put/get volume target information to/from the database.

Co-Authored-By: Stephane Miller <stephane@alum.mit.edu>
Co-Authored-By: Ruby Loo <ruby.loo@intel.com>
Change-Id: I79063f9d0aafd7b740785a883732536704e43b7c
Partial-Bug: 1526231
tags/7.0.0
Satoru Moriya 3 years ago
parent
commit
07541047be

+ 13
- 0
ironic/common/exception.py View File

@@ -217,6 +217,15 @@ class VolumeConnectorTypeAndIdAlreadyExists(Conflict):
217 217
                  "%(connector_id)s already exists.")
218 218
 
219 219
 
220
+class VolumeTargetAlreadyExists(Conflict):
221
+    _msg_fmt = _("A volume target with UUID %(uuid)s already exists.")
222
+
223
+
224
+class VolumeTargetBootIndexAlreadyExists(Conflict):
225
+    _msg_fmt = _("A volume target with boot index '%(boot_index)s' "
226
+                 "for the same node already exists.")
227
+
228
+
220 229
 class InvalidUUID(Invalid):
221 230
     _msg_fmt = _("Expected a UUID but received %(uuid)s.")
222 231
 
@@ -372,6 +381,10 @@ class VolumeConnectorNotFound(NotFound):
372 381
     _msg_fmt = _("Volume connector %(connector)s could not be found.")
373 382
 
374 383
 
384
+class VolumeTargetNotFound(NotFound):
385
+    _msg_fmt = _("Volume target %(target)s could not be found.")
386
+
387
+
375 388
 class NoDriversLoaded(IronicException):
376 389
     _msg_fmt = _("Conductor %(conductor)s cannot be started "
377 390
                  "because no drivers were loaded.")

+ 103
- 2
ironic/db/api.py View File

@@ -183,9 +183,12 @@ class Connection(object):
183 183
 
184 184
     @abc.abstractmethod
185 185
     def destroy_node(self, node_id):
186
-        """Destroy a node and all associated interfaces.
186
+        """Destroy a node and its associated resources.
187 187
 
188
-        :param node_id: The id or uuid of a node.
188
+        Destroy a node, including any associated ports, port groups,
189
+        tags, volume connectors, and volume targets.
190
+
191
+        :param node_id: The ID or UUID of a node.
189 192
         """
190 193
 
191 194
     @abc.abstractmethod
@@ -687,6 +690,7 @@ class Connection(object):
687 690
         :raises: VolumeConnectorAlreadyExists If a volume connector with
688 691
                  the same UUID already exists.
689 692
         """
693
+
690 694
     @abc.abstractmethod
691 695
     def update_volume_connector(self, ident, connector_info):
692 696
         """Update properties of a volume connector.
@@ -712,3 +716,100 @@ class Connection(object):
712 716
         :raises: VolumeConnectorNotFound If a volume connector
713 717
                  with the specified ident does not exist.
714 718
         """
719
+
720
+    @abc.abstractmethod
721
+    def get_volume_target_list(self, limit=None, marker=None,
722
+                               sort_key=None, sort_dir=None):
723
+        """Return a list of volume targets.
724
+
725
+        :param limit: Maximum number of volume targets to return.
726
+        :param marker: the last item of the previous page; we return the next
727
+                       result set.
728
+        :param sort_key: Attribute by which results should be sorted.
729
+        :param sort_dir: direction in which results should be sorted.
730
+                         (asc, desc)
731
+        :returns: A list of volume targets.
732
+        :raises: InvalidParameterValue if sort_key does not exist.
733
+        """
734
+
735
+    @abc.abstractmethod
736
+    def get_volume_target_by_id(self, db_id):
737
+        """Return a volume target representation.
738
+
739
+        :param db_id: The database primary key (integer) ID of a volume target.
740
+        :returns: A volume target.
741
+        :raises: VolumeTargetNotFound if no volume target with this ID
742
+                 exists.
743
+        """
744
+
745
+    @abc.abstractmethod
746
+    def get_volume_target_by_uuid(self, uuid):
747
+        """Return a volume target representation.
748
+
749
+        :param uuid: The UUID of a volume target.
750
+        :returns: A volume target.
751
+        :raises: VolumeTargetNotFound if no volume target with this UUID
752
+                 exists.
753
+        """
754
+
755
+    @abc.abstractmethod
756
+    def get_volume_targets_by_node_id(self, node_id, limit=None,
757
+                                      marker=None, sort_key=None,
758
+                                      sort_dir=None):
759
+        """List all the volume targets for a given node.
760
+
761
+        :param node_id: The integer node ID.
762
+        :param limit: Maximum number of volume targets to return.
763
+        :param marker: the last item of the previous page; we return the next
764
+                       result set.
765
+        :param sort_key: Attribute by which results should be sorted
766
+        :param sort_dir: direction in which results should be sorted
767
+                         (asc, desc)
768
+        :returns: A list of volume targets.
769
+        :raises: InvalidParameterValue if sort_key does not exist.
770
+        """
771
+
772
+    @abc.abstractmethod
773
+    def create_volume_target(self, target_info):
774
+        """Create a new volume target.
775
+
776
+        :param target_info: Dictionary containing the information about the
777
+                            volume target. Example::
778
+
779
+                                   {
780
+                                       'uuid': '000000-..',
781
+                                       'node_id': 2,
782
+                                       'boot_index': 0,
783
+                                       'volume_id': '12345678-...'
784
+                                       'volume_type': 'some type',
785
+                                   }
786
+        :returns: A volume target.
787
+        :raises: VolumeTargetBootIndexAlreadyExists if a volume target already
788
+                 exists with the same boot index and node ID.
789
+        :raises: VolumeTargetAlreadyExists if a volume target with the same
790
+                 UUID exists.
791
+        """
792
+
793
+    @abc.abstractmethod
794
+    def update_volume_target(self, ident, target_info):
795
+        """Update information for a volume target.
796
+
797
+        :param ident: The UUID or integer ID of a volume target.
798
+        :param target_info: Dictionary containing the information about
799
+                            volume target to update.
800
+        :returns: A volume target.
801
+        :raises: InvalidParameterValue if a UUID is included in target_info.
802
+        :raises: VolumeTargetBootIndexAlreadyExists if a volume target already
803
+                 exists with the same boot index and node ID.
804
+        :raises: VolumeTargetNotFound if no volume target with this ident
805
+                 exists.
806
+        """
807
+
808
+    @abc.abstractmethod
809
+    def destroy_volume_target(self, ident):
810
+        """Destroy a volume target.
811
+
812
+        :param ident: The UUID or integer ID of a volume target.
813
+        :raises: VolumeTargetNotFound if a volume target with the specified
814
+                 ident does not exist.
815
+        """

+ 51
- 0
ironic/db/sqlalchemy/alembic/versions/1a59178ebdf6_add_volume_targets_table.py View File

@@ -0,0 +1,51 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+"""Add volume_targets table
14
+
15
+Revision ID: 1a59178ebdf6
16
+Revises: daa1ba02d98
17
+Create Date: 2016-02-25 11:25:29.836535
18
+
19
+"""
20
+
21
+# revision identifiers, used by Alembic.
22
+revision = '1a59178ebdf6'
23
+down_revision = 'daa1ba02d98'
24
+
25
+from alembic import op
26
+import sqlalchemy as sa
27
+
28
+
29
+def upgrade():
30
+    op.create_table('volume_targets',
31
+                    sa.Column('created_at', sa.DateTime(), nullable=True),
32
+                    sa.Column('updated_at', sa.DateTime(), nullable=True),
33
+                    sa.Column('id', sa.Integer(), nullable=False),
34
+                    sa.Column('uuid', sa.String(length=36), nullable=True),
35
+                    sa.Column('node_id', sa.Integer(), nullable=True),
36
+                    sa.Column('volume_type', sa.String(length=64),
37
+                              nullable=True),
38
+                    sa.Column('properties', sa.Text(), nullable=True),
39
+                    sa.Column('boot_index', sa.Integer(), nullable=True),
40
+                    sa.Column('volume_id',
41
+                              sa.String(length=36), nullable=True),
42
+                    sa.Column('extra', sa.Text(), nullable=True),
43
+                    sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ),
44
+                    sa.PrimaryKeyConstraint('id'),
45
+                    sa.UniqueConstraint('node_id', 'boot_index',
46
+                                        name='uniq_volumetargets0node_id0'
47
+                                             'boot_index'),
48
+                    sa.UniqueConstraint('uuid',
49
+                                        name='uniq_volumetargets0uuid'),
50
+                    mysql_charset='utf8',
51
+                    mysql_engine='InnoDB')

+ 75
- 0
ironic/db/sqlalchemy/api.py View File

@@ -386,6 +386,10 @@ class Connection(api.Connection):
386 386
                 models.VolumeConnector).filter_by(node_id=node_id)
387 387
             volume_connector_query.delete()
388 388
 
389
+            volume_target_query = model_query(
390
+                models.VolumeTarget).filter_by(node_id=node_id)
391
+            volume_target_query.delete()
392
+
389 393
             query.delete()
390 394
 
391 395
     def update_node(self, node_id, values):
@@ -952,3 +956,74 @@ class Connection(api.Connection):
952 956
             count = query.delete()
953 957
             if count == 0:
954 958
                 raise exception.VolumeConnectorNotFound(connector=ident)
959
+
960
+    def get_volume_target_list(self, limit=None, marker=None,
961
+                               sort_key=None, sort_dir=None):
962
+        return _paginate_query(models.VolumeTarget, limit, marker,
963
+                               sort_key, sort_dir)
964
+
965
+    def get_volume_target_by_id(self, db_id):
966
+        query = model_query(models.VolumeTarget).filter_by(id=db_id)
967
+        try:
968
+            return query.one()
969
+        except NoResultFound:
970
+            raise exception.VolumeTargetNotFound(target=db_id)
971
+
972
+    def get_volume_target_by_uuid(self, uuid):
973
+        query = model_query(models.VolumeTarget).filter_by(uuid=uuid)
974
+        try:
975
+            return query.one()
976
+        except NoResultFound:
977
+            raise exception.VolumeTargetNotFound(target=uuid)
978
+
979
+    def get_volume_targets_by_node_id(self, node_id, limit=None, marker=None,
980
+                                      sort_key=None, sort_dir=None):
981
+        query = model_query(models.VolumeTarget).filter_by(node_id=node_id)
982
+        return _paginate_query(models.VolumeTarget, limit, marker, sort_key,
983
+                               sort_dir, query)
984
+
985
+    def create_volume_target(self, target_info):
986
+        if 'uuid' not in target_info:
987
+            target_info['uuid'] = uuidutils.generate_uuid()
988
+
989
+        target = models.VolumeTarget()
990
+        target.update(target_info)
991
+        with _session_for_write() as session:
992
+            try:
993
+                session.add(target)
994
+                session.flush()
995
+            except db_exc.DBDuplicateEntry as exc:
996
+                if 'boot_index' in exc.columns:
997
+                    raise exception.VolumeTargetBootIndexAlreadyExists(
998
+                        boot_index=target_info['boot_index'])
999
+                raise exception.VolumeTargetAlreadyExists(
1000
+                    uuid=target_info['uuid'])
1001
+            return target
1002
+
1003
+    def update_volume_target(self, ident, target_info):
1004
+        if 'uuid' in target_info:
1005
+            msg = _("Cannot overwrite UUID for an existing Volume Target.")
1006
+            raise exception.InvalidParameterValue(err=msg)
1007
+
1008
+        try:
1009
+            with _session_for_write() as session:
1010
+                query = model_query(models.VolumeTarget)
1011
+                query = add_identity_filter(query, ident)
1012
+                ref = query.one()
1013
+                orig_boot_index = ref['boot_index']
1014
+                ref.update(target_info)
1015
+                session.flush()
1016
+        except db_exc.DBDuplicateEntry:
1017
+            raise exception.VolumeTargetBootIndexAlreadyExists(
1018
+                boot_index=target_info.get('boot_index', orig_boot_index))
1019
+        except NoResultFound:
1020
+            raise exception.VolumeTargetNotFound(target=ident)
1021
+        return ref
1022
+
1023
+    def destroy_volume_target(self, ident):
1024
+        with _session_for_write():
1025
+            query = model_query(models.VolumeTarget)
1026
+            query = add_identity_filter(query, ident)
1027
+            count = query.delete()
1028
+            if count == 0:
1029
+                raise exception.VolumeTargetNotFound(target=ident)

+ 20
- 0
ironic/db/sqlalchemy/models.py View File

@@ -229,3 +229,23 @@ class VolumeConnector(Base):
229 229
     type = Column(String(32))
230 230
     connector_id = Column(String(255))
231 231
     extra = Column(db_types.JsonEncodedDict)
232
+
233
+
234
+class VolumeTarget(Base):
235
+    """Represents a volume target of a bare metal node."""
236
+
237
+    __tablename__ = 'volume_targets'
238
+    __table_args__ = (
239
+        schema.UniqueConstraint('uuid', name='uniq_volumetargets0uuid'),
240
+        schema.UniqueConstraint('node_id',
241
+                                'boot_index',
242
+                                name='uniq_volumetargets0node_id0boot_index'),
243
+        table_args())
244
+    id = Column(Integer, primary_key=True)
245
+    uuid = Column(String(36))
246
+    node_id = Column(Integer, ForeignKey('nodes.id'), nullable=True)
247
+    volume_type = Column(String(64))
248
+    properties = Column(db_types.JsonEncodedDict)
249
+    boot_index = Column(Integer)
250
+    volume_id = Column(String(36))
251
+    extra = Column(db_types.JsonEncodedDict)

+ 29
- 0
ironic/tests/unit/db/sqlalchemy/test_migrations.py View File

@@ -585,6 +585,35 @@ class MigrationCheckersMixin(object):
585 585
         self.assertEqual(1, connector['node_id'])
586 586
         self.assertEqual('{}', connector['extra'])
587 587
 
588
+    def _check_1a59178ebdf6(self, engine, data):
589
+        targets = db_utils.get_table(engine, 'volume_targets')
590
+        col_names = [column.name for column in targets.c]
591
+        expected_names = ['created_at', 'updated_at', 'id', 'uuid', 'node_id',
592
+                          'boot_index', 'extra', 'properties', 'volume_type',
593
+                          'volume_id']
594
+        self.assertEqual(sorted(expected_names), sorted(col_names))
595
+
596
+        self.assertIsInstance(targets.c.created_at.type,
597
+                              sqlalchemy.types.DateTime)
598
+        self.assertIsInstance(targets.c.updated_at.type,
599
+                              sqlalchemy.types.DateTime)
600
+        self.assertIsInstance(targets.c.id.type,
601
+                              sqlalchemy.types.Integer)
602
+        self.assertIsInstance(targets.c.uuid.type,
603
+                              sqlalchemy.types.String)
604
+        self.assertIsInstance(targets.c.node_id.type,
605
+                              sqlalchemy.types.Integer)
606
+        self.assertIsInstance(targets.c.boot_index.type,
607
+                              sqlalchemy.types.Integer)
608
+        self.assertIsInstance(targets.c.extra.type,
609
+                              sqlalchemy.types.TEXT)
610
+        self.assertIsInstance(targets.c.properties.type,
611
+                              sqlalchemy.types.TEXT)
612
+        self.assertIsInstance(targets.c.volume_type.type,
613
+                              sqlalchemy.types.String)
614
+        self.assertIsInstance(targets.c.volume_id.type,
615
+                              sqlalchemy.types.String)
616
+
588 617
     def test_upgrade_and_version(self):
589 618
         with patch_with_engine(self.engine):
590 619
             self.migration_api.upgrade('head')

+ 20
- 0
ironic/tests/unit/db/test_nodes.py View File

@@ -379,6 +379,26 @@ class DbNodeTestCase(base.DbTestCase):
379 379
         self.assertRaises(exception.VolumeConnectorNotFound,
380 380
                           self.dbapi.get_volume_connector_by_id, connector.id)
381 381
 
382
+    def test_volume_target_gets_destroyed_after_destroying_a_node(self):
383
+        node = utils.create_test_node()
384
+
385
+        target = utils.create_test_volume_target(node_id=node.id)
386
+
387
+        self.dbapi.destroy_node(node.id)
388
+
389
+        self.assertRaises(exception.VolumeTargetNotFound,
390
+                          self.dbapi.get_volume_target_by_id, target.id)
391
+
392
+    def test_volume_target_gets_destroyed_after_destroying_a_node_uuid(self):
393
+        node = utils.create_test_node()
394
+
395
+        target = utils.create_test_volume_target(node_id=node.id)
396
+
397
+        self.dbapi.destroy_node(node.uuid)
398
+
399
+        self.assertRaises(exception.VolumeTargetNotFound,
400
+                          self.dbapi.get_volume_target_by_id, target.id)
401
+
382 402
     def test_update_node(self):
383 403
         node = utils.create_test_node()
384 404
 

+ 160
- 0
ironic/tests/unit/db/test_volume_targets.py View File

@@ -0,0 +1,160 @@
1
+# Copyright 2016 Hitachi, Ltc
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+
15
+"""Tests for manipulating VolumeTargets via the DB API"""
16
+
17
+from oslo_utils import uuidutils
18
+import six
19
+
20
+from ironic.common import exception
21
+from ironic.tests.unit.db import base
22
+from ironic.tests.unit.db import utils as db_utils
23
+
24
+
25
+class DbVolumeTargetTestCase(base.DbTestCase):
26
+
27
+    def setUp(self):
28
+        # This method creates a volume_target for every test.
29
+        super(DbVolumeTargetTestCase, self).setUp()
30
+        self.node = db_utils.create_test_node()
31
+        self.target = db_utils.create_test_volume_target(node_id=self.node.id)
32
+
33
+    def test_create_volume_target(self):
34
+        info = {'uuid': uuidutils.generate_uuid(),
35
+                'node_id': self.node.id,
36
+                'boot_index': 1,
37
+                'volume_type': 'iscsi',
38
+                'volume_id': '12345678'}
39
+
40
+        target = self.dbapi.create_volume_target(info)
41
+        self.assertEqual(info['uuid'], target.uuid)
42
+        self.assertEqual(info['node_id'], target.node_id)
43
+        self.assertEqual(info['boot_index'], target.boot_index)
44
+        self.assertEqual(info['volume_type'], target.volume_type)
45
+        self.assertEqual(info['volume_id'], target.volume_id)
46
+        self.assertIsNone(target.properties)
47
+        self.assertIsNone(target.extra)
48
+
49
+    def test_create_volume_target_duplicated_nodeid_and_bootindex(self):
50
+        self.assertRaises(exception.VolumeTargetBootIndexAlreadyExists,
51
+                          db_utils.create_test_volume_target,
52
+                          uuid=uuidutils.generate_uuid(),
53
+                          node_id=self.target.node_id,
54
+                          boot_index=self.target.boot_index)
55
+
56
+    def test_create_volume_target_duplicated_uuid(self):
57
+        self.assertRaises(exception.VolumeTargetAlreadyExists,
58
+                          db_utils.create_test_volume_target,
59
+                          uuid=self.target.uuid,
60
+                          node_id=self.node.id,
61
+                          boot_index=100)
62
+
63
+    def test_get_volume_target_by_id(self):
64
+        res = self.dbapi.get_volume_target_by_id(self.target.id)
65
+        self.assertEqual(self.target.volume_type, res.volume_type)
66
+        self.assertEqual(self.target.properties, res.properties)
67
+        self.assertEqual(self.target.boot_index, res.boot_index)
68
+
69
+        self.assertRaises(exception.VolumeTargetNotFound,
70
+                          self.dbapi.get_volume_target_by_id,
71
+                          100)
72
+
73
+    def test_get_volume_target_by_uuid(self):
74
+        res = self.dbapi.get_volume_target_by_uuid(self.target.uuid)
75
+        self.assertEqual(self.target.id, res.id)
76
+
77
+        self.assertRaises(exception.VolumeTargetNotFound,
78
+                          self.dbapi.get_volume_target_by_uuid,
79
+                          '11111111-2222-3333-4444-555555555555')
80
+
81
+    def _create_list_of_volume_targets(self, num):
82
+        uuids = [six.text_type(self.target.uuid)]
83
+        for i in range(1, num):
84
+            volume_target = db_utils.create_test_volume_target(
85
+                uuid=uuidutils.generate_uuid(),
86
+                properties={"target_iqn": "iqn.test-%s" % i},
87
+                boot_index=i)
88
+            uuids.append(six.text_type(volume_target.uuid))
89
+        return uuids
90
+
91
+    def test_get_volume_target_list(self):
92
+        uuids = self._create_list_of_volume_targets(6)
93
+        res = self.dbapi.get_volume_target_list()
94
+        res_uuids = [r.uuid for r in res]
95
+        six.assertCountEqual(self, uuids, res_uuids)
96
+
97
+    def test_get_volume_target_list_sorted(self):
98
+        uuids = self._create_list_of_volume_targets(5)
99
+        res = self.dbapi.get_volume_target_list(sort_key='uuid')
100
+        res_uuids = [r.uuid for r in res]
101
+        self.assertEqual(sorted(uuids), res_uuids)
102
+
103
+        self.assertRaises(exception.InvalidParameterValue,
104
+                          self.dbapi.get_volume_target_list, sort_key='foo')
105
+
106
+    def test_get_volume_targets_by_node_id(self):
107
+        node2 = db_utils.create_test_node(uuid=uuidutils.generate_uuid())
108
+        target2 = db_utils.create_test_volume_target(
109
+            uuid=uuidutils.generate_uuid(), node_id=node2.id)
110
+        self._create_list_of_volume_targets(2)
111
+        res = self.dbapi.get_volume_targets_by_node_id(node2.id)
112
+        self.assertEqual(1, len(res))
113
+        self.assertEqual(target2.uuid, res[0].uuid)
114
+
115
+    def test_get_volume_targets_by_node_id_that_does_not_exist(self):
116
+        self.assertEqual([], self.dbapi.get_volume_targets_by_node_id(99))
117
+
118
+    def test_update_volume_target(self):
119
+        old_boot_index = self.target.boot_index
120
+        new_boot_index = old_boot_index + 1
121
+
122
+        res = self.dbapi.update_volume_target(self.target.id,
123
+                                              {'boot_index': new_boot_index})
124
+        self.assertEqual(new_boot_index, res.boot_index)
125
+
126
+        res = self.dbapi.update_volume_target(self.target.id,
127
+                                              {'boot_index': old_boot_index})
128
+        self.assertEqual(old_boot_index, res.boot_index)
129
+
130
+    def test_update_volume_target_uuid(self):
131
+        self.assertRaises(exception.InvalidParameterValue,
132
+                          self.dbapi.update_volume_target,
133
+                          self.target.id,
134
+                          {'uuid': uuidutils.generate_uuid()})
135
+
136
+    def test_update_volume_target_fails_invalid_id(self):
137
+        self.assertRaises(exception.VolumeTargetNotFound,
138
+                          self.dbapi.update_volume_target,
139
+                          99,
140
+                          {'boot_index': 6})
141
+
142
+    def test_update_volume_target_duplicated_nodeid_and_bootindex(self):
143
+        t = db_utils.create_test_volume_target(uuid=uuidutils.generate_uuid(),
144
+                                               boot_index=1)
145
+        self.assertRaises(exception.VolumeTargetBootIndexAlreadyExists,
146
+                          self.dbapi.update_volume_target,
147
+                          t.uuid,
148
+                          {'boot_index': self.target.boot_index,
149
+                           'node_id': self.target.node_id})
150
+
151
+    def test_destroy_volume_target(self):
152
+        self.dbapi.destroy_volume_target(self.target.id)
153
+        self.assertRaises(exception.VolumeTargetNotFound,
154
+                          self.dbapi.get_volume_target_by_id,
155
+                          self.target.id)
156
+
157
+        # Ensure that destroy_volume_target returns the expected exception.
158
+        self.assertRaises(exception.VolumeTargetNotFound,
159
+                          self.dbapi.destroy_volume_target,
160
+                          self.target.id)

+ 33
- 0
ironic/tests/unit/db/utils.py View File

@@ -346,6 +346,39 @@ def create_test_volume_connector(**kw):
346 346
     return dbapi.create_volume_connector(connector)
347 347
 
348 348
 
349
+def get_test_volume_target(**kw):
350
+    fake_properties = {"target_iqn": "iqn.foo"}
351
+    return {
352
+        'id': kw.get('id', 789),
353
+        'uuid': kw.get('uuid', '1be26c0b-03f2-4d2e-ae87-c02d7f33c781'),
354
+        'node_id': kw.get('node_id', 123),
355
+        'volume_type': kw.get('volume_type', 'iscsi'),
356
+        'properties': kw.get('properties', fake_properties),
357
+        'boot_index': kw.get('boot_index', 0),
358
+        'volume_id': kw.get('volume_id', '12345678'),
359
+        'extra': kw.get('extra', {}),
360
+        'created_at': kw.get('created_at'),
361
+        'updated_at': kw.get('updated_at'),
362
+    }
363
+
364
+
365
+def create_test_volume_target(**kw):
366
+    """Create test target entry in DB and return VolumeTarget DB object.
367
+
368
+    Function to be used to create test VolumeTarget objects in the database.
369
+
370
+    :param kw: kwargs with overriding values for target's attributes.
371
+    :returns: Test VolumeTarget DB object.
372
+
373
+    """
374
+    target = get_test_volume_target(**kw)
375
+    # Let DB generate ID if it isn't specified explicitly
376
+    if 'id' not in kw:
377
+        del target['id']
378
+    dbapi = db_api.get_instance()
379
+    return dbapi.create_volume_target(target)
380
+
381
+
349 382
 def get_test_chassis(**kw):
350 383
     return {
351 384
         'id': kw.get('id', 42),

Loading…
Cancel
Save