Merge "Implement additional driver mode for Generic driver"
This commit is contained in:
commit
77e3087ad0
@ -20,6 +20,7 @@ import sys
|
||||
|
||||
from novaclient import exceptions as nova_exception
|
||||
from novaclient import service_catalog
|
||||
from novaclient import utils
|
||||
from novaclient.v1_1 import client as nova_client
|
||||
from novaclient.v1_1.contrib import assisted_volume_snapshots
|
||||
from novaclient.v1_1 import servers as nova_servers
|
||||
@ -27,6 +28,7 @@ from oslo_config import cfg
|
||||
|
||||
from manila.db import base
|
||||
from manila import exception
|
||||
from manila.i18n import _
|
||||
from manila.openstack.common import log as logging
|
||||
|
||||
|
||||
@ -181,6 +183,15 @@ class API(base.Base):
|
||||
novaclient(context).servers.get(instance_id)
|
||||
)
|
||||
|
||||
def server_get_by_name_or_id(self, context, instance_name_or_id):
|
||||
try:
|
||||
server = utils.find_resource(
|
||||
novaclient(context).servers, instance_name_or_id)
|
||||
except nova_exception.CommandError as e:
|
||||
msg = _("Failed to get Nova VM. %s") % e
|
||||
raise exception.ManilaException(msg)
|
||||
return _untranslate_server_summary_view(server)
|
||||
|
||||
def server_list(self, context, search_opts=None, all_tenants=False):
|
||||
if search_opts is None:
|
||||
search_opts = {}
|
||||
|
@ -109,7 +109,9 @@ _global_opt_lists = [
|
||||
manila.share.drivers.huawei.huawei_nas.huawei_opts,
|
||||
manila.share.drivers.ibm.gpfs.gpfs_share_opts,
|
||||
manila.share.drivers.netapp.cluster_mode.NETAPP_NAS_OPTS,
|
||||
manila.share.drivers.service_instance.server_opts,
|
||||
manila.share.drivers.service_instance.common_opts,
|
||||
manila.share.drivers.service_instance.no_share_servers_handling_mode_opts,
|
||||
manila.share.drivers.service_instance.share_servers_handling_mode_opts,
|
||||
manila.share.drivers.zfssa.zfssashare.ZFSSA_OPTS,
|
||||
manila.share.manager.share_manager_opts,
|
||||
manila.volume._volume_opts,
|
||||
|
@ -85,22 +85,35 @@ CONF.register_opts(share_opts)
|
||||
|
||||
|
||||
def ensure_server(f):
|
||||
|
||||
def wrap(self, *args, **kwargs):
|
||||
server = kwargs.get('share_server')
|
||||
context = args[0]
|
||||
if not server:
|
||||
# For now generic driver does not support flat networking.
|
||||
# When we implement flat networking in generic driver
|
||||
# we will not need share server to be passed and
|
||||
# will change this logic.
|
||||
raise exception.ManilaException(_('Share server not found.'))
|
||||
server = kwargs.get('share_server')
|
||||
|
||||
if not self.driver_handles_share_servers:
|
||||
if not server:
|
||||
server = self.service_instance_manager.get_common_server()
|
||||
kwargs['share_server'] = server
|
||||
else:
|
||||
raise exception.ManilaException(
|
||||
_("Share server handling is not available. "
|
||||
"But 'share_server' was provided. '%s'. "
|
||||
"Share network should not be used.") % server['id'])
|
||||
elif not server:
|
||||
raise exception.ManilaException(
|
||||
_("Share server handling is enabled. But 'share_server' "
|
||||
"is not provided. Make sure you used 'share_network'."))
|
||||
|
||||
if not server.get('backend_details'):
|
||||
raise exception.ManilaException(_('Share server backend '
|
||||
'details missing.'))
|
||||
raise exception.ManilaException(
|
||||
_("Share server '%s' does not have backend details.") %
|
||||
server['id'])
|
||||
if not self.service_instance_manager.ensure_service_instance(
|
||||
context, server['backend_details']):
|
||||
raise exception.ServiceInstanceUnavailable()
|
||||
|
||||
return f(self, *args, **kwargs)
|
||||
|
||||
return wrap
|
||||
|
||||
|
||||
@ -109,11 +122,11 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
|
||||
def __init__(self, db, *args, **kwargs):
|
||||
"""Do initialization."""
|
||||
super(GenericShareDriver, self).__init__(True, *args, **kwargs)
|
||||
super(GenericShareDriver, self).__init__(
|
||||
[False, True], *args, **kwargs)
|
||||
self.admin_context = context.get_admin_context()
|
||||
self.db = db
|
||||
self.configuration.append_config_values(share_opts)
|
||||
self.configuration.append_config_values(service_instance.server_opts)
|
||||
self._helpers = {}
|
||||
self.backend_name = self.configuration.safe_get(
|
||||
'share_backend_name') or "Cinder_Volumes"
|
||||
@ -479,6 +492,8 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
|
||||
def delete_share(self, context, share, share_server=None):
|
||||
"""Deletes share."""
|
||||
if not self.driver_handles_share_servers:
|
||||
share_server = self.service_instance_manager.get_common_server()
|
||||
if self._is_share_server_active(context, share_server):
|
||||
self._get_helper(share).remove_export(
|
||||
share_server['backend_details'], share['name'])
|
||||
@ -490,7 +505,6 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
# with any reason that caused absence of Nova instances.
|
||||
self._deallocate_container(self.admin_context, share)
|
||||
|
||||
@ensure_server
|
||||
def create_snapshot(self, context, snapshot, share_server=None):
|
||||
"""Creates a snapshot."""
|
||||
volume = self._get_volume(self.admin_context, snapshot['share_id'])
|
||||
@ -515,7 +529,6 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
'created in %ss. Giving up') %
|
||||
self.configuration.max_time_to_create_volume)
|
||||
|
||||
@ensure_server
|
||||
def delete_snapshot(self, context, snapshot, share_server=None):
|
||||
"""Deletes a snapshot."""
|
||||
volume_snapshot = self._get_volume_snapshot(self.admin_context,
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Copyright (c) 2014 NetApp, Inc.
|
||||
# Copyright (c) 2015 Mirantis, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
@ -25,7 +26,7 @@ from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from manila.common import constants
|
||||
from manila.common import constants as const
|
||||
from manila import compute
|
||||
from manila import context
|
||||
from manila import exception
|
||||
@ -39,7 +40,7 @@ from manila import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
server_opts = [
|
||||
share_servers_handling_mode_opts = [
|
||||
cfg.StrOpt('service_image_name',
|
||||
default='manila-service-image',
|
||||
help="Name of image in glance, that will be used to create "
|
||||
@ -47,11 +48,6 @@ server_opts = [
|
||||
cfg.StrOpt('service_instance_name_template',
|
||||
default='manila_service_instance_%s',
|
||||
help="Name of service instance."),
|
||||
cfg.StrOpt('service_instance_user',
|
||||
help="User in service instance."),
|
||||
cfg.StrOpt('service_instance_password',
|
||||
default=None,
|
||||
help="Password to service instance user."),
|
||||
cfg.StrOpt('manila_service_keypair_name',
|
||||
default='manila-service',
|
||||
help="Name of keypair that will be created and used "
|
||||
@ -59,12 +55,6 @@ server_opts = [
|
||||
cfg.StrOpt('path_to_public_key',
|
||||
default='~/.ssh/id_rsa.pub',
|
||||
help="Path to hosts public key."),
|
||||
cfg.StrOpt('path_to_private_key',
|
||||
default='~/.ssh/id_rsa',
|
||||
help="Path to hosts private key."),
|
||||
cfg.IntOpt('max_time_to_build_instance',
|
||||
default=300,
|
||||
help="Maximum time to wait for creating service instance."),
|
||||
cfg.StrOpt('service_instance_security_group',
|
||||
default="manila-service",
|
||||
help="Name of security group, that will be used for "
|
||||
@ -93,8 +83,48 @@ server_opts = [
|
||||
help='Attach share server directly to share network.'),
|
||||
]
|
||||
|
||||
no_share_servers_handling_mode_opts = [
|
||||
cfg.StrOpt(
|
||||
"service_instance_name_or_id",
|
||||
help="Name or ID of service instance in Nova to use for share "
|
||||
"exports. Used only when share servers handling is disabled."),
|
||||
cfg.StrOpt(
|
||||
"service_net_name_or_ip",
|
||||
help="Can be either name of network that is used by service "
|
||||
"instance within Nova to get IP address or IP address itself "
|
||||
"for managing shares there. "
|
||||
"Used only when share servers handling is disabled."),
|
||||
cfg.StrOpt(
|
||||
"tenant_net_name_or_ip",
|
||||
help="Can be either name of network that is used by service "
|
||||
"instance within Nova to get IP address or IP address itself "
|
||||
"for exporting shares. "
|
||||
"Used only when share servers handling is disabled."),
|
||||
]
|
||||
|
||||
common_opts = [
|
||||
cfg.StrOpt(
|
||||
"service_instance_user",
|
||||
help="User in service instance that will be used for authentication."),
|
||||
cfg.StrOpt(
|
||||
"service_instance_password",
|
||||
default=None,
|
||||
secret=True,
|
||||
help="Password for service instance user."),
|
||||
cfg.StrOpt(
|
||||
"path_to_private_key",
|
||||
default="~/.ssh/id_rsa",
|
||||
help="Path to host's private key."),
|
||||
cfg.IntOpt(
|
||||
"max_time_to_build_instance",
|
||||
default=300,
|
||||
help="Maximum time in seconds to wait for creating service instance."),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(server_opts)
|
||||
CONF.register_opts(common_opts)
|
||||
CONF.register_opts(no_share_servers_handling_mode_opts)
|
||||
CONF.register_opts(share_servers_handling_mode_opts)
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
@ -126,20 +156,45 @@ class ServiceInstanceManager(object):
|
||||
value = CONF.get(key)
|
||||
return value
|
||||
|
||||
def __init__(self, db, *args, **kwargs):
|
||||
def __init__(self, db, driver_config):
|
||||
"""Do initialization."""
|
||||
super(ServiceInstanceManager, self).__init__()
|
||||
self.driver_config = None
|
||||
if "driver_config" in kwargs:
|
||||
self.driver_config = kwargs["driver_config"]
|
||||
self.db = db
|
||||
self.driver_config = driver_config
|
||||
|
||||
self.driver_config.append_config_values(common_opts)
|
||||
if self.get_config_option("driver_handles_share_servers"):
|
||||
self.driver_config.append_config_values(
|
||||
share_servers_handling_mode_opts)
|
||||
else:
|
||||
self.driver_config.append_config_values(
|
||||
no_share_servers_handling_mode_opts)
|
||||
|
||||
if not self.get_config_option("service_instance_user"):
|
||||
raise exception.ServiceInstanceException(_('Service instance user '
|
||||
'is not specified'))
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Service instance user is not specified.'))
|
||||
self.admin_context = context.get_admin_context()
|
||||
self._execute = utils.execute
|
||||
self.compute_api = compute.API()
|
||||
self.neutron_api = neutron.API()
|
||||
self.db = db
|
||||
self.path_to_private_key = self.get_config_option(
|
||||
"path_to_private_key")
|
||||
self.max_time_to_build_instance = self.get_config_option(
|
||||
"max_time_to_build_instance")
|
||||
|
||||
if self.get_config_option("driver_handles_share_servers"):
|
||||
self.neutron_api = neutron.API()
|
||||
self.path_to_public_key = self.get_config_option(
|
||||
"path_to_public_key")
|
||||
self.connect_share_server_to_tenant_network = (
|
||||
self.get_config_option(
|
||||
'connect_share_server_to_tenant_network'))
|
||||
self._get_service_tenant_id()
|
||||
self.service_network_id = self._get_service_network()
|
||||
self.vif_driver = importutils.import_class(
|
||||
self.get_config_option("interface_driver"))()
|
||||
self._setup_connectivity_with_service_instances()
|
||||
|
||||
def _get_service_tenant_id(self):
|
||||
attempts = 5
|
||||
while attempts:
|
||||
try:
|
||||
@ -152,17 +207,57 @@ class ServiceInstanceManager(object):
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Can not receive '
|
||||
'service tenant id.'))
|
||||
self.service_network_id = self._get_service_network()
|
||||
self.vif_driver = importutils.import_class(
|
||||
self.get_config_option("interface_driver"))()
|
||||
self._setup_connectivity_with_service_instances()
|
||||
self.max_time_to_build_instance = self.get_config_option(
|
||||
"max_time_to_build_instance")
|
||||
self.path_to_private_key = self.get_config_option(
|
||||
"path_to_private_key")
|
||||
self.path_to_public_key = self.get_config_option("path_to_public_key")
|
||||
self.connect_share_server_to_tenant_network = self.get_config_option(
|
||||
'connect_share_server_to_tenant_network')
|
||||
|
||||
def get_common_server(self):
|
||||
data = {
|
||||
'public_address': None,
|
||||
'private_address': None,
|
||||
'service_net_name_or_ip': self.get_config_option(
|
||||
'service_net_name_or_ip'),
|
||||
'tenant_net_name_or_ip': self.get_config_option(
|
||||
'tenant_net_name_or_ip'),
|
||||
}
|
||||
|
||||
data['instance'] = self.compute_api.server_get_by_name_or_id(
|
||||
self.admin_context,
|
||||
self.get_config_option('service_instance_name_or_id'))
|
||||
|
||||
if netaddr.valid_ipv4(data['service_net_name_or_ip']):
|
||||
data['private_address'] = [data['service_net_name_or_ip']]
|
||||
else:
|
||||
data['private_address'] = self._get_addresses_by_network_name(
|
||||
data['service_net_name_or_ip'], data['instance'])
|
||||
|
||||
if netaddr.valid_ipv4(data['tenant_net_name_or_ip']):
|
||||
data['public_address'] = [data['tenant_net_name_or_ip']]
|
||||
else:
|
||||
data['public_address'] = self._get_addresses_by_network_name(
|
||||
data['tenant_net_name_or_ip'], data['instance'])
|
||||
|
||||
if not (data['public_address'] and data['private_address']):
|
||||
raise exception.ManilaException(
|
||||
"Can not find one of net addresses for service instance. "
|
||||
"Instance: %(instance)s, "
|
||||
"private_address: %(private_address)s, "
|
||||
"public_address: %(public_address)s." % data)
|
||||
|
||||
share_server = {
|
||||
'username': self.get_config_option('service_instance_user'),
|
||||
'password': self.get_config_option('service_instance_password'),
|
||||
'pk_path': self.path_to_private_key,
|
||||
'ip': data['private_address'][0], # for handling
|
||||
'public_address': data['public_address'][0], # for exports
|
||||
'instance_id': data['instance']['id'],
|
||||
}
|
||||
return {'backend_details': share_server}
|
||||
|
||||
def _get_addresses_by_network_name(self, net_name, server):
|
||||
net_ips = []
|
||||
if 'networks' in server and net_name in server['networks']:
|
||||
net_ips = server['networks'][net_name]
|
||||
elif 'addresses' in server and net_name in server['addresses']:
|
||||
net_ips = [addr['addr'] for addr in server['addresses'][net_name]]
|
||||
return net_ips
|
||||
|
||||
@utils.synchronized("service_instance_get_service_network", external=True)
|
||||
def _get_service_network(self):
|
||||
@ -193,11 +288,7 @@ class ServiceInstanceManager(object):
|
||||
def _get_server_ip(self, server):
|
||||
"""Returns service vms ip address."""
|
||||
net_name = self.get_config_option("service_network_name")
|
||||
net_ips = []
|
||||
if 'networks' in server and net_name in server['networks']:
|
||||
net_ips = server['networks'][net_name]
|
||||
elif 'addresses' in server and net_name in server['addresses']:
|
||||
net_ips = [addr['addr'] for addr in server['addresses'][net_name]]
|
||||
net_ips = self._get_addresses_by_network_name(net_name, server)
|
||||
if not net_ips:
|
||||
msg = _("Failed to get service instance ip address. "
|
||||
"Service network name is '%(net_name)s' "
|
||||
@ -234,7 +325,7 @@ class ServiceInstanceManager(object):
|
||||
LOG.debug("Creating security group with name '%s'.", name)
|
||||
sg = self.compute_api.security_group_create(
|
||||
context, name, description)
|
||||
for protocol, ports in constants.SERVICE_INSTANCE_SECGROUP_DATA:
|
||||
for protocol, ports in const.SERVICE_INSTANCE_SECGROUP_DATA:
|
||||
self.compute_api.security_group_rule_create(
|
||||
context,
|
||||
parent_group_id=sg.id,
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import mock
|
||||
from novaclient import exceptions as nova_exception
|
||||
from novaclient import utils
|
||||
from novaclient.v1_1 import servers as nova_servers
|
||||
|
||||
from manila.compute import nova
|
||||
@ -87,7 +88,17 @@ class NovaApiTestCase(test.TestCase):
|
||||
def test_server_get(self):
|
||||
instance_id = 'instance_id1'
|
||||
result = self.api.server_get(self.ctx, instance_id)
|
||||
self.assertEqual(result['id'], instance_id)
|
||||
self.assertEqual(instance_id, result['id'])
|
||||
|
||||
def test_server_get_by_name_or_id(self):
|
||||
instance_id = 'instance_id1'
|
||||
server = {'id': instance_id, 'fake_key': 'fake_value'}
|
||||
self.stubs.Set(utils, 'find_resource', mock.Mock(return_value=server))
|
||||
|
||||
result = self.api.server_get_by_name_or_id(self.ctx, instance_id)
|
||||
|
||||
self.assertEqual(instance_id, result['id'])
|
||||
utils.find_resource.assert_called_once_with(mock.ANY, instance_id)
|
||||
|
||||
def test_server_get_failed(self):
|
||||
nova.novaclient.side_effect = nova_exception.NotFound(404)
|
||||
|
@ -89,6 +89,9 @@ class API(object):
|
||||
def server_get(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def server_get_by_name_or_id(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def keypair_list(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Copyright (c) 2014 NetApp, Inc.
|
||||
# Copyright (c) 2015 Mirantis, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
@ -624,6 +625,27 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self._helper_nfs.create_export.assert_called_once_with(
|
||||
self.server['backend_details'], self.share['name'])
|
||||
|
||||
def test_delete_share_no_share_servers_handling(self):
|
||||
self.stubs.Set(self._driver, '_deallocate_container', mock.Mock())
|
||||
self.stubs.Set(
|
||||
self._driver.service_instance_manager,
|
||||
'get_common_server', mock.Mock(return_value=self.server))
|
||||
self.stubs.Set(
|
||||
self._driver.service_instance_manager,
|
||||
'ensure_service_instance', mock.Mock(return_value=False))
|
||||
|
||||
CONF.set_default('driver_handles_share_servers', False)
|
||||
|
||||
self._driver.delete_share(self._context, self.share)
|
||||
|
||||
self._driver.service_instance_manager.get_common_server.\
|
||||
assert_called_once_with()
|
||||
self._driver._deallocate_container.assert_called_once_with(
|
||||
self._driver.admin_context, self.share)
|
||||
self._driver.service_instance_manager.ensure_service_instance.\
|
||||
assert_called_once_with(
|
||||
self._context, self.server['backend_details'])
|
||||
|
||||
def test_delete_share(self):
|
||||
self.stubs.Set(self._driver, '_unmount_device', mock.Mock())
|
||||
self.stubs.Set(self._driver, '_detach_volume', mock.Mock())
|
||||
@ -641,6 +663,9 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self.server['backend_details'])
|
||||
self._driver._deallocate_container.assert_called_once_with(
|
||||
self._driver.admin_context, self.share)
|
||||
self._driver.service_instance_manager.ensure_service_instance.\
|
||||
assert_called_once_with(
|
||||
self._context, self.server['backend_details'])
|
||||
|
||||
def test_delete_share_without_share_server(self):
|
||||
self.stubs.Set(self._driver, '_unmount_device', mock.Mock())
|
||||
@ -684,17 +709,20 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self.stubs.Set(self._driver, '_detach_volume', mock.Mock())
|
||||
self.stubs.Set(self._driver, '_deallocate_container', mock.Mock())
|
||||
|
||||
with mock.patch.object(self._driver.service_instance_manager,
|
||||
'ensure_service_instance',
|
||||
mock.Mock(return_value=False)):
|
||||
self._driver.delete_share(
|
||||
self._context, self.share, share_server=self.server)
|
||||
self.stubs.Set(
|
||||
self._driver.service_instance_manager,
|
||||
'ensure_service_instance', mock.Mock(return_value=False))
|
||||
self._driver.delete_share(
|
||||
self._context, self.share, share_server=self.server)
|
||||
|
||||
self.assertFalse(self._helper_nfs.remove_export.called)
|
||||
self.assertFalse(self._driver._unmount_device.called)
|
||||
self.assertFalse(self._driver._detach_volume.called)
|
||||
self._driver._deallocate_container.assert_called_once_with(
|
||||
self._driver.admin_context, self.share)
|
||||
self.assertFalse(self._helper_nfs.remove_export.called)
|
||||
self.assertFalse(self._driver._unmount_device.called)
|
||||
self.assertFalse(self._driver._detach_volume.called)
|
||||
self._driver._deallocate_container.assert_called_once_with(
|
||||
self._driver.admin_context, self.share)
|
||||
self._driver.service_instance_manager.ensure_service_instance.\
|
||||
assert_called_once_with(
|
||||
self._context, self.server['backend_details'])
|
||||
|
||||
def test_create_snapshot(self):
|
||||
fake_vol = fake_volume.FakeVolume()
|
||||
@ -787,7 +815,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self.assertRaises(exception.InvalidShare,
|
||||
self._driver._get_helper, share)
|
||||
|
||||
def test_setup_network(self):
|
||||
def test__setup_server(self):
|
||||
sim = self._driver.instance_manager
|
||||
net_info = {'server_id': 'fake',
|
||||
'neutron_net_id': 'fake-net-id',
|
||||
@ -799,7 +827,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
'fake-net-id',
|
||||
'fake-subnet-id')
|
||||
|
||||
def test_setup_network_revert(self):
|
||||
def test__setup_server_revert(self):
|
||||
|
||||
def raise_exception(*args, **kwargs):
|
||||
raise exception.ServiceInstanceException
|
||||
@ -814,7 +842,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self._driver.setup_server,
|
||||
net_info)
|
||||
|
||||
def test_teardown_network(self):
|
||||
def test__teardown_server(self):
|
||||
server_details = {
|
||||
'instance_id': 'fake_instance_id',
|
||||
'subnet_id': 'fake_subnet_id',
|
||||
@ -929,6 +957,70 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
self.assertEqual('Open Source', result['vendor_name'])
|
||||
|
||||
|
||||
@generic.ensure_server
|
||||
def fake(driver_instance, context, share_server=None):
|
||||
return share_server
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class GenericDriverEnsureServerTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(GenericDriverEnsureServerTestCase, self).setUp()
|
||||
self._context = context.get_admin_context()
|
||||
self.server = {'id': 'fake_id', 'backend_details': {'foo': 'bar'}}
|
||||
self.dhss_false = type(
|
||||
'Fake', (object,), {'driver_handles_share_servers': False})
|
||||
self.dhss_true = type(
|
||||
'Fake', (object,), {'driver_handles_share_servers': True})
|
||||
|
||||
def test_share_servers_are_not_handled_server_not_provided(self):
|
||||
self.dhss_false.service_instance_manager = mock.Mock()
|
||||
self.dhss_false.service_instance_manager.get_common_server = (
|
||||
mock.Mock(return_value=self.server))
|
||||
self.dhss_false.service_instance_manager.ensure_service_instance = (
|
||||
mock.Mock(return_value=True))
|
||||
|
||||
actual = fake(self.dhss_false, self._context)
|
||||
|
||||
self.assertEqual(self.server, actual)
|
||||
self.dhss_false.service_instance_manager.\
|
||||
get_common_server.assert_called_once_with()
|
||||
self.dhss_false.service_instance_manager.ensure_service_instance.\
|
||||
assert_called_once_with(
|
||||
self._context, self.server['backend_details'])
|
||||
|
||||
@ddt.data({'id': 'without_details'},
|
||||
{'id': 'with_details', 'backend_details': {'foo': 'bar'}})
|
||||
def test_share_servers_are_not_handled_server_provided(self, server):
|
||||
self.assertRaises(
|
||||
exception.ManilaException,
|
||||
fake, self.dhss_false, self._context, share_server=server)
|
||||
|
||||
def test_share_servers_are_handled_server_provided(self):
|
||||
self.dhss_true.service_instance_manager = mock.Mock()
|
||||
self.dhss_true.service_instance_manager.ensure_service_instance = (
|
||||
mock.Mock(return_value=True))
|
||||
|
||||
actual = fake(self.dhss_true, self._context, share_server=self.server)
|
||||
|
||||
self.assertEqual(self.server, actual)
|
||||
self.dhss_true.service_instance_manager.ensure_service_instance.\
|
||||
assert_called_once_with(
|
||||
self._context, self.server['backend_details'])
|
||||
|
||||
def test_share_servers_are_handled_invalid_server_provided(self):
|
||||
server = {'id': 'without_details'}
|
||||
|
||||
self.assertRaises(
|
||||
exception.ManilaException,
|
||||
fake, self.dhss_true, self._context, share_server=server)
|
||||
|
||||
def test_share_servers_are_handled_server_not_provided(self):
|
||||
self.assertRaises(
|
||||
exception.ManilaException, fake, self.dhss_true, self._context)
|
||||
|
||||
|
||||
class NFSHelperTestCase(test.TestCase):
|
||||
"""Test case for NFS helper of generic driver."""
|
||||
|
||||
|
@ -18,12 +18,15 @@
|
||||
import copy
|
||||
import os
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.share import configuration
|
||||
from manila.share.drivers import service_instance
|
||||
from manila import test
|
||||
from manila.tests import fake_compute
|
||||
@ -34,23 +37,60 @@ from manila import utils
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def fake_get_config_option(key):
|
||||
if key == 'driver_handles_share_servers':
|
||||
return True
|
||||
elif key == 'service_instance_password':
|
||||
return None
|
||||
elif key == 'service_instance_user':
|
||||
return 'fake_user'
|
||||
elif key == 'service_network_name':
|
||||
return 'fake_service_network_name'
|
||||
elif key == 'service_instance_flavor_id':
|
||||
return 100
|
||||
elif key == 'service_instance_name_template':
|
||||
return 'fake_manila_service_instance_%s'
|
||||
elif key == 'service_image_name':
|
||||
return 'fake_service_image_name'
|
||||
elif key == 'manila_service_keypair_name':
|
||||
return 'fake_manila_service_keypair_name'
|
||||
elif key == 'path_to_private_key':
|
||||
return 'fake_path_to_private_key'
|
||||
elif key == 'path_to_public_key':
|
||||
return 'fake_path_to_public_key'
|
||||
elif key == 'max_time_to_build_instance':
|
||||
return 500
|
||||
elif key == 'connect_share_server_to_tenant_network':
|
||||
return False
|
||||
elif key == 'service_network_cidr':
|
||||
return '99.254.0.0/16'
|
||||
elif key == 'service_network_division_mask':
|
||||
return 25
|
||||
else:
|
||||
return mock.Mock()
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
"""Tests InstanceManager."""
|
||||
|
||||
def setUp(self):
|
||||
super(ServiceInstanceManagerTestCase, self).setUp()
|
||||
self._context = context.get_admin_context()
|
||||
self.config = configuration.Configuration(None)
|
||||
self.config.safe_get = mock.Mock(side_effect=fake_get_config_option)
|
||||
|
||||
self._helper_cifs = mock.Mock()
|
||||
self._helper_nfs = mock.Mock()
|
||||
self._db = mock.Mock()
|
||||
self.stubs.Set(service_instance.neutron, 'API', fake_network.API)
|
||||
self.stubs.Set(service_instance.compute, 'API', fake_compute.API)
|
||||
self.stubs.Set(importutils, 'import_class', mock.Mock())
|
||||
with mock.patch.object(service_instance.ServiceInstanceManager,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock()):
|
||||
self._manager = service_instance.ServiceInstanceManager(self._db,
|
||||
{})
|
||||
self._manager = service_instance.ServiceInstanceManager(
|
||||
self._db, self.config)
|
||||
self._manager.service_tenant_id = 'service tenant id'
|
||||
self._manager.service_network_id = 'service network id'
|
||||
self._manager.admin_context = self._context
|
||||
@ -70,12 +110,12 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
def test_get_service_network_net_exists(self):
|
||||
net1 = copy.copy(fake_network.API.network)
|
||||
net2 = copy.copy(fake_network.API.network)
|
||||
net1['name'] = CONF.service_network_name
|
||||
net1['name'] = self._manager.get_config_option('service_network_name')
|
||||
net1['id'] = 'fake service network id'
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[net1, net2]))
|
||||
result = self._manager._get_service_network()
|
||||
self.assertEqual(result, net1['id'])
|
||||
self.assertEqual(net1['id'], result)
|
||||
|
||||
def test_get_service_network_net_does_not_exists(self):
|
||||
net = fake_network.FakeNetwork()
|
||||
@ -84,10 +124,11 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self.stubs.Set(self._manager.neutron_api, 'network_create',
|
||||
mock.Mock(return_value=net))
|
||||
result = self._manager._get_service_network()
|
||||
self.assertEqual(result, net['id'])
|
||||
self.assertEqual(net['id'], result)
|
||||
|
||||
def test_get_service_network_ambiguos(self):
|
||||
net = fake_network.FakeNetwork(name=CONF.service_network_name)
|
||||
net = fake_network.FakeNetwork(
|
||||
name=self._manager.get_config_option('service_network_name'))
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[net, net]))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
@ -96,14 +137,14 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
def test_get_service_instance_name(self):
|
||||
result = self._manager._get_service_instance_name(
|
||||
'fake_share_network_id')
|
||||
self.assertEqual(result, CONF.service_instance_name_template %
|
||||
'fake_share_network_id')
|
||||
self.assertEqual(
|
||||
'fake_manila_service_instance_None_fake_share_network_id', result)
|
||||
|
||||
def test_get_server_ip_found_in_networks_section(self):
|
||||
ip = '10.0.0.1'
|
||||
fake_server = {
|
||||
'networks': {
|
||||
CONF.service_network_name: [ip],
|
||||
self._manager.get_config_option('service_network_name'): [ip],
|
||||
}
|
||||
}
|
||||
result = self._manager._get_server_ip(fake_server)
|
||||
@ -113,7 +154,7 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
ip = '10.0.0.1'
|
||||
fake_server = {
|
||||
'addresses': {
|
||||
CONF.service_network_name: [
|
||||
self._manager.get_config_option('service_network_name'): [
|
||||
{'addr': ip, 'version': 4, }
|
||||
],
|
||||
}
|
||||
@ -311,8 +352,9 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_get_key_create_new(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name)
|
||||
keypair_name = self._manager.get_config_option(
|
||||
'manila_service_keypair_name')
|
||||
fake_keypair = fake_compute.FakeKeypair(name=keypair_name)
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_import',
|
||||
@ -320,17 +362,20 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
|
||||
result = self._manager._get_key(self._context)
|
||||
|
||||
self.assertEqual(result,
|
||||
(fake_keypair.name,
|
||||
os.path.expanduser(CONF.path_to_private_key)))
|
||||
self.assertEqual(
|
||||
(fake_keypair.name,
|
||||
os.path.expanduser(self._manager.get_config_option(
|
||||
'path_to_private_key'))),
|
||||
result)
|
||||
self._manager.compute_api.keypair_list.assert_called_once_with(
|
||||
self._context)
|
||||
self._manager.compute_api.keypair_import.assert_called_once_with(
|
||||
self._context, 'manila-service', '')
|
||||
self._context, keypair_name, '')
|
||||
|
||||
def test_get_key_exists(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name,
|
||||
name=self._manager.get_config_option(
|
||||
'manila_service_keypair_name'),
|
||||
public_key='fake_public_key')
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[fake_keypair]))
|
||||
@ -344,13 +389,16 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self._manager.compute_api.keypair_list.assert_called_once_with(
|
||||
self._context)
|
||||
self.assertFalse(self._manager.compute_api.keypair_import.called)
|
||||
self.assertEqual(result,
|
||||
(fake_keypair.name,
|
||||
os.path.expanduser(CONF.path_to_private_key)))
|
||||
self.assertEqual(
|
||||
(fake_keypair.name,
|
||||
os.path.expanduser(self._manager.get_config_option(
|
||||
'path_to_private_key'))),
|
||||
result)
|
||||
|
||||
def test_get_key_exists_recreate(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name,
|
||||
name=self._manager.get_config_option(
|
||||
'manila_service_keypair_name'),
|
||||
public_key='fake_public_key1')
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[fake_keypair]))
|
||||
@ -369,9 +417,11 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self._context, fake_keypair.id)
|
||||
self._manager.compute_api.keypair_import.assert_called_once_with(
|
||||
self._context, fake_keypair.name, 'fake_public_key2')
|
||||
self.assertEqual(result,
|
||||
(fake_keypair.name,
|
||||
os.path.expanduser(CONF.path_to_private_key)))
|
||||
self.assertEqual(
|
||||
(fake_keypair.name,
|
||||
os.path.expanduser(self._manager.get_config_option(
|
||||
'path_to_private_key'))),
|
||||
result)
|
||||
|
||||
def test_get_key_keypath_to_public_not_set(self):
|
||||
self._manager.path_to_public_key = None
|
||||
@ -414,14 +464,15 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self.assertEqual(result, (None, None))
|
||||
|
||||
def test_get_service_image(self):
|
||||
fake_image1 = fake_compute.FakeImage(name=CONF.service_image_name)
|
||||
fake_image1 = fake_compute.FakeImage(
|
||||
name=self._manager.get_config_option('service_image_name'))
|
||||
fake_image2 = fake_compute.FakeImage(name='another-image')
|
||||
self.stubs.Set(self._manager.compute_api, 'image_list',
|
||||
mock.Mock(return_value=[fake_image1, fake_image2]))
|
||||
|
||||
result = self._manager._get_service_image(self._context)
|
||||
|
||||
self.assertEqual(result, fake_image1.id)
|
||||
self.assertEqual(fake_image1.id, result)
|
||||
|
||||
def test_get_service_image_not_found(self):
|
||||
self.stubs.Set(self._manager.compute_api, 'image_list',
|
||||
@ -834,8 +885,9 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
|
||||
def test_get_cidr_for_subnet(self):
|
||||
serv_cidr = service_instance.netaddr.IPNetwork(
|
||||
CONF.service_network_cidr)
|
||||
fake_division_mask = CONF.service_network_division_mask
|
||||
self._manager.get_config_option('service_network_cidr'))
|
||||
fake_division_mask = self._manager.get_config_option(
|
||||
'service_network_division_mask')
|
||||
cidrs = serv_cidr.subnet(fake_division_mask)
|
||||
cidr1 = six.text_type(next(cidrs))
|
||||
cidr2 = six.text_type(next(cidrs))
|
||||
@ -936,3 +988,79 @@ class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
self._manager.neutron_api.update_subnet.assert_has_calls([
|
||||
mock.call(subnet_id, ''),
|
||||
])
|
||||
|
||||
@ddt.data(
|
||||
{'s': 'fake_net_s', 't': 'fake_net_t'},
|
||||
{'s': 'fake_net_s', 't': '12.34.56.78'},
|
||||
{'s': '98.76.54.123', 't': 'fake_net_t'},
|
||||
{'s': '98.76.54.123', 't': '12.34.56.78'})
|
||||
@ddt.unpack
|
||||
def test_get_common_server_valid_cases(self, s, t):
|
||||
self._get_common_server(s, t, True)
|
||||
|
||||
@ddt.data(
|
||||
{'s': 'fake_net_s', 't': 'fake'},
|
||||
{'s': 'fake', 't': 'fake_net_t'},
|
||||
{'s': 'fake', 't': 'fake'},
|
||||
{'s': '98.76.54.123', 't': '12.12.12.1212'},
|
||||
{'s': '12.12.12.1212', 't': '12.34.56.78'},
|
||||
{'s': '12.12.12.1212', 't': '12.12.12.1212'})
|
||||
@ddt.unpack
|
||||
def test_get_common_server_invalid_cases(self, s, t):
|
||||
self._get_common_server(s, t, False)
|
||||
|
||||
def _get_common_server(self, s, t, is_valid=True):
|
||||
fake_instance_id = 'fake_instance_id'
|
||||
fake_user = 'fake_user'
|
||||
fake_pass = 'fake_pass'
|
||||
fake_net_s = 'fake_net_s'
|
||||
fake_addr_s = '98.76.54.123'
|
||||
fake_net_t = 'fake_net_t'
|
||||
fake_addr_t = '12.34.56.78'
|
||||
fake_server = {
|
||||
'id': fake_instance_id,
|
||||
'networks': {fake_net_s: [fake_addr_s], fake_net_t: [fake_addr_t]},
|
||||
'addresses': {fake_net_s: {'addr': fake_addr_s},
|
||||
fake_net_t: {'addr': fake_addr_t}},
|
||||
}
|
||||
expected = {
|
||||
'backend_details': {
|
||||
'username': fake_user,
|
||||
'password': fake_pass,
|
||||
'pk_path': self._manager.path_to_private_key,
|
||||
'ip': fake_addr_s,
|
||||
'public_address': fake_addr_t,
|
||||
'instance_id': fake_instance_id,
|
||||
}
|
||||
}
|
||||
|
||||
def fake_get_config_option(attr):
|
||||
if attr == 'service_net_name_or_ip':
|
||||
return s
|
||||
elif attr == 'tenant_net_name_or_ip':
|
||||
return t
|
||||
elif attr == 'service_instance_name_or_id':
|
||||
return fake_instance_id
|
||||
elif attr == 'service_instance_user':
|
||||
return fake_user
|
||||
elif attr == 'service_instance_password':
|
||||
return fake_pass
|
||||
else:
|
||||
raise exception.ManilaException("Wrong test data provided.")
|
||||
|
||||
self.mock_object(
|
||||
self._manager.compute_api, 'server_get_by_name_or_id',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.mock_object(
|
||||
self._manager, 'get_config_option',
|
||||
mock.Mock(side_effect=fake_get_config_option))
|
||||
|
||||
if is_valid:
|
||||
actual = self._manager.get_common_server()
|
||||
self.assertEqual(expected, actual)
|
||||
else:
|
||||
self.assertRaises(
|
||||
exception.ManilaException,
|
||||
self._manager.get_common_server)
|
||||
self.assertTrue(
|
||||
self._manager.compute_api.server_get_by_name_or_id.called)
|
||||
|
Loading…
Reference in New Issue
Block a user