Browse Source

Enhance boot from volume

Attached volumes already had support for explicit volume type,
availability zone, and instance locality. Extend this capability to
boot volumes.

(For posterity's sake, a summary of why other options related to
attached volumes were not in fact appropriate for boot volumes:
- volumes_per_node: there can only be one boot volume
- volumes_size: boot volume size given by flavor
- volume_mount_prefix: boot volume handled differently)

Change-Id: I009c0da4179c880fd87a7c1903c93825e8997a38
Story: 2004507
Task: 28229
Jeremy Freudberg 3 months ago
parent
commit
359b89de3f

+ 6
- 0
releasenotes/notes/enhance-bfv-12bac06c4438675f.yaml View File

@@ -0,0 +1,6 @@
1
+---
2
+features:
3
+  - In Sahara APIv2, the type, availability zone, and locality of boot volumes
4
+    may be expressed explicitly through the `boot_volume_type`,
5
+    `boot_volume_availability_zone`, and `boot_volume_local_to_instance`
6
+    parameters.

+ 3
- 0
sahara/conductor/manager.py View File

@@ -51,6 +51,9 @@ NODE_GROUP_DEFAULTS = {
51 51
     "volume_mount_prefix": "/volumes/disk",
52 52
     "volume_type": None,
53 53
     "boot_from_volume": False,
54
+    "boot_volume_type": None,
55
+    "boot_volume_availability_zone": None,
56
+    "boot_volume_local_to_instance": False,
54 57
     "floating_ip_pool": None,
55 58
     "security_groups": None,
56 59
     "auto_security_group": False,

+ 9
- 0
sahara/conductor/objects.py View File

@@ -112,6 +112,12 @@ class NodeGroup(object):
112 112
     volume_type
113 113
     boot_from_volume - If set to True, the base image will be converted to a
114 114
                        bootable volume.
115
+    boot_volume_type
116
+    boot_volume_availability_zone - name of Cinder availability zone for
117
+                                    spawning bootable volume.
118
+    boot_volume_local_to_instance - indicates if boot volume and instance
119
+                                    should be c reated on the same physical
120
+                                    host.
115 121
     floating_ip_pool - Floating IP Pool name used to assign Floating IPs to
116 122
                        instances in this Node Group
117 123
     security_groups - List of security groups for instances in this Node Group
@@ -234,6 +240,9 @@ class NodeGroupTemplate(object):
234 240
     volume_mount_prefix
235 241
     volume_type
236 242
     boot_from_volume
243
+    boot_volume_type
244
+    boot_volume_availability_zone
245
+    boot_volume_local_to_instance
237 246
     floating_ip_pool
238 247
     security_groups
239 248
     auto_security_group

+ 70
- 0
sahara/db/migration/alembic_migrations/versions/035_boot_from_volume_enhancements.py View File

@@ -0,0 +1,70 @@
1
+# Copyright 2019 OpenStack Foundation.
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain 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,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+# implied.
13
+# See the License for the specific language governing permissions and
14
+# limitations under the License.
15
+
16
+"""boot from volume enhancements
17
+
18
+Revision ID: 035
19
+Revises: 034
20
+Create Date: 2019-01-07 19:55:54.025736
21
+
22
+"""
23
+
24
+# revision identifiers, used by Alembic.
25
+revision = '035'
26
+down_revision = '034'
27
+
28
+from alembic import op
29
+import sqlalchemy as sa
30
+
31
+
32
+def upgrade():
33
+    op.add_column('node_group_templates',
34
+                  sa.Column('boot_volume_availability_zone',
35
+                            sa.String(length=255),
36
+                            nullable=True))
37
+    op.add_column('node_group_templates',
38
+                  sa.Column('boot_volume_local_to_instance',
39
+                            sa.Boolean(),
40
+                            nullable=True))
41
+    op.add_column('node_group_templates',
42
+                  sa.Column('boot_volume_type',
43
+                            sa.String(length=255),
44
+                            nullable=True))
45
+
46
+    op.add_column('node_groups',
47
+                  sa.Column('boot_volume_availability_zone',
48
+                            sa.String(length=255),
49
+                            nullable=True))
50
+    op.add_column('node_groups',
51
+                  sa.Column('boot_volume_local_to_instance',
52
+                            sa.Boolean(),
53
+                            nullable=True))
54
+    op.add_column('node_groups',
55
+                  sa.Column('boot_volume_type',
56
+                            sa.String(length=255),
57
+                            nullable=True))
58
+
59
+    op.add_column('templates_relations',
60
+                  sa.Column('boot_volume_availability_zone',
61
+                            sa.String(length=255),
62
+                            nullable=True))
63
+    op.add_column('templates_relations',
64
+                  sa.Column('boot_volume_local_to_instance',
65
+                            sa.Boolean(),
66
+                            nullable=True))
67
+    op.add_column('templates_relations',
68
+                  sa.Column('boot_volume_type',
69
+                            sa.String(length=255),
70
+                            nullable=True))

+ 9
- 0
sahara/db/sqlalchemy/models.py View File

@@ -118,6 +118,9 @@ class NodeGroup(mb.SaharaBase):
118 118
     volume_mount_prefix = sa.Column(sa.String(80))
119 119
     volume_type = sa.Column(sa.String(255))
120 120
     boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
121
+    boot_volume_type = sa.Column(sa.String(255))
122
+    boot_volume_availability_zone = sa.Column(sa.String(255))
123
+    boot_volume_local_to_instance = sa.Column(sa.Boolean())
121 124
     count = sa.Column(sa.Integer, nullable=False)
122 125
     use_autoconfig = sa.Column(sa.Boolean(), default=True)
123 126
 
@@ -230,6 +233,9 @@ class NodeGroupTemplate(mb.SaharaBase):
230 233
     volume_mount_prefix = sa.Column(sa.String(80))
231 234
     volume_type = sa.Column(sa.String(255))
232 235
     boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
236
+    boot_volume_type = sa.Column(sa.String(255))
237
+    boot_volume_availability_zone = sa.Column(sa.String(255))
238
+    boot_volume_local_to_instance = sa.Column(sa.Boolean())
233 239
     floating_ip_pool = sa.Column(sa.String(36))
234 240
     security_groups = sa.Column(st.JsonListType())
235 241
     auto_security_group = sa.Column(sa.Boolean())
@@ -264,6 +270,9 @@ class TemplatesRelation(mb.SaharaBase):
264 270
     volume_mount_prefix = sa.Column(sa.String(80))
265 271
     volume_type = sa.Column(sa.String(255))
266 272
     boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
273
+    boot_volume_type = sa.Column(sa.String(255))
274
+    boot_volume_availability_zone = sa.Column(sa.String(255))
275
+    boot_volume_local_to_instance = sa.Column(sa.Boolean())
267 276
     count = sa.Column(sa.Integer, nullable=False)
268 277
     use_autoconfig = sa.Column(sa.Boolean(), default=True)
269 278
     cluster_template_id = sa.Column(sa.String(36),

+ 17
- 4
sahara/service/heat/templates.py View File

@@ -544,13 +544,26 @@ class ClusterStack(object):
544 544
         node_group_flavor = nova.get_flavor(id=node_group.flavor_id)
545 545
         image_size = node_group_flavor.disk
546 546
 
547
+        properties = {}
548
+        properties["size"] = image_size
549
+        properties["image"] = node_group.get_image_id()
550
+
551
+        if node_group.boot_volume_type:
552
+            properties["volume_type"] = node_group.boot_volume_type
553
+
554
+        if node_group.boot_volume_availability_zone:
555
+            properties["availability_zone"] = (
556
+                node_group.boot_volume_availability_zone
557
+            )
558
+
559
+        if node_group.boot_volume_local_to_instance:
560
+            properties["scheduler_hints"] = {
561
+                "local_to_instance": {"get_param": "instance"}}
562
+
547 563
         return {
548 564
             "bootable_volume": {
549 565
                 "type": "OS::Cinder::Volume",
550
-                "properties": {
551
-                    "size": image_size,
552
-                    "image": node_group.get_image_id()
553
-                }
566
+                "properties": properties
554 567
             }
555 568
         }
556 569
 

+ 9
- 0
sahara/service/validations/node_group_template_schema.py View File

@@ -122,6 +122,15 @@ NODE_GROUP_TEMPLATE_SCHEMA_V2["required"].append("plugin_version")
122 122
 NODE_GROUP_TEMPLATE_SCHEMA_V2["properties"].update({
123 123
     "boot_from_volume": {
124 124
         "type": "boolean",
125
+    },
126
+    "boot_volume_type": {
127
+        "type": "string",
128
+    },
129
+    "boot_volume_availability_zone": {
130
+        "type": "string",
131
+    },
132
+    "boot_volume_local_to_instance": {
133
+        "type": "boolean",
125 134
     }})
126 135
 
127 136
 

+ 3
- 0
sahara/tests/unit/conductor/manager/test_clusters.py View File

@@ -133,6 +133,9 @@ class ClusterTest(test_base.ConductorManagerTestCase):
133 133
             ng.pop("volume_type")
134 134
             ng.pop("floating_ip_pool")
135 135
             ng.pop("boot_from_volume")
136
+            ng.pop("boot_volume_type")
137
+            ng.pop("boot_volume_availability_zone")
138
+            ng.pop("boot_volume_local_to_instance")
136 139
             ng.pop("image_username")
137 140
             ng.pop("open_ports")
138 141
             ng.pop("auto_security_group")

+ 3
- 0
sahara/tests/unit/conductor/manager/test_templates.py View File

@@ -459,6 +459,9 @@ class ClusterTemplates(test_base.ConductorManagerTestCase):
459 459
             ng.pop("auto_security_group")
460 460
             ng.pop("is_proxy_gateway")
461 461
             ng.pop("boot_from_volume")
462
+            ng.pop("boot_volume_type")
463
+            ng.pop("boot_volume_availability_zone")
464
+            ng.pop("boot_volume_local_to_instance")
462 465
             ng.pop('volume_local_to_instance')
463 466
 
464 467
         self.assertEqual(SAMPLE_CLT["node_groups"],

+ 8
- 0
sahara/tests/unit/db/migration/test_migrations.py View File

@@ -634,6 +634,14 @@ class SaharaMigrationsCheckers(object):
634 634
         self.assertColumnExists(engine, 'templates_relations',
635 635
                                 'boot_from_volume')
636 636
 
637
+    def _check_035(self, engine, data):
638
+        for col in ['boot_volume_type',
639
+                    'boot_volume_availability_zone',
640
+                    'boot_volume_local_to_instance']:
641
+            self.assertColumnExists(engine, 'node_groups', col)
642
+            self.assertColumnExists(engine, 'node_group_templates', col)
643
+            self.assertColumnExists(engine, 'templates_relations', col)
644
+
637 645
 
638 646
 class TestMigrationsMySQL(SaharaMigrationsCheckers,
639 647
                           base.BaseWalkMigrationTestCase,

Loading…
Cancel
Save