Enable setting blocksize on volumes.

Some back-ends support blocksizes other than the default 512 (like 4096),
this change adds a provider_geometry column to the volumes table,
format is "physical_block_size logical_block_size".

This can then be used by libvirt to determine if it should pass in
non-default block_size info, and there's a method for future
geometry/disk info that might be needed.

Fixes bug: 1196248

Change-Id: I8d40bc56403154fbe955cd4ccf8f0c55fc9eb7c5
This commit is contained in:
John Griffith 2013-07-10 15:34:26 -06:00
parent 2f5e26a247
commit 67078ab932
7 changed files with 177 additions and 4 deletions

View File

@ -0,0 +1,37 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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.
from sqlalchemy import Column
from sqlalchemy import MetaData, String, Table
def upgrade(migrate_engine):
"""Add provider_geometry column to volumes."""
meta = MetaData()
meta.bind = migrate_engine
volumes = Table('volumes', meta, autoload=True)
provider_geometry = Column('provider_geometry', String(255))
volumes.create_column(provider_geometry)
volumes.update().values(provider_geometry=None).execute()
def downgrade(migrate_engine):
"""Remove provider_geometry column from volumes."""
meta = MetaData()
meta.bind = migrate_engine
volumes = Table('volumes', meta, autoload=True)
provider_geometry = Column('provider_geometry', String(255))
volumes.drop_column(provider_geometry)

View File

@ -0,0 +1,68 @@
BEGIN TRANSACTION;
CREATE TABLE volumes_v12 (
created_at DATETIME,
updated_at DATETIME,
deleted_at DATETIME,
deleted BOOLEAN,
id VARCHAR(36) NOT NULL,
ec2_id INTEGER,
user_id VARCHAR(255),
project_id VARCHAR(255),
snapshot_id VARCHAR(36),
host VARCHAR(255),
size INTEGER,
availability_zone VARCHAR(255),
instance_uuid VARCHAR(36),
mountpoint VARCHAR(255),
attach_time VARCHAR(255),
status VARCHAR(255),
attach_status VARCHAR(255),
scheduled_at DATETIME,
launched_at DATETIME,
terminated_at DATETIME,
display_name VARCHAR(255),
display_description VARCHAR(255),
provider_location VARCHAR(255),
provider_auth VARCHAR(255),
volume_type_id VARCHAR(36),
source_volid VARCHAR(36),
bootable BOOLEAN,
attached_host VARCHAR(255),
PRIMARY KEY (id)
);
INSERT INTO volumes_v12
SELECT created_at,
updated_at,
deleted_at,
deleted,
id,
ec2_id,
user_id,
project_id,
snapshot_id,
host,
size,
availability_zone,
instance_uuid,
mountpoint,
attach_time,
status,
attach_status,
scheduled_at,
launched_at,
terminated_at,
display_name,
display_description,
provider_location,
provider_auth,
volume_type_id,
source_volid,
bootable,
attached_host
FROM volumes;
DROP TABLE volumes;
ALTER TABLE volumes_v12 RENAME TO volumes;
COMMIT;

View File

@ -111,6 +111,7 @@ class Volume(BASE, CinderBase):
provider_location = Column(String(255))
provider_auth = Column(String(255))
provider_geometry = Column(String(255))
volume_type_id = Column(String(36))
source_volid = Column(String(36))

View File

@ -747,3 +747,29 @@ class TestMigrations(test.TestCase):
metadata,
autoload=True)
self.assertTrue('attached_host' not in volumes.c)
def test_migration_013(self):
"""Test that adding provider_geometry column works correctly."""
for (key, engine) in self.engines.items():
migration_api.version_control(engine,
TestMigrations.REPOSITORY,
migration.INIT_VERSION)
migration_api.upgrade(engine, TestMigrations.REPOSITORY, 12)
metadata = sqlalchemy.schema.MetaData()
metadata.bind = engine
migration_api.upgrade(engine, TestMigrations.REPOSITORY, 13)
volumes = sqlalchemy.Table('volumes',
metadata,
autoload=True)
self.assertTrue(isinstance(volumes.c.provider_geometry.type,
sqlalchemy.types.VARCHAR))
migration_api.downgrade(engine, TestMigrations.REPOSITORY, 12)
metadata = sqlalchemy.schema.MetaData()
metadata.bind = engine
volumes = sqlalchemy.Table('volumes',
metadata,
autoload=True)
self.assertTrue('provider_geometry' not in volumes.c)

View File

@ -16,10 +16,6 @@
# under the License.
import mox
from mox import IgnoreArg
from mox import IsA
from mox import stubout
from cinder import exception
from cinder.openstack.common import log as logging
@ -160,6 +156,42 @@ class SolidFireVolumeTestCase(test.TestCase):
sfv = SolidFire(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
self.assertNotEqual(model_update, None)
self.assertEqual(model_update.get('provider_geometry', None), None)
def test_create_volume_non_512(self):
self.stubs.Set(SolidFire, '_issue_api_request',
self.fake_issue_api_request)
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'volume_type_id': None}
self.configuration.sf_emulate_512 = False
sfv = SolidFire(configuration=self.configuration)
model_update = sfv.create_volume(testvol)
self.assertEqual(model_update.get('provider_geometry', None),
'4096 4096')
self.configuration.sf_emulate_512 = True
def test_initialize_connector_with_blocksizes(self):
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
testvol = {'project_id': 'testprjid',
'name': 'testvol',
'size': 1,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66',
'volume_type_id': None,
'provider_location': '10.10.7.1:3260 iqn.2010-01.com.'
'solidfire:87hg.uuid-2cc06226-cc'
'74-4cb7-bd55-14aed659a0cc.4060 0',
'provider_auth': 'CHAP stack-1-a60e2611875f40199931f2'
'c76370d66b 2FE0CQ8J196R',
'provider_geometry': '4096 4096'
}
sfv = SolidFire(configuration=self.configuration)
properties = sfv.initialize_connection(testvol, connector)
self.assertEqual(properties['data']['physical_block_size'], '4096')
self.assertEqual(properties['data']['logical_block_size'], '4096')
def test_create_volume_with_qos(self):
preset_qos = {}

View File

@ -323,6 +323,12 @@ class ISCSIDriver(VolumeDriver):
properties['auth_username'] = auth_username
properties['auth_password'] = auth_secret
geometry = volume.get('provider_geometry', None)
if geometry:
(physical_block_size, logical_block_size) = geometry.split()
properties['physical_block_size'] = physical_block_size
properties['logical_block_size'] = logical_block_size
return properties
def _run_iscsiadm(self, iscsi_properties, iscsi_command, **kwargs):

View File

@ -299,6 +299,9 @@ class SolidFire(SanISCSIDriver):
model_update['provider_auth'] = ('CHAP %s %s'
% (sfaccount['username'],
chap_secret))
if not self.configuration.sf_emulate_512:
model_update['provider_geometry'] = ('%s %s' % (4096, 4096))
return model_update
def _do_clone_volume(self, src_uuid, src_project_id, v_ref):