Add possibility to enable/disable some share protocols

It is useful in case we use share backends that do not implement some share
protocol or want to disable something for some other reason. For the moment,
there is no share driver that supports all share protocols in Manila.

Change-Id: I80a6a7927aa897931a84d310b657d0af06f02823
Closes-Bug: #1403161
This commit is contained in:
Valeriy Ponomaryov 2015-02-02 15:52:14 +02:00 committed by vponomaryov
parent fd5e0f8eb9
commit 4d19edb989
8 changed files with 123 additions and 28 deletions

View File

@ -50,6 +50,7 @@ CONF = cfg.CONF
if __name__ == '__main__':
CONF(sys.argv[1:], project='manila',
version=version.version_string())
config.verify_share_protocols()
logging.setup("manila")
utils.monkey_patch()
server = service.WSGIService('osapi_share')

View File

@ -81,6 +81,7 @@ fi
# Common opts
SHARE_NAME_PREFIX=${SHARE_NAME_PREFIX:-share-}
MANILA_ENABLED_SHARE_PROTOCOLS=${ENABLED_SHARE_PROTOCOLS:-"NFS,CIFS"}
MANILA_SCHEDULER_DRIVER=${MANILA_SCHEDULER_DRIVER:-manila.scheduler.filter_scheduler.FilterScheduler}
MANILA_SERVICE_SECGROUP="manila-service"
@ -250,6 +251,8 @@ function configure_manila {
iniset $MANILA_CONF DEFAULT cinder_admin_password $SERVICE_PASSWORD
iniset $MANILA_CONF DEFAULT neutron_admin_password $SERVICE_PASSWORD
iniset $MANILA_CONF DEFAULT enabled_share_protocols $MANILA_ENABLED_SHARE_PROTOCOLS
iniset $MANILA_CONF oslo_concurrency lock_path $MANILA_LOCK_PATH
# Note: set up config group does not mean that this backend will be enabled.

View File

@ -27,7 +27,10 @@ stepping stone.
import socket
from oslo_config import cfg
import six
from manila.common import constants
from manila import exception
from manila.i18n import _
CONF = cfg.CONF
@ -172,8 +175,36 @@ global_opts = [
help='A list of share backend names to use. These backend '
'names should be backed by a unique [CONFIG] group '
'with its options.'),
cfg.ListOpt('enabled_share_protocols',
default=['NFS', 'CIFS'],
help="Specify list of protocols to be allowed for share "
"creation. Available values are '%s'" % six.text_type(
constants.SUPPORTED_SHARE_PROTOCOLS)),
cfg.BoolOpt('no_snapshot_gb_quota',
default=False,
help='Whether snapshots count against Gigabyte quota.'), ]
CONF.register_opts(global_opts)
def verify_share_protocols():
"""Perfom verification of 'enabled_share_protocols'."""
msg = None
supported_protocols = constants.SUPPORTED_SHARE_PROTOCOLS
data = dict(supported=six.text_type(supported_protocols))
if CONF.enabled_share_protocols:
for share_proto in CONF.enabled_share_protocols:
if share_proto not in supported_protocols:
data.update({'share_proto': share_proto})
msg = _("Unsupported share protocol '%(share_proto)s' "
"is set as enabled. Available values are "
"%(supported)s. ")
break
else:
msg = _("No share protocols were specified as enabled. "
"Available values are %(supported)s. ")
if msg:
msg += _("Please specify one or more protocols using "
"configuration option 'enabled_share_protocols.")
msg = msg % data
raise exception.ManilaException(message=msg)

View File

@ -23,6 +23,9 @@ STATUS_INACTIVE = 'INACTIVE'
STATUS_ACTIVATING = 'ACTIVATING'
STATUS_DEACTIVATING = 'DEACTIVATING'
SUPPORTED_SHARE_PROTOCOLS = (
'NFS', 'CIFS', 'GLUSTERFS', 'HDFS')
SECURITY_SERVICES_ALLOWED_TYPES = ['active_directory', 'ldap', 'kerberos']
NFS_EXPORTS_FILE = '/etc/exports'

View File

@ -106,10 +106,15 @@ class API(base.Base):
"You should omit the argument.")
raise exception.InvalidInput(reason=msg)
# TODO(rushiagr): Find a suitable place to keep all the allowed
# share types so that it becomes easier to add one
if share_proto.lower() not in ['nfs', 'cifs', 'glusterfs', 'hdfs']:
msg = (_("Invalid share type provided: %s") % share_proto)
supported_share_protocols = (
proto.upper() for proto in CONF.enabled_share_protocols)
if not (share_proto and
share_proto.upper() in supported_share_protocols):
msg = (_("Invalid share protocol provided: %(provided)s. "
"It is either disabled or unsupported. Available "
"protocols: %(supported)s") % dict(
provided=share_proto,
supported=CONF.enabled_share_protocols))
raise exception.InvalidInput(reason=msg)
try:

View File

View File

@ -0,0 +1,42 @@
# Copyright 2015 Mirantis Inc.
# All Rights Reserved.
#
# 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.
import ddt
from manila.common import config
from manila.common import constants
from manila import exception
from manila import test
from manila.tests import utils as test_utils
VALID_CASES = [proto for proto in constants.SUPPORTED_SHARE_PROTOCOLS]
VALID_CASES.append(','.join(case for case in VALID_CASES))
@ddt.ddt
class VerifyConfigShareProtocolsTestCase(test.TestCase):
@ddt.data(*VALID_CASES)
def test_verify_share_protocols_valid_cases(self, proto):
data = dict(DEFAULT=dict(enabled_share_protocols=proto))
with test_utils.create_temp_config_with_opts(data):
config.verify_share_protocols()
@ddt.data(None, '', 'fake', [], ['fake'], [VALID_CASES[0] + 'fake'])
def test_verify_share_protocols_invalid_cases(self, proto):
data = dict(DEFAULT=dict(enabled_share_protocols=proto))
with test_utils.create_temp_config_with_opts(data):
self.assertRaises(
exception.ManilaException, config.verify_share_protocols)

View File

@ -26,6 +26,7 @@ from oslo.utils import timeutils as timeutils_old # noqa
from oslo_config import cfg
from oslo_utils import timeutils
from manila.common import constants
from manila import context
from manila import db as db_driver
from manila import exception
@ -34,6 +35,7 @@ from manila import share
from manila.share import api as share_api
from manila import test
from manila.tests.db import fakes as db_fakes
from manila.tests import utils as test_utils
from manila import utils
CONF = cfg.CONF
@ -419,9 +421,9 @@ class ShareAPITestCase(test.TestCase):
def test_get_all_filter_by_invalid_extra_specs(self):
self._get_all_filter_metadata_or_extra_specs_invalid(key='extra_specs')
def test_create(self):
date = datetime.datetime(1, 1, 1, 1, 1, 1)
timeutils.utcnow.return_value = date
@ddt.data(*constants.SUPPORTED_SHARE_PROTOCOLS)
def test_create_share_valid_protocol(self, proto):
timeutils.utcnow.return_value = datetime.datetime(1, 1, 1, 1, 1, 1)
share = fake_share('fakeid',
user_id=self.context.user_id,
project_id=self.context.project_id,
@ -430,31 +432,39 @@ class ShareAPITestCase(test.TestCase):
for name in ('id', 'export_location', 'host', 'launched_at',
'terminated_at'):
options.pop(name, None)
with mock.patch.object(db_driver, 'share_create',
mock.Mock(return_value=share)):
self.api.create(self.context, 'nfs', '1', 'fakename', 'fakedesc',
availability_zone='fakeaz')
db_driver.share_create.assert_called_once_with(
self.context, options)
options.update(share_proto=proto)
self.mock_object(
db_driver, 'share_create', mock.Mock(return_value=share))
def test_create_glusterfs(self):
date = datetime.datetime(1, 1, 1, 1, 1, 1)
timeutils.utcnow.return_value = date
share = fake_share('fakeid',
user_id=self.context.user_id,
project_id=self.context.project_id,
status='creating')
options = share.copy()
all_protos = ','.join(
proto for proto in constants.SUPPORTED_SHARE_PROTOCOLS)
data = dict(DEFAULT=dict(enabled_share_protocols=all_protos))
with test_utils.create_temp_config_with_opts(data):
self.api.create(
self.context, proto, '1', 'fakename', 'fakedesc',
availability_zone='fakeaz')
db_driver.share_create.assert_called_once_with(
self.context, options)
@ddt.data(
None, '', 'fake', 'nfsfake', 'cifsfake', 'glusterfsfake', 'hdfsfake')
def test_create_share_invalid_protocol(self, proto):
options = fake_share(
'fakeid', user_id=self.context.user_id,
project_id=self.context.project_id, status='creating')
for name in ('id', 'export_location', 'host', 'launched_at',
'terminated_at'):
options.pop(name, None)
with mock.patch.object(db_driver, 'share_create',
mock.Mock(return_value=share)):
options.update(share_proto='glusterfs')
self.api.create(self.context, 'glusterfs', '1', 'fakename',
'fakedesc', availability_zone='fakeaz')
db_driver.share_create.assert_called_once_with(
self.context, options)
options.update(share_proto=proto)
all_protos = ','.join(
proto for proto in constants.SUPPORTED_SHARE_PROTOCOLS)
data = dict(DEFAULT=dict(enabled_share_protocols=all_protos))
with test_utils.create_temp_config_with_opts(data):
self.assertRaises(
exception.InvalidInput,
self.api.create,
self.context, proto, '1', 'fakename', 'fakedesc')
@mock.patch.object(quota.QUOTAS, 'reserve',
mock.Mock(return_value='reservation'))