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
This commit is contained in:
parent
0b8002a99d
commit
359b89de3f
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- In Sahara APIv2, the type, availability zone, and locality of boot volumes
|
||||||
|
may be expressed explicitly through the `boot_volume_type`,
|
||||||
|
`boot_volume_availability_zone`, and `boot_volume_local_to_instance`
|
||||||
|
parameters.
|
|
@ -51,6 +51,9 @@ NODE_GROUP_DEFAULTS = {
|
||||||
"volume_mount_prefix": "/volumes/disk",
|
"volume_mount_prefix": "/volumes/disk",
|
||||||
"volume_type": None,
|
"volume_type": None,
|
||||||
"boot_from_volume": False,
|
"boot_from_volume": False,
|
||||||
|
"boot_volume_type": None,
|
||||||
|
"boot_volume_availability_zone": None,
|
||||||
|
"boot_volume_local_to_instance": False,
|
||||||
"floating_ip_pool": None,
|
"floating_ip_pool": None,
|
||||||
"security_groups": None,
|
"security_groups": None,
|
||||||
"auto_security_group": False,
|
"auto_security_group": False,
|
||||||
|
|
|
@ -112,6 +112,12 @@ class NodeGroup(object):
|
||||||
volume_type
|
volume_type
|
||||||
boot_from_volume - If set to True, the base image will be converted to a
|
boot_from_volume - If set to True, the base image will be converted to a
|
||||||
bootable volume.
|
bootable volume.
|
||||||
|
boot_volume_type
|
||||||
|
boot_volume_availability_zone - name of Cinder availability zone for
|
||||||
|
spawning bootable volume.
|
||||||
|
boot_volume_local_to_instance - indicates if boot volume and instance
|
||||||
|
should be c reated on the same physical
|
||||||
|
host.
|
||||||
floating_ip_pool - Floating IP Pool name used to assign Floating IPs to
|
floating_ip_pool - Floating IP Pool name used to assign Floating IPs to
|
||||||
instances in this Node Group
|
instances in this Node Group
|
||||||
security_groups - List of security groups for instances in this Node Group
|
security_groups - List of security groups for instances in this Node Group
|
||||||
|
@ -234,6 +240,9 @@ class NodeGroupTemplate(object):
|
||||||
volume_mount_prefix
|
volume_mount_prefix
|
||||||
volume_type
|
volume_type
|
||||||
boot_from_volume
|
boot_from_volume
|
||||||
|
boot_volume_type
|
||||||
|
boot_volume_availability_zone
|
||||||
|
boot_volume_local_to_instance
|
||||||
floating_ip_pool
|
floating_ip_pool
|
||||||
security_groups
|
security_groups
|
||||||
auto_security_group
|
auto_security_group
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Copyright 2019 OpenStack Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""boot from volume enhancements
|
||||||
|
|
||||||
|
Revision ID: 035
|
||||||
|
Revises: 034
|
||||||
|
Create Date: 2019-01-07 19:55:54.025736
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '035'
|
||||||
|
down_revision = '034'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('node_group_templates',
|
||||||
|
sa.Column('boot_volume_availability_zone',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True))
|
||||||
|
op.add_column('node_group_templates',
|
||||||
|
sa.Column('boot_volume_local_to_instance',
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True))
|
||||||
|
op.add_column('node_group_templates',
|
||||||
|
sa.Column('boot_volume_type',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True))
|
||||||
|
|
||||||
|
op.add_column('node_groups',
|
||||||
|
sa.Column('boot_volume_availability_zone',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True))
|
||||||
|
op.add_column('node_groups',
|
||||||
|
sa.Column('boot_volume_local_to_instance',
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True))
|
||||||
|
op.add_column('node_groups',
|
||||||
|
sa.Column('boot_volume_type',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True))
|
||||||
|
|
||||||
|
op.add_column('templates_relations',
|
||||||
|
sa.Column('boot_volume_availability_zone',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True))
|
||||||
|
op.add_column('templates_relations',
|
||||||
|
sa.Column('boot_volume_local_to_instance',
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True))
|
||||||
|
op.add_column('templates_relations',
|
||||||
|
sa.Column('boot_volume_type',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True))
|
|
@ -118,6 +118,9 @@ class NodeGroup(mb.SaharaBase):
|
||||||
volume_mount_prefix = sa.Column(sa.String(80))
|
volume_mount_prefix = sa.Column(sa.String(80))
|
||||||
volume_type = sa.Column(sa.String(255))
|
volume_type = sa.Column(sa.String(255))
|
||||||
boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
|
boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
|
||||||
|
boot_volume_type = sa.Column(sa.String(255))
|
||||||
|
boot_volume_availability_zone = sa.Column(sa.String(255))
|
||||||
|
boot_volume_local_to_instance = sa.Column(sa.Boolean())
|
||||||
count = sa.Column(sa.Integer, nullable=False)
|
count = sa.Column(sa.Integer, nullable=False)
|
||||||
use_autoconfig = sa.Column(sa.Boolean(), default=True)
|
use_autoconfig = sa.Column(sa.Boolean(), default=True)
|
||||||
|
|
||||||
|
@ -230,6 +233,9 @@ class NodeGroupTemplate(mb.SaharaBase):
|
||||||
volume_mount_prefix = sa.Column(sa.String(80))
|
volume_mount_prefix = sa.Column(sa.String(80))
|
||||||
volume_type = sa.Column(sa.String(255))
|
volume_type = sa.Column(sa.String(255))
|
||||||
boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
|
boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
|
||||||
|
boot_volume_type = sa.Column(sa.String(255))
|
||||||
|
boot_volume_availability_zone = sa.Column(sa.String(255))
|
||||||
|
boot_volume_local_to_instance = sa.Column(sa.Boolean())
|
||||||
floating_ip_pool = sa.Column(sa.String(36))
|
floating_ip_pool = sa.Column(sa.String(36))
|
||||||
security_groups = sa.Column(st.JsonListType())
|
security_groups = sa.Column(st.JsonListType())
|
||||||
auto_security_group = sa.Column(sa.Boolean())
|
auto_security_group = sa.Column(sa.Boolean())
|
||||||
|
@ -264,6 +270,9 @@ class TemplatesRelation(mb.SaharaBase):
|
||||||
volume_mount_prefix = sa.Column(sa.String(80))
|
volume_mount_prefix = sa.Column(sa.String(80))
|
||||||
volume_type = sa.Column(sa.String(255))
|
volume_type = sa.Column(sa.String(255))
|
||||||
boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
|
boot_from_volume = sa.Column(sa.Boolean(), default=False, nullable=False)
|
||||||
|
boot_volume_type = sa.Column(sa.String(255))
|
||||||
|
boot_volume_availability_zone = sa.Column(sa.String(255))
|
||||||
|
boot_volume_local_to_instance = sa.Column(sa.Boolean())
|
||||||
count = sa.Column(sa.Integer, nullable=False)
|
count = sa.Column(sa.Integer, nullable=False)
|
||||||
use_autoconfig = sa.Column(sa.Boolean(), default=True)
|
use_autoconfig = sa.Column(sa.Boolean(), default=True)
|
||||||
cluster_template_id = sa.Column(sa.String(36),
|
cluster_template_id = sa.Column(sa.String(36),
|
||||||
|
|
|
@ -544,13 +544,26 @@ class ClusterStack(object):
|
||||||
node_group_flavor = nova.get_flavor(id=node_group.flavor_id)
|
node_group_flavor = nova.get_flavor(id=node_group.flavor_id)
|
||||||
image_size = node_group_flavor.disk
|
image_size = node_group_flavor.disk
|
||||||
|
|
||||||
|
properties = {}
|
||||||
|
properties["size"] = image_size
|
||||||
|
properties["image"] = node_group.get_image_id()
|
||||||
|
|
||||||
|
if node_group.boot_volume_type:
|
||||||
|
properties["volume_type"] = node_group.boot_volume_type
|
||||||
|
|
||||||
|
if node_group.boot_volume_availability_zone:
|
||||||
|
properties["availability_zone"] = (
|
||||||
|
node_group.boot_volume_availability_zone
|
||||||
|
)
|
||||||
|
|
||||||
|
if node_group.boot_volume_local_to_instance:
|
||||||
|
properties["scheduler_hints"] = {
|
||||||
|
"local_to_instance": {"get_param": "instance"}}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"bootable_volume": {
|
"bootable_volume": {
|
||||||
"type": "OS::Cinder::Volume",
|
"type": "OS::Cinder::Volume",
|
||||||
"properties": {
|
"properties": properties
|
||||||
"size": image_size,
|
|
||||||
"image": node_group.get_image_id()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,15 @@ NODE_GROUP_TEMPLATE_SCHEMA_V2["required"].append("plugin_version")
|
||||||
NODE_GROUP_TEMPLATE_SCHEMA_V2["properties"].update({
|
NODE_GROUP_TEMPLATE_SCHEMA_V2["properties"].update({
|
||||||
"boot_from_volume": {
|
"boot_from_volume": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"boot_volume_type": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"boot_volume_availability_zone": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"boot_volume_local_to_instance": {
|
||||||
|
"type": "boolean",
|
||||||
}})
|
}})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,9 @@ class ClusterTest(test_base.ConductorManagerTestCase):
|
||||||
ng.pop("volume_type")
|
ng.pop("volume_type")
|
||||||
ng.pop("floating_ip_pool")
|
ng.pop("floating_ip_pool")
|
||||||
ng.pop("boot_from_volume")
|
ng.pop("boot_from_volume")
|
||||||
|
ng.pop("boot_volume_type")
|
||||||
|
ng.pop("boot_volume_availability_zone")
|
||||||
|
ng.pop("boot_volume_local_to_instance")
|
||||||
ng.pop("image_username")
|
ng.pop("image_username")
|
||||||
ng.pop("open_ports")
|
ng.pop("open_ports")
|
||||||
ng.pop("auto_security_group")
|
ng.pop("auto_security_group")
|
||||||
|
|
|
@ -459,6 +459,9 @@ class ClusterTemplates(test_base.ConductorManagerTestCase):
|
||||||
ng.pop("auto_security_group")
|
ng.pop("auto_security_group")
|
||||||
ng.pop("is_proxy_gateway")
|
ng.pop("is_proxy_gateway")
|
||||||
ng.pop("boot_from_volume")
|
ng.pop("boot_from_volume")
|
||||||
|
ng.pop("boot_volume_type")
|
||||||
|
ng.pop("boot_volume_availability_zone")
|
||||||
|
ng.pop("boot_volume_local_to_instance")
|
||||||
ng.pop('volume_local_to_instance')
|
ng.pop('volume_local_to_instance')
|
||||||
|
|
||||||
self.assertEqual(SAMPLE_CLT["node_groups"],
|
self.assertEqual(SAMPLE_CLT["node_groups"],
|
||||||
|
|
|
@ -634,6 +634,14 @@ class SaharaMigrationsCheckers(object):
|
||||||
self.assertColumnExists(engine, 'templates_relations',
|
self.assertColumnExists(engine, 'templates_relations',
|
||||||
'boot_from_volume')
|
'boot_from_volume')
|
||||||
|
|
||||||
|
def _check_035(self, engine, data):
|
||||||
|
for col in ['boot_volume_type',
|
||||||
|
'boot_volume_availability_zone',
|
||||||
|
'boot_volume_local_to_instance']:
|
||||||
|
self.assertColumnExists(engine, 'node_groups', col)
|
||||||
|
self.assertColumnExists(engine, 'node_group_templates', col)
|
||||||
|
self.assertColumnExists(engine, 'templates_relations', col)
|
||||||
|
|
||||||
|
|
||||||
class TestMigrationsMySQL(SaharaMigrationsCheckers,
|
class TestMigrationsMySQL(SaharaMigrationsCheckers,
|
||||||
base.BaseWalkMigrationTestCase,
|
base.BaseWalkMigrationTestCase,
|
||||||
|
|
Loading…
Reference in New Issue