Merge "Splits service_instance module from generic driver"
This commit is contained in:
commit
6849850945
|
@ -537,3 +537,7 @@ class InstanceNotFound(NotFound):
|
|||
|
||||
class BridgeDoesNotExist(ManilaException):
|
||||
message = _("Bridge %(bridge)s does not exist.")
|
||||
|
||||
|
||||
class ServiceInstanceException(ManilaException):
|
||||
message = _("Exception in service instance manager occurred.")
|
||||
|
|
|
@ -144,6 +144,13 @@ class API(base.Base):
|
|||
raise exception.NetworkException(code=e.status_code,
|
||||
message=e.message)
|
||||
|
||||
def delete_subnet(self, subnet_id):
|
||||
try:
|
||||
self.client.delete_subnet(subnet_id)
|
||||
except neutron_client_exc.NeutronClientException as e:
|
||||
raise exception.NetworkException(code=e.status_code,
|
||||
message=e.message)
|
||||
|
||||
def list_ports(self, **search_opts):
|
||||
"""List ports for the client based on search options."""
|
||||
return self.client.list_ports(**search_opts).get('ports')
|
||||
|
@ -233,6 +240,18 @@ class API(base.Base):
|
|||
raise exception.NetworkException(code=e.status_code,
|
||||
message=e.message)
|
||||
|
||||
def router_remove_interface(self, router_id, subnet_id, port_id=None):
|
||||
body = {}
|
||||
if subnet_id:
|
||||
body['subnet_id'] = subnet_id
|
||||
if port_id:
|
||||
body['port_id'] = port_id
|
||||
try:
|
||||
self.client.remove_interface_router(router_id, body)
|
||||
except neutron_client_exc.NeutronClientException as e:
|
||||
raise exception.NetworkException(code=e.status_code,
|
||||
message=e.message)
|
||||
|
||||
def router_list(self):
|
||||
try:
|
||||
return self.client.list_routers().get('routers', {})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2014 Mirantis Inc.
|
||||
# Copyright (c) 2014 NetApp, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -12,96 +12,55 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Generic Driver for shares.
|
||||
|
||||
"""
|
||||
"""Generic Driver for shares."""
|
||||
|
||||
import ConfigParser
|
||||
import netaddr
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from manila import compute
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.network.linux import ip_lib
|
||||
from manila.network.neutron import api as neutron
|
||||
from manila.openstack.common import importutils
|
||||
from manila.openstack.common import log as logging
|
||||
from manila.share import driver
|
||||
from manila import utils
|
||||
from manila.share.drivers import service_instance
|
||||
from manila import volume
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
share_opts = [
|
||||
cfg.StrOpt('service_image_name',
|
||||
default='manila-service-image',
|
||||
help="Name of image in glance, that will be used to create "
|
||||
"service instance"),
|
||||
cfg.StrOpt('smb_template_config_path',
|
||||
default='$state_path/smb.conf',
|
||||
help="Path to smb config"),
|
||||
help="Path to smb config."),
|
||||
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"),
|
||||
help="Name of service instance."),
|
||||
cfg.StrOpt('volume_name_template',
|
||||
default='manila-share-%s',
|
||||
help="Volume name template"),
|
||||
cfg.StrOpt('manila_service_keypair_name',
|
||||
default='manila-service',
|
||||
help="Name of keypair that will be created and used "
|
||||
"for service instance"),
|
||||
cfg.StrOpt('path_to_public_key',
|
||||
default='/home/stack/.ssh/id_rsa.pub',
|
||||
help="Path to hosts public key"),
|
||||
cfg.StrOpt('path_to_private_key',
|
||||
default='/home/stack/.ssh/id_rsa',
|
||||
help="Path to hosts private key"),
|
||||
help="Volume name template."),
|
||||
cfg.StrOpt('volume_snapshot_name_template',
|
||||
default='manila-snapshot-%s',
|
||||
help="Volume snapshot name template"),
|
||||
cfg.IntOpt('max_time_to_build_instance',
|
||||
default=300,
|
||||
help="Maximum time to wait for creating service instance"),
|
||||
help="Volume snapshot name template."),
|
||||
cfg.StrOpt('share_mount_path',
|
||||
default='/shares',
|
||||
help="Parent path in service instance where shares "
|
||||
"will be mounted"),
|
||||
"will be mounted."),
|
||||
cfg.IntOpt('max_time_to_create_volume',
|
||||
default=180,
|
||||
help="Maximum time to wait for creating cinder volume"),
|
||||
help="Maximum time to wait for creating cinder volume."),
|
||||
cfg.IntOpt('max_time_to_attach',
|
||||
default=120,
|
||||
help="Maximum time to wait for attaching cinder volume"),
|
||||
cfg.IntOpt('service_instance_flavor_id',
|
||||
default=100,
|
||||
help="ID of flavor, that will be used for service instance "
|
||||
"creation"),
|
||||
help="Maximum time to wait for attaching cinder volume."),
|
||||
cfg.StrOpt('service_instance_smb_config_path',
|
||||
default='$share_mount_path/smb.conf',
|
||||
help="Path to smb config in service instance"),
|
||||
cfg.StrOpt('service_network_name',
|
||||
default='manila_service_network',
|
||||
help="Name of manila service network"),
|
||||
cfg.StrOpt('service_network_cidr',
|
||||
default='10.254.0.0/16',
|
||||
help="CIDR of manila service network"),
|
||||
cfg.StrOpt('interface_driver',
|
||||
default='manila.network.linux.interface.OVSInterfaceDriver',
|
||||
help="Vif driver"),
|
||||
help="Path to smb config in service instance."),
|
||||
cfg.ListOpt('share_helpers',
|
||||
default=[
|
||||
'CIFS=manila.share.drivers.generic.CIFSHelper',
|
||||
|
@ -113,31 +72,8 @@ share_opts = [
|
|||
CONF = cfg.CONF
|
||||
CONF.register_opts(share_opts)
|
||||
|
||||
|
||||
def synchronized(f):
|
||||
"""Decorates function with unique locks for each share network."""
|
||||
def wrapped_func(self, *args, **kwargs):
|
||||
for arg in args:
|
||||
share_network_id = getattr(arg, 'share_network_id', None)
|
||||
if isinstance(arg, dict):
|
||||
share_network_id = arg.get('share_network_id', None)
|
||||
if share_network_id:
|
||||
break
|
||||
else:
|
||||
raise exception.\
|
||||
ManilaException(_('Could not get share network id'))
|
||||
with self.share_networks_locks.setdefault(share_network_id,
|
||||
threading.RLock()):
|
||||
return f(self, *args, **kwargs)
|
||||
return wrapped_func
|
||||
|
||||
|
||||
def _ssh_exec(server, command):
|
||||
"""Executes ssh commands and checks/restores ssh connection."""
|
||||
if not server['ssh'].get_transport().is_active():
|
||||
server['ssh_pool'].remove(server['ssh'])
|
||||
server['ssh'] = server['ssh_pool'].create()
|
||||
return utils.ssh_execute(server['ssh'], ' '.join(command))
|
||||
_ssh_exec = service_instance._ssh_exec
|
||||
synchronized = service_instance.synchronized
|
||||
|
||||
|
||||
class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
|
@ -149,59 +85,31 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
self.admin_context = context.get_admin_context()
|
||||
self.db = db
|
||||
self.configuration.append_config_values(share_opts)
|
||||
self._helpers = None
|
||||
self._helpers = {}
|
||||
|
||||
def check_for_setup_error(self):
|
||||
"""Returns an error if prerequisites aren't met."""
|
||||
if not self.configuration.service_instance_user:
|
||||
raise exception.ManilaException(_('Service instance user is not '
|
||||
'specified'))
|
||||
pass
|
||||
|
||||
def do_setup(self, context):
|
||||
"""Any initialization the generic driver does while starting."""
|
||||
super(GenericShareDriver, self).do_setup(context)
|
||||
self.compute_api = compute.API()
|
||||
self.volume_api = volume.API()
|
||||
self.neutron_api = neutron.API()
|
||||
self.share_networks_locks = {}
|
||||
self.share_networks_servers = {}
|
||||
attempts = 5
|
||||
while attempts:
|
||||
try:
|
||||
self.service_tenant_id = self.neutron_api.admin_tenant_id
|
||||
break
|
||||
except exception.NetworkException:
|
||||
LOG.debug(_('Connection to neutron failed'))
|
||||
attempts -= 1
|
||||
time.sleep(3)
|
||||
else:
|
||||
raise exception.\
|
||||
ManilaException(_('Can not receive service tenant id'))
|
||||
self.service_network_id = self._get_service_network()
|
||||
self.vif_driver = importutils.\
|
||||
import_class(self.configuration.interface_driver)()
|
||||
self._setup_connectivity_with_service_instances()
|
||||
self.service_instance_manager = service_instance.\
|
||||
ServiceInstanceManager(self.db, self._helpers)
|
||||
self.get_service_instance = self.service_instance_manager.\
|
||||
get_service_instance
|
||||
self.share_networks_locks = self.service_instance_manager.\
|
||||
share_networks_locks
|
||||
self.share_networks_servers = self.service_instance_manager.\
|
||||
share_networks_servers
|
||||
self._setup_helpers()
|
||||
|
||||
def _get_service_network(self):
|
||||
"""Finds existing or creates new service network."""
|
||||
service_network_name = self.configuration.service_network_name
|
||||
networks = [network for network in self.neutron_api.
|
||||
get_all_tenant_networks(self.service_tenant_id)
|
||||
if network['name'] == service_network_name]
|
||||
if len(networks) > 1:
|
||||
raise exception.ManilaException(_('Ambiguous service networks'))
|
||||
elif not networks:
|
||||
return self.neutron_api.network_create(self.service_tenant_id,
|
||||
service_network_name)['id']
|
||||
else:
|
||||
return networks[0]['id']
|
||||
|
||||
def _setup_helpers(self):
|
||||
"""Initializes protocol-specific NAS drivers."""
|
||||
self._helpers = {}
|
||||
for helper_str in self.configuration.share_helpers:
|
||||
share_proto, _, import_str = helper_str.partition('=')
|
||||
share_proto, __, import_str = helper_str.partition('=')
|
||||
helper = importutils.import_class(import_str)
|
||||
self._helpers[share_proto.upper()] = helper(self._execute,
|
||||
self.configuration,
|
||||
|
@ -210,9 +118,10 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
def create_share(self, context, share):
|
||||
"""Creates share."""
|
||||
if share['share_network_id'] is None:
|
||||
raise exception.\
|
||||
ManilaException(_('Share Network is not specified'))
|
||||
server = self._get_service_instance(self.admin_context, share)
|
||||
raise exception.ManilaException(
|
||||
_('Share Network is not specified'))
|
||||
server = self.get_service_instance(self.admin_context,
|
||||
share_network_id=share['share_network_id'])
|
||||
volume = self._allocate_container(context, share)
|
||||
volume = self._attach_volume(context, share, server, volume)
|
||||
self._format_device(server, volume)
|
||||
|
@ -314,8 +223,8 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
if len(volume_snapshot_list) == 1:
|
||||
volume_snapshot = volume_snapshot_list[0]
|
||||
elif len(volume_snapshot_list) > 1:
|
||||
raise exception.\
|
||||
ManilaException(_('Error. Ambiguous volume snaphots'))
|
||||
raise exception.ManilaException(
|
||||
_('Error. Ambiguous volume snaphots'))
|
||||
return volume_snapshot
|
||||
|
||||
@synchronized
|
||||
|
@ -341,382 +250,16 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
% self.configuration.max_time_to_attach)
|
||||
|
||||
def _get_device_path(self, context, server):
|
||||
"""Returns device path, that will be used for cinder volume attaching.
|
||||
"""
|
||||
"""Returns device path for cinder volume attaching."""
|
||||
volumes = self.compute_api.instance_volumes_list(context, server['id'])
|
||||
used_literals = set(volume.device[-1] for volume in volumes
|
||||
if '/dev/vd' in volume.device)
|
||||
lit = 'b'
|
||||
while lit in used_literals:
|
||||
lit = chr(ord(lit) + 1)
|
||||
device_name = '/dev/vd' + lit
|
||||
device_name = '/dev/vd%s' % lit
|
||||
return device_name
|
||||
|
||||
def _get_service_instance_name(self, share):
|
||||
"""Returns service vms name."""
|
||||
return self.configuration.service_instance_name_template % \
|
||||
share['share_network_id']
|
||||
|
||||
def _get_server_ip(self, server):
|
||||
"""Returns service vms ip address."""
|
||||
net = server['networks']
|
||||
try:
|
||||
net_ips = net[self.configuration.service_network_name]
|
||||
return net_ips[0]
|
||||
except KeyError:
|
||||
msg = _('Service vm is not attached to %s network')
|
||||
except IndexError:
|
||||
msg = _('Service vm has no ips on %s network')
|
||||
msg = msg % self.configuration.service_network_name
|
||||
LOG.error(msg)
|
||||
raise exception.ManilaException(msg)
|
||||
|
||||
def _ensure_or_delete_server(self, context, server, update=False):
|
||||
"""Ensures that server exists and active, otherwise deletes it."""
|
||||
if update:
|
||||
try:
|
||||
server.update(self.compute_api.server_get(context,
|
||||
server['id']))
|
||||
except exception.InstanceNotFound as e:
|
||||
LOG.debug(e)
|
||||
return False
|
||||
if server['status'] == 'ACTIVE':
|
||||
if self._check_server_availability(server):
|
||||
return True
|
||||
|
||||
self._delete_server(context, server)
|
||||
return False
|
||||
|
||||
def _delete_server(self, context, server):
|
||||
"""Deletes the server."""
|
||||
self.compute_api.server_delete(context, server['id'])
|
||||
t = time.time()
|
||||
while time.time() - t < self.configuration.\
|
||||
max_time_to_build_instance:
|
||||
try:
|
||||
server = self.compute_api.server_get(context,
|
||||
server['id'])
|
||||
except exception.InstanceNotFound:
|
||||
LOG.debug(_('Service instance was deleted succesfully'))
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise exception.ManilaException(_('Instance have not been deleted '
|
||||
'in %ss. Giving up') %
|
||||
self.configuration.max_time_to_build_instance)
|
||||
|
||||
@synchronized
|
||||
def _get_service_instance(self, context, share, create=True):
|
||||
"""Finds or creates and setups service vm."""
|
||||
server = self.share_networks_servers.get(share['share_network_id'], {})
|
||||
old_server_ip = server.get('ip', None)
|
||||
if server and self._ensure_or_delete_server(context,
|
||||
server,
|
||||
update=True):
|
||||
return server
|
||||
else:
|
||||
server = {}
|
||||
service_instance_name = self._get_service_instance_name(share)
|
||||
search_opts = {'name': service_instance_name}
|
||||
servers = self.compute_api.server_list(context, search_opts, True)
|
||||
if len(servers) == 1:
|
||||
server = servers[0]
|
||||
server['ip'] = self._get_server_ip(server)
|
||||
old_server_ip = server['ip']
|
||||
if not self._ensure_or_delete_server(context, server):
|
||||
server.clear()
|
||||
elif len(servers) > 1:
|
||||
raise exception.\
|
||||
ManilaException(_('Ambiguous service instances'))
|
||||
if not server and create:
|
||||
server = self._create_service_instance(context,
|
||||
service_instance_name,
|
||||
share, old_server_ip)
|
||||
if server:
|
||||
server['share_network_id'] = share['share_network_id']
|
||||
server['ip'] = self._get_server_ip(server)
|
||||
server['ssh_pool'] = self._get_ssh_pool(server)
|
||||
server['ssh'] = server['ssh_pool'].create()
|
||||
for helper in self._helpers.values():
|
||||
helper.init_helper(server)
|
||||
|
||||
self.share_networks_servers[share['share_network_id']] = server
|
||||
return server
|
||||
|
||||
def _get_ssh_pool(self, server):
|
||||
"""Returns ssh connection pool for service vm."""
|
||||
ssh_pool = utils.SSHPool(server['ip'], 22, None,
|
||||
self.configuration.service_instance_user,
|
||||
password=self.configuration.service_instance_password,
|
||||
privatekey=self.configuration.path_to_private_key,
|
||||
max_size=1)
|
||||
return ssh_pool
|
||||
|
||||
def _get_key(self, context):
|
||||
"""Returns name of key, that will be injected to service vm."""
|
||||
if not self.configuration.path_to_public_key or \
|
||||
not self.configuration.path_to_private_key:
|
||||
return
|
||||
path_to_public_key = \
|
||||
os.path.expanduser(self.configuration.path_to_public_key)
|
||||
path_to_private_key = \
|
||||
os.path.expanduser(self.configuration.path_to_private_key)
|
||||
if not os.path.exists(path_to_public_key) or \
|
||||
not os.path.exists(path_to_private_key):
|
||||
return
|
||||
keypair_name = self.configuration.manila_service_keypair_name
|
||||
keypairs = [k for k in self.compute_api.keypair_list(context)
|
||||
if k.name == keypair_name]
|
||||
if len(keypairs) > 1:
|
||||
raise exception.ManilaException(_('Ambiguous keypairs'))
|
||||
|
||||
public_key, _ = self._execute('cat',
|
||||
path_to_public_key,
|
||||
run_as_root=True)
|
||||
if not keypairs:
|
||||
keypair = self.compute_api.keypair_import(context, keypair_name,
|
||||
public_key)
|
||||
else:
|
||||
keypair = keypairs[0]
|
||||
if keypair.public_key != public_key:
|
||||
LOG.debug('Public key differs from existing keypair. '
|
||||
'Creating new keypair')
|
||||
self.compute_api.keypair_delete(context, keypair.id)
|
||||
keypair = self.compute_api.keypair_import(context,
|
||||
keypair_name,
|
||||
public_key)
|
||||
return keypair.name
|
||||
|
||||
def _get_service_image(self, context):
|
||||
"""Returns ID of service image, that will be used for service vm
|
||||
creating.
|
||||
"""
|
||||
images = [image.id for image in self.compute_api.image_list(context)
|
||||
if image.name == self.configuration.service_image_name]
|
||||
if len(images) == 1:
|
||||
return images[0]
|
||||
elif not images:
|
||||
raise exception.\
|
||||
ManilaException(_('No appropriate image was found'))
|
||||
else:
|
||||
raise exception.ManilaException(_('Ambiguous image name'))
|
||||
|
||||
def _create_service_instance(self, context, instance_name, share,
|
||||
old_server_ip):
|
||||
"""Creates service vm and sets up networking for it."""
|
||||
service_image_id = self._get_service_image(context)
|
||||
key_name = self._get_key(context)
|
||||
if not self.configuration.service_instance_password and not key_name:
|
||||
raise exception.ManilaException(_('Neither service instance'
|
||||
'password nor key are available'))
|
||||
|
||||
port = self._setup_network_for_instance(context, share, old_server_ip)
|
||||
try:
|
||||
self._setup_connectivity_with_service_instances()
|
||||
except Exception as e:
|
||||
LOG.debug(e)
|
||||
self.neutron_api.delete_port(port['id'])
|
||||
raise
|
||||
service_instance = self.compute_api.server_create(context,
|
||||
instance_name, service_image_id,
|
||||
self.configuration.service_instance_flavor_id,
|
||||
key_name, None, None,
|
||||
nics=[{'port-id': port['id']}])
|
||||
|
||||
t = time.time()
|
||||
while time.time() - t < self.configuration.max_time_to_build_instance:
|
||||
if service_instance['status'] == 'ACTIVE':
|
||||
break
|
||||
if service_instance['status'] == 'ERROR':
|
||||
raise exception.ManilaException(_('Failed to build service '
|
||||
'instance'))
|
||||
time.sleep(1)
|
||||
try:
|
||||
service_instance = self.compute_api.server_get(context,
|
||||
service_instance['id'])
|
||||
except exception.InstanceNotFound as e:
|
||||
LOG.debug(e)
|
||||
else:
|
||||
raise exception.ManilaException(_('Instance have not been spawned '
|
||||
'in %ss. Giving up') %
|
||||
self.configuration.max_time_to_build_instance)
|
||||
|
||||
service_instance['ip'] = self._get_server_ip(service_instance)
|
||||
if not self._check_server_availability(service_instance):
|
||||
raise exception.ManilaException(_('SSH connection have not been '
|
||||
'established in %ss. Giving up')
|
||||
% self.configuration.max_time_to_build_instance)
|
||||
return service_instance
|
||||
|
||||
def _check_server_availability(self, server):
|
||||
t = time.time()
|
||||
while time.time() - t < self.configuration.max_time_to_build_instance:
|
||||
LOG.debug('Checking service vm availablity')
|
||||
try:
|
||||
socket.socket().connect((server['ip'], 22))
|
||||
LOG.debug(_('Service vm is available via ssh.'))
|
||||
return True
|
||||
except socket.error as e:
|
||||
LOG.debug(e)
|
||||
LOG.debug(_('Server is not available through ssh. Waiting...'))
|
||||
time.sleep(5)
|
||||
return False
|
||||
|
||||
def _setup_network_for_instance(self, context, share, old_server_ip):
|
||||
"""Setups network for service vm."""
|
||||
service_network = self.neutron_api.get_network(self.service_network_id)
|
||||
all_service_subnets = [self.neutron_api.get_subnet(subnet_id)
|
||||
for subnet_id in service_network['subnets']]
|
||||
service_subnets = [subnet for subnet in all_service_subnets
|
||||
if subnet['name'] == share['share_network_id']]
|
||||
if len(service_subnets) > 1:
|
||||
raise exception.ManilaException(_('Ambiguous subnets'))
|
||||
elif not service_subnets:
|
||||
service_subnet = \
|
||||
self.neutron_api.subnet_create(self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
share['share_network_id'],
|
||||
self._get_cidr_for_subnet(all_service_subnets))
|
||||
else:
|
||||
service_subnet = service_subnets[0]
|
||||
|
||||
share_network = self.db.share_network_get(context,
|
||||
share['share_network_id'])
|
||||
private_router = self._get_private_router(share_network)
|
||||
try:
|
||||
self.neutron_api.router_add_interface(private_router['id'],
|
||||
service_subnet['id'])
|
||||
except exception.NetworkException as e:
|
||||
if 'already has' not in e.msg:
|
||||
raise
|
||||
LOG.debug(_('Subnet %(subnet_id)s is already attached to the '
|
||||
'router %(router_id)s') %
|
||||
{'subnet_id': service_subnet['id'],
|
||||
'router_id': private_router['id']})
|
||||
|
||||
return self.neutron_api.create_port(self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
subnet_id=service_subnet['id'],
|
||||
fixed_ip=old_server_ip,
|
||||
device_owner='manila')
|
||||
|
||||
def _get_private_router(self, share_network):
|
||||
"""Returns router attached to private subnet gateway."""
|
||||
private_subnet = self.neutron_api.\
|
||||
get_subnet(share_network['neutron_subnet_id'])
|
||||
if not private_subnet['gateway_ip']:
|
||||
raise exception.ManilaException(_('Subnet must have gateway'))
|
||||
private_network_ports = [p for p in self.neutron_api.list_ports(
|
||||
network_id=share_network['neutron_net_id'])]
|
||||
for p in private_network_ports:
|
||||
fixed_ip = p['fixed_ips'][0]
|
||||
if fixed_ip['subnet_id'] == private_subnet['id'] and \
|
||||
fixed_ip['ip_address'] == private_subnet['gateway_ip']:
|
||||
private_subnet_gateway_port = p
|
||||
break
|
||||
else:
|
||||
raise exception.ManilaException(_('Subnet gateway is not attached '
|
||||
'the router'))
|
||||
private_subnet_router = self.neutron_api.show_router(
|
||||
private_subnet_gateway_port['device_id'])
|
||||
return private_subnet_router
|
||||
|
||||
def _setup_connectivity_with_service_instances(self):
|
||||
"""Setups connectivity with service instances by creating port
|
||||
in service network, creating and setting up required network devices.
|
||||
"""
|
||||
port = self._setup_service_port()
|
||||
interface_name = self.vif_driver.get_device_name(port)
|
||||
self.vif_driver.plug(port['id'], interface_name, port['mac_address'])
|
||||
ip_cidrs = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
subnet = self.neutron_api.get_subnet(fixed_ip['subnet_id'])
|
||||
net = netaddr.IPNetwork(subnet['cidr'])
|
||||
ip_cidr = '%s/%s' % (fixed_ip['ip_address'], net.prefixlen)
|
||||
ip_cidrs.append(ip_cidr)
|
||||
|
||||
self.vif_driver.init_l3(interface_name, ip_cidrs)
|
||||
|
||||
# ensure that interface is first in the list
|
||||
device = ip_lib.IPDevice(interface_name)
|
||||
device.route.pullup_route(interface_name)
|
||||
|
||||
# here we are checking for garbage devices from removed service port
|
||||
self._clean_garbage(device)
|
||||
|
||||
def _clean_garbage(self, device):
|
||||
"""Finds and removes network device, that was associated with deleted
|
||||
service port.
|
||||
"""
|
||||
list_dev = []
|
||||
for dev in ip_lib.IPWrapper().get_devices():
|
||||
if dev.name != device.name and dev.name[:3] == device.name[:3]:
|
||||
cidr_set = set()
|
||||
for a in dev.addr.list():
|
||||
if a['ip_version'] == 4:
|
||||
cidr_set.add(str(netaddr.IPNetwork(a['cidr']).cidr))
|
||||
list_dev.append((dev.name, cidr_set))
|
||||
device_cidr_set = set(str(netaddr.IPNetwork(a['cidr']).cidr)
|
||||
for a in device.addr.list()
|
||||
if a['ip_version'] == 4)
|
||||
|
||||
for dev_name, cidr_set in list_dev:
|
||||
if device_cidr_set & cidr_set:
|
||||
self.vif_driver.unplug(dev_name)
|
||||
|
||||
def _setup_service_port(self):
|
||||
"""Find or creates neutron port, that will be used for connectivity
|
||||
with service instances.
|
||||
"""
|
||||
ports = [port for port in self.neutron_api.
|
||||
list_ports(device_id='manila-share')]
|
||||
if len(ports) > 1:
|
||||
raise exception.\
|
||||
ManilaException(_('Error. Ambiguous service ports'))
|
||||
elif not ports:
|
||||
try:
|
||||
stdout, stderr = self._execute('hostname')
|
||||
host = stdout.strip()
|
||||
except exception.ProcessExecutionError as e:
|
||||
msg = _('Unable to get host. %s') % e.stderr
|
||||
raise exception.ManilaException(msg)
|
||||
port = self.neutron_api.create_port(self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
device_id='manila-share',
|
||||
device_owner='manila:generic_driver',
|
||||
host_id=host)
|
||||
else:
|
||||
port = ports[0]
|
||||
|
||||
network = self.neutron_api.get_network(self.service_network_id)
|
||||
subnets = set(network['subnets'])
|
||||
port_fixed_ips = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
port_fixed_ips.append({'subnet_id': fixed_ip['subnet_id'],
|
||||
'ip_address': fixed_ip['ip_address']})
|
||||
if fixed_ip['subnet_id'] in subnets:
|
||||
subnets.remove(fixed_ip['subnet_id'])
|
||||
|
||||
# If there are subnets here that means that
|
||||
# we need to add those to the port and call update.
|
||||
if subnets:
|
||||
port_fixed_ips.extend([dict(subnet_id=s) for s in subnets])
|
||||
port = self.neutron_api.update_port_fixed_ips(
|
||||
port['id'], {'fixed_ips': port_fixed_ips})
|
||||
|
||||
return port
|
||||
|
||||
def _get_cidr_for_subnet(self, subnets):
|
||||
"""Returns not used cidr for service subnet creating."""
|
||||
used_cidrs = set(subnet['cidr'] for subnet in subnets)
|
||||
serv_cidr = netaddr.IPNetwork(self.configuration.service_network_cidr)
|
||||
for subnet in serv_cidr.subnet(29):
|
||||
cidr = str(subnet.cidr)
|
||||
if cidr not in used_cidrs:
|
||||
return cidr
|
||||
else:
|
||||
raise exception.ManilaException(_('No available cidrs'))
|
||||
|
||||
def _allocate_container(self, context, share, snapshot=None):
|
||||
"""Creates cinder volume, associated to share by name."""
|
||||
volume_snapshot = None
|
||||
|
@ -748,8 +291,8 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
if volume:
|
||||
self.volume_api.delete(context, volume['id'])
|
||||
t = time.time()
|
||||
while time.time() - t < self.configuration.\
|
||||
max_time_to_create_volume:
|
||||
while (time.time() - t <
|
||||
self.configuration.max_time_to_create_volume):
|
||||
try:
|
||||
volume = self.volume_api.get(context, volume['id'])
|
||||
except exception.VolumeNotFound:
|
||||
|
@ -785,15 +328,16 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
|
||||
data['total_capacity_gb'] = 'infinite'
|
||||
data['free_capacity_gb'] = 'infinite'
|
||||
data['reserved_percentage'] = \
|
||||
self.configuration.reserved_share_percentage
|
||||
data['reserved_percentage'] = (self.configuration.
|
||||
reserved_share_percentage)
|
||||
data['QoS_support'] = False
|
||||
|
||||
self._stats = data
|
||||
|
||||
def create_share_from_snapshot(self, context, share, snapshot):
|
||||
"""Is called to create share from snapshot."""
|
||||
server = self._get_service_instance(self.admin_context, share)
|
||||
server = self.get_service_instance(self.admin_context,
|
||||
share_network_id=share['share_network_id'])
|
||||
volume = self._allocate_container(context, share, snapshot)
|
||||
volume = self._attach_volume(context, share, server, volume)
|
||||
self._mount_device(context, share, server, volume)
|
||||
|
@ -805,8 +349,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
"""Deletes share."""
|
||||
if not share['share_network_id']:
|
||||
return
|
||||
server = self._get_service_instance(self.admin_context,
|
||||
share, create=False)
|
||||
server = self.get_service_instance(self.admin_context,
|
||||
share_network_id=share['share_network_id'],
|
||||
create=False)
|
||||
if server:
|
||||
self._get_helper(share).remove_export(server, share['name'])
|
||||
self._unmount_device(context, share, server)
|
||||
|
@ -816,8 +361,8 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
def create_snapshot(self, context, snapshot):
|
||||
"""Creates a snapshot."""
|
||||
volume = self._get_volume(context, snapshot['share_id'])
|
||||
volume_snapshot_name = self.configuration.\
|
||||
volume_snapshot_name_template % snapshot['id']
|
||||
volume_snapshot_name = (self.configuration.
|
||||
volume_snapshot_name_template % snapshot['id'])
|
||||
volume_snapshot = self.volume_api.create_snapshot_force(context,
|
||||
volume['id'],
|
||||
volume_snapshot_name,
|
||||
|
@ -859,7 +404,8 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
|
||||
def ensure_share(self, context, share):
|
||||
"""Ensure that storage are mounted and exported."""
|
||||
server = self._get_service_instance(context, share)
|
||||
server = self.get_service_instance(context,
|
||||
share_network_id=share['share_network_id'])
|
||||
volume = self._get_volume(context, share['id'])
|
||||
volume = self._attach_volume(context, share, server, volume)
|
||||
self._mount_device(context, share, server, volume)
|
||||
|
@ -867,9 +413,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
|
||||
def allow_access(self, context, share, access):
|
||||
"""Allow access to the share."""
|
||||
server = self._get_service_instance(self.admin_context,
|
||||
share,
|
||||
create=False)
|
||||
server = self.get_service_instance(self.admin_context,
|
||||
share_network_id=share['share_network_id'],
|
||||
create=False)
|
||||
if not server:
|
||||
raise exception.ManilaException('Server not found. Try to '
|
||||
'restart manila share service')
|
||||
|
@ -881,9 +427,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
|||
"""Deny access to the share."""
|
||||
if not share['share_network_id']:
|
||||
return
|
||||
server = self._get_service_instance(self.admin_context,
|
||||
share,
|
||||
create=False)
|
||||
server = self.get_service_instance(self.admin_context,
|
||||
share_network_id=share['share_network_id'],
|
||||
create=False)
|
||||
if server:
|
||||
self._get_helper(share).deny_access(server, share['name'],
|
||||
access['access_type'],
|
||||
|
@ -1009,8 +555,7 @@ class CIFSHelper(NASHelperBase):
|
|||
local_config = self._create_local_config(server['share_network_id'])
|
||||
config_dir = os.path.dirname(self.config_path)
|
||||
try:
|
||||
_ssh_exec(server, ['sudo', 'mkdir',
|
||||
config_dir])
|
||||
_ssh_exec(server, ['sudo', 'mkdir', config_dir])
|
||||
except exception.ProcessExecutionError as e:
|
||||
if 'File exists' not in e.stderr:
|
||||
raise
|
||||
|
@ -1068,12 +613,12 @@ class CIFSHelper(NASHelperBase):
|
|||
self._update_config(parser, config)
|
||||
self._write_remote_config(config, server)
|
||||
_ssh_exec(server, ['sudo', 'smbcontrol', 'all', 'close-share',
|
||||
share_name])
|
||||
share_name])
|
||||
|
||||
@synchronized
|
||||
def _write_remote_config(self, config, server):
|
||||
with open(config, 'r') as f:
|
||||
cfg = "'" + f.read() + "'"
|
||||
cfg = "'%s'" % f.read()
|
||||
_ssh_exec(server, ['echo %s > %s' % (cfg, self.config_path)])
|
||||
|
||||
def allow_access(self, server, share_name, access_type, access):
|
||||
|
@ -1131,8 +676,7 @@ class CIFSHelper(NASHelperBase):
|
|||
#Check that configuration is correct
|
||||
with open(self.test_config, 'w') as fp:
|
||||
parser.write(fp)
|
||||
self._execute('testparm', '-s', self.test_config,
|
||||
check_exit_code=True)
|
||||
self._execute('testparm', '-s', self.test_config, check_exit_code=True)
|
||||
#save it
|
||||
with open(config, 'w') as fp:
|
||||
parser.write(fp)
|
||||
|
|
|
@ -0,0 +1,578 @@
|
|||
# Copyright (c) 2014 NetApp, 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.
|
||||
|
||||
"""Module for managing nova instances for share drivers."""
|
||||
|
||||
import netaddr
|
||||
import os
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from manila import compute
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.network.linux import ip_lib
|
||||
from manila.network.neutron import api as neutron
|
||||
from manila.openstack.common import importutils
|
||||
from manila.openstack.common import log as logging
|
||||
from manila import utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
server_opts = [
|
||||
cfg.StrOpt('service_image_name',
|
||||
default='manila-service-image',
|
||||
help="Name of image in glance, that will be used to create "
|
||||
"service instance."),
|
||||
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 "
|
||||
"for service instance."),
|
||||
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.IntOpt('service_instance_flavor_id',
|
||||
default=100,
|
||||
help="ID of flavor, that will be used for service instance "
|
||||
"creation."),
|
||||
cfg.StrOpt('service_network_name',
|
||||
default='manila_service_network',
|
||||
help="Name of manila service network."),
|
||||
cfg.StrOpt('service_network_cidr',
|
||||
default='10.254.0.0/16',
|
||||
help="CIDR of manila service network."),
|
||||
cfg.StrOpt('interface_driver',
|
||||
default='manila.network.linux.interface.OVSInterfaceDriver',
|
||||
help="Vif driver."),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(server_opts)
|
||||
|
||||
|
||||
def synchronized(f):
|
||||
"""Decorates function with unique locks for each share network.
|
||||
|
||||
Share network id must be provided either as value/attribute
|
||||
of one of args or as named argument.
|
||||
"""
|
||||
def wrapped_func(self, *args, **kwargs):
|
||||
share_network_id = kwargs.get('share_network_id', None)
|
||||
if not share_network_id:
|
||||
for arg in args:
|
||||
share_network_id = getattr(arg, 'share_network_id', None)
|
||||
if isinstance(arg, dict):
|
||||
share_network_id = arg.get('share_network_id', None)
|
||||
if share_network_id:
|
||||
break
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Could not get '
|
||||
'share network id'))
|
||||
with self.share_networks_locks.setdefault(share_network_id,
|
||||
threading.RLock()):
|
||||
return f(self, *args, **kwargs)
|
||||
return wrapped_func
|
||||
|
||||
|
||||
def _ssh_exec(server, command):
|
||||
"""Executes ssh commands and checks/restores ssh connection."""
|
||||
if not server['ssh'].get_transport().is_active():
|
||||
server['ssh_pool'].remove(server['ssh'])
|
||||
server['ssh'] = server['ssh_pool'].create()
|
||||
return utils.ssh_execute(server['ssh'], ' '.join(command))
|
||||
|
||||
|
||||
class ServiceInstanceManager(object):
|
||||
"""Manages nova instances for various share drivers."""
|
||||
|
||||
def __init__(self, db, _helpers, *args, **kwargs):
|
||||
"""Do initialization."""
|
||||
super(ServiceInstanceManager, self).__init__(*args, **kwargs)
|
||||
if not CONF.service_instance_user:
|
||||
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._helpers = _helpers
|
||||
self.db = db
|
||||
attempts = 5
|
||||
while attempts:
|
||||
try:
|
||||
self.service_tenant_id = self.neutron_api.admin_tenant_id
|
||||
break
|
||||
except exception.NetworkException:
|
||||
LOG.debug(_('Connection to neutron failed.'))
|
||||
attempts -= 1
|
||||
time.sleep(3)
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Can not receive '
|
||||
'service tenant id.'))
|
||||
self.share_networks_locks = {}
|
||||
self.share_networks_servers = {}
|
||||
self.service_network_id = self._get_service_network()
|
||||
self.vif_driver = importutils.import_class(CONF.interface_driver)()
|
||||
self._setup_connectivity_with_service_instances()
|
||||
|
||||
def _get_service_network(self):
|
||||
"""Finds existing or creates new service network."""
|
||||
service_network_name = CONF.service_network_name
|
||||
networks = [network for network in self.neutron_api.
|
||||
get_all_tenant_networks(self.service_tenant_id)
|
||||
if network['name'] == service_network_name]
|
||||
if len(networks) > 1:
|
||||
raise exception.ServiceInstanceException(_('Ambiguous service '
|
||||
'networks.'))
|
||||
elif not networks:
|
||||
return self.neutron_api.network_create(self.service_tenant_id,
|
||||
service_network_name)['id']
|
||||
else:
|
||||
return networks[0]['id']
|
||||
|
||||
def _get_service_instance_name(self, share_network_id):
|
||||
"""Returns service vms name."""
|
||||
return CONF.service_instance_name_template % share_network_id
|
||||
|
||||
def _get_server_ip(self, server):
|
||||
"""Returns service vms ip address."""
|
||||
net = server['networks']
|
||||
try:
|
||||
net_ips = net[CONF.service_network_name]
|
||||
return net_ips[0]
|
||||
except KeyError:
|
||||
msg = _('Service vm is not attached to %s network.')
|
||||
except IndexError:
|
||||
msg = _('Service vm has no ips on %s network.')
|
||||
msg = msg % CONF.service_network_name
|
||||
LOG.error(msg)
|
||||
raise exception.ServiceInstanceException(msg)
|
||||
|
||||
def _ensure_server(self, context, server, update=False):
|
||||
"""Ensures that server exists and active, otherwise deletes it."""
|
||||
if not server:
|
||||
return False
|
||||
if update:
|
||||
try:
|
||||
server.update(self.compute_api.server_get(context,
|
||||
server['id']))
|
||||
except exception.InstanceNotFound as e:
|
||||
LOG.debug(e)
|
||||
return False
|
||||
if server['status'] == 'ACTIVE':
|
||||
if self._check_server_availability(server):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _delete_server(self, context, server):
|
||||
"""Deletes the server."""
|
||||
if not server:
|
||||
return
|
||||
self.compute_api.server_delete(context, server['id'])
|
||||
t = time.time()
|
||||
while time.time() - t < CONF.max_time_to_build_instance:
|
||||
try:
|
||||
server = self.compute_api.server_get(context, server['id'])
|
||||
except exception.InstanceNotFound:
|
||||
LOG.debug(_('Service instance was deleted succesfully.'))
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Instance have not '
|
||||
'been deleted in %ss. Giving up.') %
|
||||
CONF.max_time_to_build_instance)
|
||||
|
||||
@synchronized
|
||||
def get_service_instance(self, context, share_network_id, create=True):
|
||||
"""Finds or creates and sets up service vm."""
|
||||
server = self.share_networks_servers.get(share_network_id, {})
|
||||
old_server_ip = server.get('ip', None)
|
||||
if self._ensure_server(context, server, update=True):
|
||||
return server
|
||||
else:
|
||||
self._delete_server(context, server)
|
||||
server = {}
|
||||
service_instance_name = self._get_service_instance_name(
|
||||
share_network_id)
|
||||
search_opts = {'name': service_instance_name}
|
||||
servers = self.compute_api.server_list(context, search_opts, True)
|
||||
if len(servers) == 1:
|
||||
server = servers[0]
|
||||
server['ip'] = self._get_server_ip(server)
|
||||
old_server_ip = server['ip']
|
||||
if not self._ensure_server(context, server):
|
||||
self._delete_server(context, server)
|
||||
server.clear()
|
||||
elif len(servers) > 1:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Error. Ambiguous service instances.'))
|
||||
if not server and create:
|
||||
server = self._create_service_instance(context,
|
||||
service_instance_name,
|
||||
share_network_id,
|
||||
old_server_ip)
|
||||
if server:
|
||||
server['share_network_id'] = share_network_id
|
||||
server['ip'] = self._get_server_ip(server)
|
||||
server['ssh_pool'] = self._get_ssh_pool(server)
|
||||
server['ssh'] = server['ssh_pool'].create()
|
||||
for helper in self._helpers.values():
|
||||
helper.init_helper(server)
|
||||
|
||||
self.share_networks_servers[share_network_id] = server
|
||||
return server
|
||||
|
||||
def _get_ssh_pool(self, server):
|
||||
"""Returns ssh connection pool for service vm."""
|
||||
ssh_pool = utils.SSHPool(server['ip'], 22, None,
|
||||
CONF.service_instance_user,
|
||||
password=CONF.service_instance_password,
|
||||
privatekey=CONF.path_to_private_key,
|
||||
max_size=1)
|
||||
return ssh_pool
|
||||
|
||||
def _get_key(self, context):
|
||||
"""Returns name of key, that will be injected to service vm."""
|
||||
if not CONF.path_to_public_key or not CONF.path_to_private_key:
|
||||
return
|
||||
path_to_public_key = os.path.expanduser(CONF.path_to_public_key)
|
||||
path_to_private_key = os.path.expanduser(CONF.path_to_private_key)
|
||||
if (not os.path.exists(path_to_public_key) or
|
||||
not os.path.exists(path_to_private_key)):
|
||||
return
|
||||
keypair_name = CONF.manila_service_keypair_name
|
||||
keypairs = [k for k in self.compute_api.keypair_list(context)
|
||||
if k.name == keypair_name]
|
||||
if len(keypairs) > 1:
|
||||
raise exception.ServiceInstanceException(_('Ambiguous keypairs.'))
|
||||
|
||||
public_key, __ = self._execute('cat', path_to_public_key)
|
||||
if not keypairs:
|
||||
keypair = self.compute_api.keypair_import(context,
|
||||
keypair_name,
|
||||
public_key)
|
||||
else:
|
||||
keypair = keypairs[0]
|
||||
if keypair.public_key != public_key:
|
||||
LOG.debug(_('Public key differs from existing keypair. '
|
||||
'Creating new keypair.'))
|
||||
self.compute_api.keypair_delete(context, keypair.id)
|
||||
keypair = self.compute_api.keypair_import(context,
|
||||
keypair_name,
|
||||
public_key)
|
||||
return keypair.name
|
||||
|
||||
def _get_service_image(self, context):
|
||||
"""Returns ID of service image for service vm creating."""
|
||||
images = [image.id for image in self.compute_api.image_list(context)
|
||||
if image.name == CONF.service_image_name]
|
||||
if len(images) == 1:
|
||||
return images[0]
|
||||
elif not images:
|
||||
raise exception.ServiceInstanceException(_('No appropriate '
|
||||
'image was found.'))
|
||||
else:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Ambiguous image name.'))
|
||||
|
||||
def _create_service_instance(self, context, instance_name,
|
||||
share_network_id, old_server_ip):
|
||||
"""Creates service vm and sets up networking for it."""
|
||||
service_image_id = self._get_service_image(context)
|
||||
key_name = self._get_key(context)
|
||||
if not CONF.service_instance_password and not key_name:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Neither service instance password nor key are available.'))
|
||||
|
||||
port = self._setup_network_for_instance(context,
|
||||
share_network_id,
|
||||
old_server_ip)
|
||||
try:
|
||||
self._setup_connectivity_with_service_instances()
|
||||
except Exception as e:
|
||||
LOG.debug(e)
|
||||
self.neutron_api.delete_port(port['id'])
|
||||
raise
|
||||
service_instance = self.compute_api.server_create(context,
|
||||
instance_name,
|
||||
service_image_id,
|
||||
CONF.service_instance_flavor_id,
|
||||
key_name,
|
||||
None,
|
||||
None,
|
||||
nics=[{'port-id': port['id']}])
|
||||
|
||||
t = time.time()
|
||||
while time.time() - t < CONF.max_time_to_build_instance:
|
||||
if service_instance['status'] == 'ACTIVE':
|
||||
break
|
||||
if service_instance['status'] == 'ERROR':
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Failed to build service instance.'))
|
||||
time.sleep(1)
|
||||
try:
|
||||
service_instance = self.compute_api.server_get(context,
|
||||
service_instance['id'])
|
||||
except exception.InstanceNotFound as e:
|
||||
LOG.debug(e)
|
||||
else:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Instance have not been spawned in %ss. Giving up.') %
|
||||
CONF.max_time_to_build_instance)
|
||||
|
||||
service_instance['ip'] = self._get_server_ip(service_instance)
|
||||
if not self._check_server_availability(service_instance):
|
||||
raise exception.ServiceInstanceException(
|
||||
_('SSH connection have not been '
|
||||
'established in %ss. Giving up.') %
|
||||
CONF.max_time_to_build_instance)
|
||||
return service_instance
|
||||
|
||||
def _check_server_availability(self, server):
|
||||
t = time.time()
|
||||
while time.time() - t < CONF.max_time_to_build_instance:
|
||||
LOG.debug(_('Checking service vm availablity.'))
|
||||
try:
|
||||
socket.socket().connect((server['ip'], 22))
|
||||
LOG.debug(_('Service vm is available via ssh.'))
|
||||
return True
|
||||
except socket.error as e:
|
||||
LOG.debug(e)
|
||||
LOG.debug(_('Server is not available through ssh. Waiting...'))
|
||||
time.sleep(5)
|
||||
return False
|
||||
|
||||
def _setup_network_for_instance(self, context, share_network_id,
|
||||
old_server_ip):
|
||||
"""Sets up network for service vm."""
|
||||
service_subnet = self._get_service_subnet(share_network_id)
|
||||
if not service_subnet:
|
||||
service_subnet = self.neutron_api.subnet_create(
|
||||
self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
share_network_id,
|
||||
self._get_cidr_for_subnet())
|
||||
|
||||
private_router = self._get_private_router(share_network_id)
|
||||
try:
|
||||
self.neutron_api.router_add_interface(private_router['id'],
|
||||
service_subnet['id'])
|
||||
except exception.NetworkException as e:
|
||||
if e.kwargs['code'] != 400:
|
||||
raise
|
||||
LOG.debug(_('Subnet %(subnet_id)s is already attached to the '
|
||||
'router %(router_id)s.') %
|
||||
{'subnet_id': service_subnet['id'],
|
||||
'router_id': private_router['id']})
|
||||
|
||||
return self.neutron_api.create_port(self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
subnet_id=service_subnet['id'],
|
||||
fixed_ip=old_server_ip,
|
||||
device_owner='manila')
|
||||
|
||||
def _get_private_router(self, share_network_id):
|
||||
"""Returns router attached to private subnet gateway."""
|
||||
share_network = self.db.share_network_get(self.admin_context,
|
||||
share_network_id)
|
||||
private_subnet = self.neutron_api.get_subnet(
|
||||
share_network['neutron_subnet_id'])
|
||||
if not private_subnet['gateway_ip']:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Subnet must have gateway.'))
|
||||
private_network_ports = [p for p in self.neutron_api.list_ports(
|
||||
network_id=share_network['neutron_net_id'])]
|
||||
for p in private_network_ports:
|
||||
fixed_ip = p['fixed_ips'][0]
|
||||
if (fixed_ip['subnet_id'] == private_subnet['id'] and
|
||||
fixed_ip['ip_address'] == private_subnet['gateway_ip']):
|
||||
private_subnet_gateway_port = p
|
||||
break
|
||||
else:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Subnet gateway is not attached the router.'))
|
||||
private_subnet_router = self.neutron_api.show_router(
|
||||
private_subnet_gateway_port['device_id'])
|
||||
return private_subnet_router
|
||||
|
||||
def _setup_connectivity_with_service_instances(self):
|
||||
"""Sets up connectivity with service instances.
|
||||
|
||||
Creates creating port in service network, creating and setting up
|
||||
required network devices.
|
||||
"""
|
||||
port = self._get_service_port()
|
||||
port = self._add_fixed_ips_to_service_port(port)
|
||||
interface_name = self.vif_driver.get_device_name(port)
|
||||
self.vif_driver.plug(port['id'], interface_name, port['mac_address'])
|
||||
ip_cidrs = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
subnet = self.neutron_api.get_subnet(fixed_ip['subnet_id'])
|
||||
net = netaddr.IPNetwork(subnet['cidr'])
|
||||
ip_cidr = '%s/%s' % (fixed_ip['ip_address'], net.prefixlen)
|
||||
ip_cidrs.append(ip_cidr)
|
||||
|
||||
self.vif_driver.init_l3(interface_name, ip_cidrs)
|
||||
|
||||
# ensure that interface is first in the list
|
||||
device = ip_lib.IPDevice(interface_name)
|
||||
device.route.pullup_route(interface_name)
|
||||
|
||||
# here we are checking for garbage devices from removed service port
|
||||
self._remove_outdated_interfaces(device)
|
||||
|
||||
def _remove_outdated_interfaces(self, device):
|
||||
"""Finds and removes unused network device."""
|
||||
list_dev = []
|
||||
for dev in ip_lib.IPWrapper().get_devices():
|
||||
if dev.name != device.name and dev.name[:3] == device.name[:3]:
|
||||
cidr_set = set()
|
||||
for a in dev.addr.list():
|
||||
if a['ip_version'] == 4:
|
||||
cidr_set.add(str(netaddr.IPNetwork(a['cidr']).cidr))
|
||||
list_dev.append((dev.name, cidr_set))
|
||||
device_cidr_set = set(str(netaddr.IPNetwork(a['cidr']).cidr)
|
||||
for a in device.addr.list()
|
||||
if a['ip_version'] == 4)
|
||||
|
||||
for dev_name, cidr_set in list_dev:
|
||||
if device_cidr_set & cidr_set:
|
||||
self.vif_driver.unplug(dev_name)
|
||||
|
||||
def _get_service_port(self):
|
||||
"""Find or creates service neutron port.
|
||||
|
||||
This port will be used for connectivity with service instances.
|
||||
"""
|
||||
ports = [port for port in self.neutron_api.
|
||||
list_ports(device_id='manila-share')]
|
||||
if len(ports) > 1:
|
||||
raise exception.ServiceInstanceException(
|
||||
_('Error. Ambiguous service ports.'))
|
||||
elif not ports:
|
||||
try:
|
||||
stdout, stderr = self._execute('hostname')
|
||||
host = stdout.strip()
|
||||
except exception.ProcessExecutionError as e:
|
||||
msg = _('Unable to get host. %s') % e.stderr
|
||||
raise exception.ManilaException(msg)
|
||||
port = self.neutron_api.create_port(self.service_tenant_id,
|
||||
self.service_network_id,
|
||||
device_id='manila-share',
|
||||
device_owner='manila:share',
|
||||
host_id=host)
|
||||
else:
|
||||
port = ports[0]
|
||||
return port
|
||||
|
||||
def _add_fixed_ips_to_service_port(self, port):
|
||||
network = self.neutron_api.get_network(self.service_network_id)
|
||||
subnets = set(network['subnets'])
|
||||
port_fixed_ips = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
port_fixed_ips.append({'subnet_id': fixed_ip['subnet_id'],
|
||||
'ip_address': fixed_ip['ip_address']})
|
||||
if fixed_ip['subnet_id'] in subnets:
|
||||
subnets.remove(fixed_ip['subnet_id'])
|
||||
|
||||
# If there are subnets here that means that
|
||||
# we need to add those to the port and call update.
|
||||
if subnets:
|
||||
port_fixed_ips.extend([dict(subnet_id=s) for s in subnets])
|
||||
port = self.neutron_api.update_port_fixed_ips(
|
||||
port['id'], {'fixed_ips': port_fixed_ips})
|
||||
|
||||
return port
|
||||
|
||||
def _remove_fixed_ip_from_service_port(self, port, subnet_id):
|
||||
port_fixed_ips = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
if fixed_ip['subnet_id'] == subnet_id:
|
||||
continue
|
||||
port_fixed_ips.append({'subnet_id': fixed_ip['subnet_id'],
|
||||
'ip_address': fixed_ip['ip_address']})
|
||||
|
||||
if port_fixed_ips != port['fixed_ips']:
|
||||
port = self.neutron_api.update_port_fixed_ips(
|
||||
port['id'], {'fixed_ips': port_fixed_ips})
|
||||
|
||||
return port
|
||||
|
||||
def _get_cidr_for_subnet(self):
|
||||
"""Returns not used cidr for service subnet creating."""
|
||||
subnets = self._get_all_service_subnets()
|
||||
used_cidrs = set(subnet['cidr'] for subnet in subnets)
|
||||
serv_cidr = netaddr.IPNetwork(CONF.service_network_cidr)
|
||||
for subnet in serv_cidr.subnet(29):
|
||||
cidr = str(subnet.cidr)
|
||||
if cidr not in used_cidrs:
|
||||
return cidr
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('No available cidrs.'))
|
||||
|
||||
def delete_share_infrastructure(self, context, share_network_id):
|
||||
"""Removes share infrastructure.
|
||||
|
||||
Deletes service vm and subnet, associated to share network.
|
||||
"""
|
||||
server = self.get_service_instance(context,
|
||||
share_network_id=share_network_id,
|
||||
create=False)
|
||||
if server:
|
||||
self._delete_server(context, server)
|
||||
subnet_id = self._get_service_subnet(share_network_id)
|
||||
if subnet_id:
|
||||
router = self._get_private_router(share_network_id)
|
||||
port = self._get_service_port()
|
||||
self.neutron_api.router_remove_interface(router['id'], subnet_id)
|
||||
self._remove_fixed_ip_from_service_port(port, subnet_id)
|
||||
self.neutron_api.delete_subnet(subnet_id)
|
||||
self._setup_connectivity_with_service_instances()
|
||||
|
||||
def _get_all_service_subnets(self):
|
||||
service_network = self.neutron_api.get_network(self.service_network_id)
|
||||
return [self.neutron_api.get_subnet(subnet_id)
|
||||
for subnet_id in service_network['subnets']]
|
||||
|
||||
def _get_service_subnet(self, share_network_id):
|
||||
all_service_subnets = self._get_all_service_subnets()
|
||||
service_subnets = [subnet for subnet in all_service_subnets
|
||||
if subnet['name'] == share_network_id]
|
||||
if len(service_subnets) == 1:
|
||||
return service_subnets[0]
|
||||
elif not service_subnets:
|
||||
return None
|
||||
else:
|
||||
raise exception.ServiceInstanceException(_('Ambiguous service '
|
||||
'subnets.'))
|
|
@ -34,5 +34,6 @@ def set_defaults(conf):
|
|||
conf.set_default('sqlite_synchronous', False)
|
||||
conf.set_default('policy_file', 'manila/tests/policy.json')
|
||||
conf.set_default('share_export_ip', '0.0.0.0')
|
||||
conf.set_default('service_instance_user', 'fake_user')
|
||||
conf.set_default('share_driver',
|
||||
'manila.tests.fake_driver.FakeShareDriver')
|
||||
|
|
|
@ -0,0 +1,657 @@
|
|||
# Copyright (c) 2014 NetApp, 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.
|
||||
|
||||
"""Unit tests for the instance module."""
|
||||
|
||||
import copy
|
||||
import mock
|
||||
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.share.drivers import service_instance
|
||||
from manila import test
|
||||
from manila.tests.db import fakes as db_fakes
|
||||
from manila.tests import fake_compute
|
||||
from manila.tests import fake_network
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def fake_share(**kwargs):
|
||||
share = {
|
||||
'id': 'fakeid',
|
||||
'name': 'fakename',
|
||||
'size': 1,
|
||||
'share_proto': 'NFS',
|
||||
'share_network_id': 'fake share network id',
|
||||
'export_location': '127.0.0.1:/mnt/nfs/volume-00002',
|
||||
}
|
||||
share.update(kwargs)
|
||||
return db_fakes.FakeModel(share)
|
||||
|
||||
|
||||
class ServiceInstanceManagerTestCase(test.TestCase):
|
||||
"""Tests InstanceManager."""
|
||||
|
||||
def setUp(self):
|
||||
super(ServiceInstanceManagerTestCase, self).setUp()
|
||||
self._context = context.get_admin_context()
|
||||
|
||||
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)
|
||||
with mock.patch.object(service_instance.ServiceInstanceManager,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock()):
|
||||
self._manager = service_instance.ServiceInstanceManager(self._db,
|
||||
{})
|
||||
self._manager.service_tenant_id = 'service tenant id'
|
||||
self._manager.service_network_id = 'service network id'
|
||||
self._manager.admin_context = self._context
|
||||
self._manager._execute = mock.Mock(return_value=('', ''))
|
||||
self._manager.vif_driver = mock.Mock()
|
||||
self.stubs.Set(service_instance, '_ssh_exec', mock.Mock())
|
||||
self.stubs.Set(service_instance, 'synchronized', mock.Mock(side_effect=
|
||||
lambda f: f))
|
||||
self.stubs.Set(service_instance.os.path, 'exists',
|
||||
mock.Mock(return_value=True))
|
||||
self._manager._helpers = {
|
||||
'CIFS': self._helper_cifs,
|
||||
'NFS': self._helper_nfs,
|
||||
}
|
||||
self.share = fake_share()
|
||||
|
||||
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['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'])
|
||||
|
||||
def test_get_service_network_net_does_not_exists(self):
|
||||
net = fake_network.FakeNetwork()
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[]))
|
||||
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'])
|
||||
|
||||
def test_get_service_network_ambiguos(self):
|
||||
net = fake_network.FakeNetwork(name=CONF.service_network_name)
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[net, net]))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._get_service_network)
|
||||
|
||||
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')
|
||||
|
||||
def test_get_server_ip(self):
|
||||
fake_server = fake_compute.FakeServer(networks=
|
||||
{CONF.service_network_name: '10.254.0.1'})
|
||||
|
||||
result = self._manager._get_server_ip(fake_server)
|
||||
|
||||
self.assertEqual(result,
|
||||
fake_server['networks'][CONF.service_network_name][0])
|
||||
|
||||
def test_get_server_ip_exception(self):
|
||||
fake_server = fake_compute.FakeServer(networks={})
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._get_server_ip, fake_server)
|
||||
|
||||
def test_get_service_instance(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._manager, '_ensure_server',
|
||||
mock.Mock(return_value=False))
|
||||
self.stubs.Set(self._manager, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._manager, '_create_service_instance',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._manager, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
|
||||
result = self._manager.get_service_instance(self._context,
|
||||
share_network_id='fake_share_network_id')
|
||||
|
||||
self._manager._ensure_server.assert_called_once()
|
||||
self._manager._get_ssh_pool.assert_called_once_with(fake_server)
|
||||
self._manager.compute_api.server_list.assert_called_once()
|
||||
self._manager._get_server_ip.assert_called_once()
|
||||
self._manager._create_service_instance.assert_called_once()
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_get_service_instance_existed_in_memory(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self._manager.share_networks_servers = {'fake_share_network_id':
|
||||
fake_server}
|
||||
self.stubs.Set(self._manager, '_ensure_server',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[fake_server]))
|
||||
self.stubs.Set(self._manager, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
self.stubs.Set(self._manager, '_create_service_instance', mock.Mock())
|
||||
|
||||
result = self._manager.get_service_instance(self._context,
|
||||
share_network_id='fake_share_network_id')
|
||||
|
||||
self._manager._ensure_server.assert_called_once()
|
||||
self.assertFalse(self._manager._get_ssh_pool.called)
|
||||
self.assertFalse(self._manager.compute_api.server_list.called)
|
||||
self.assertFalse(self._manager._create_service_instance.called)
|
||||
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_get_service_instance_existed_in_memory_non_active(self):
|
||||
old_fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
new_fake_server = fake_compute.FakeServer()
|
||||
self._manager.share_networks_servers = {'fake_share_network_id':
|
||||
old_fake_server}
|
||||
self.stubs.Set(self._manager, '_ensure_server',
|
||||
mock.Mock(return_value=False))
|
||||
self.stubs.Set(self._manager, '_delete_server', mock.Mock())
|
||||
self.stubs.Set(self._manager, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._manager, '_create_service_instance',
|
||||
mock.Mock(return_value=new_fake_server))
|
||||
self.stubs.Set(self._manager, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
|
||||
result = self._manager.get_service_instance(self._context,
|
||||
share_network_id='fake_share_network_id')
|
||||
|
||||
self._manager._ensure_server.assert_has_calls(
|
||||
[mock.call(self._context, old_fake_server, update=True)])
|
||||
self._manager._get_ssh_pool.assert_called_once_with(new_fake_server)
|
||||
self._manager.compute_api.server_list.assert_called_once()
|
||||
self._manager._get_server_ip.assert_called_once()
|
||||
self._manager._create_service_instance.assert_called_once()
|
||||
|
||||
self.assertEqual(result, new_fake_server)
|
||||
|
||||
def test_get_service_instance_existed(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._manager, '_ensure_server',
|
||||
mock.Mock(side_effect=[False, True]))
|
||||
self.stubs.Set(self._manager, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[fake_server]))
|
||||
self.stubs.Set(self._manager, '_create_service_instance',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._manager, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
|
||||
result = self._manager.get_service_instance(self._context,
|
||||
share_network_id='fake_share_network_id')
|
||||
|
||||
self._manager._ensure_server.assert_called_once()
|
||||
self._manager._get_ssh_pool.assert_called_once_with(fake_server)
|
||||
self._manager.compute_api.server_list.assert_called_once()
|
||||
self._manager._get_server_ip.assert_called_once()
|
||||
self.assertFalse(self._manager._create_service_instance.called)
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_ensure_server(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._manager, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_get',
|
||||
mock.Mock(return_value=fake_server))
|
||||
result = self._manager._ensure_server(self._context,
|
||||
fake_server,
|
||||
update=True)
|
||||
self._manager.compute_api.server_get.\
|
||||
assert_called_once_with(self._context, fake_server['id'])
|
||||
self._manager._check_server_availability.\
|
||||
assert_called_once_with(fake_server)
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_ensure_server_not_exists(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._manager, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_get',
|
||||
mock.Mock(side_effect=exception.InstanceNotFound(
|
||||
instance_id=fake_server['id'])))
|
||||
result = self._manager._ensure_server(self._context,
|
||||
fake_server,
|
||||
update=True)
|
||||
self._manager.compute_api.server_get.\
|
||||
assert_called_once_with(self._context, fake_server['id'])
|
||||
self.assertFalse(self._manager._check_server_availability.called)
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_ensure_server_exception(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._manager, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_get',
|
||||
mock.Mock(side_effect=exception.ManilaException))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._ensure_server,
|
||||
self._context,
|
||||
fake_server,
|
||||
update=True)
|
||||
self._manager.compute_api.server_get.\
|
||||
assert_called_once_with(self._context, fake_server['id'])
|
||||
self.assertFalse(self._manager._check_server_availability.called)
|
||||
|
||||
def test_ensure_server_non_active(self):
|
||||
fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
self.stubs.Set(self._manager, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
result = self._manager._ensure_server(self._context, fake_server)
|
||||
self.assertFalse(self._manager._check_server_availability.called)
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_get_key_create_new(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(name=
|
||||
CONF.manila_service_keypair_name)
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_import',
|
||||
mock.Mock(return_value=fake_keypair))
|
||||
|
||||
result = self._manager._get_key(self._context)
|
||||
|
||||
self.assertEqual(result, fake_keypair.name)
|
||||
self._manager.compute_api.keypair_list.assert_called_once()
|
||||
self._manager.compute_api.keypair_import.assert_called_once()
|
||||
|
||||
def test_get_key_exists(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name,
|
||||
public_key='fake_public_key')
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[fake_keypair]))
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_import',
|
||||
mock.Mock(return_value=fake_keypair))
|
||||
self.stubs.Set(self._manager, '_execute',
|
||||
mock.Mock(return_value=('fake_public_key', '')))
|
||||
|
||||
result = self._manager._get_key(self._context)
|
||||
|
||||
self._manager.compute_api.keypair_list.assert_called_once()
|
||||
self.assertFalse(self._manager.compute_api.keypair_import.called)
|
||||
self.assertEqual(result, fake_keypair.name)
|
||||
|
||||
def test_get_key_exists_recreate(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name,
|
||||
public_key='fake_public_key1')
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[fake_keypair]))
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_import',
|
||||
mock.Mock(return_value=fake_keypair))
|
||||
self.stubs.Set(self._manager.compute_api, 'keypair_delete',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._manager, '_execute',
|
||||
mock.Mock(return_value=('fake_public_key2', '')))
|
||||
|
||||
result = self._manager._get_key(self._context)
|
||||
|
||||
self._manager.compute_api.keypair_list.assert_called_once()
|
||||
self._manager.compute_api.keypair_delete.assert_called_once()
|
||||
self._manager.compute_api.keypair_import.\
|
||||
assert_called_once_with(self._context, fake_keypair.name,
|
||||
'fake_public_key2')
|
||||
self.assertEqual(result, fake_keypair.name)
|
||||
|
||||
def test_get_service_image(self):
|
||||
fake_image1 = fake_compute.FakeImage(name=CONF.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)
|
||||
|
||||
def test_get_service_image_not_found(self):
|
||||
self.stubs.Set(self._manager.compute_api, 'image_list',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._get_service_image,
|
||||
self._context)
|
||||
|
||||
def test_get_service_image_ambiguous(self):
|
||||
fake_image = fake_compute.FakeImage(name=CONF.service_image_name)
|
||||
self.stubs.Set(self._manager.compute_api, 'image_list',
|
||||
mock.Mock(return_value=[fake_image, fake_image]))
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._get_service_image,
|
||||
self._context)
|
||||
|
||||
def test_create_service_instance(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._manager, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._manager, '_get_key',
|
||||
mock.Mock(return_value='fake_key_name'))
|
||||
self.stubs.Set(self._manager, '_setup_network_for_instance',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._manager,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._manager.compute_api, 'server_create',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._manager, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(service_instance.socket, 'socket', mock.Mock())
|
||||
|
||||
result = self._manager._create_service_instance(self._context,
|
||||
'instance_name', self.share, None)
|
||||
|
||||
self._manager._get_service_image.assert_called_once()
|
||||
self._manager._get_key.assert_called_once()
|
||||
self._manager._setup_network_for_instance.assert_called_once()
|
||||
self._manager._setup_connectivity_with_service_instances.\
|
||||
assert_called_once()
|
||||
self._manager.compute_api.server_create.assert_called_once_with(
|
||||
self._context, 'instance_name', 'fake_image_id',
|
||||
CONF.service_instance_flavor_id, 'fake_key_name', None, None,
|
||||
nics=[{'port-id': fake_port['id']}])
|
||||
service_instance.socket.socket.assert_called_once()
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_create_service_instance_error(self):
|
||||
fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._manager, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._manager, '_get_key',
|
||||
mock.Mock(return_value='fake_key_name'))
|
||||
self.stubs.Set(self._manager, '_setup_network_for_instance',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._manager,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._manager.compute_api, 'server_create',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_get',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(service_instance.socket, 'socket', mock.Mock())
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._create_service_instance, self._context,
|
||||
'instance_name', self.share, None)
|
||||
|
||||
self._manager.compute_api.server_create.assert_called_once()
|
||||
self.assertFalse(self._manager.compute_api.server_get.called)
|
||||
self.assertFalse(service_instance.socket.socket.called)
|
||||
|
||||
def test_create_service_instance_failed_setup_connectivity(self):
|
||||
fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._manager, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._manager, '_get_key',
|
||||
mock.Mock(return_value='fake_key_name'))
|
||||
self.stubs.Set(self._manager, '_setup_network_for_instance',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._manager,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock(side_effect=exception.ManilaException))
|
||||
self.stubs.Set(self._manager.neutron_api, 'delete_port', mock.Mock())
|
||||
self.stubs.Set(self._manager.compute_api, 'server_create',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._manager.compute_api, 'server_get',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(service_instance.socket, 'socket', mock.Mock())
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._create_service_instance,
|
||||
self._context, 'instance_name', self.share, None)
|
||||
|
||||
self._manager.neutron_api.delete_port.\
|
||||
assert_called_once_with(fake_port['id'])
|
||||
self.assertFalse(self._manager.compute_api.server_create.called)
|
||||
self.assertFalse(self._manager.compute_api.server_get.called)
|
||||
self.assertFalse(service_instance.socket.socket.called)
|
||||
|
||||
def test_create_service_instance_no_key_and_password(self):
|
||||
self.stubs.Set(self._manager, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._manager, '_get_key',
|
||||
mock.Mock(return_value=None))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._create_service_instance, self._context,
|
||||
'instance_name', self.share, None)
|
||||
|
||||
def test_setup_network_for_instance(self):
|
||||
fake_service_net = fake_network.FakeNetwork(subnets=[])
|
||||
fake_service_subnet = fake_network.\
|
||||
FakeSubnet(name=self.share['share_network_id'])
|
||||
fake_router = fake_network.FakeRouter()
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_network',
|
||||
mock.Mock(return_value=fake_service_net))
|
||||
self.stubs.Set(self._manager.neutron_api, 'subnet_create',
|
||||
mock.Mock(return_value=fake_service_subnet))
|
||||
self.stubs.Set(self._manager.db, 'share_network_get',
|
||||
mock.Mock(return_value='fake_share_network'))
|
||||
self.stubs.Set(self._manager, '_get_private_router',
|
||||
mock.Mock(return_value=fake_router))
|
||||
self.stubs.Set(self._manager.neutron_api, 'router_add_interface',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._manager.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._manager, '_get_cidr_for_subnet',
|
||||
mock.Mock(return_value='fake_cidr'))
|
||||
|
||||
result = self._manager._setup_network_for_instance(self._context,
|
||||
'fake_share_network', None)
|
||||
|
||||
self._manager.neutron_api.get_network.\
|
||||
assert_called_once_with(self._manager.service_network_id)
|
||||
self._manager._get_private_router.\
|
||||
assert_called_once_with('fake_share_network')
|
||||
self._manager.neutron_api.router_add_interface.\
|
||||
assert_called_once_with('fake_router_id', 'fake_subnet_id')
|
||||
self._manager.neutron_api.subnet_create.assert_called_once_with(
|
||||
self._manager.service_tenant_id,
|
||||
self._manager.service_network_id,
|
||||
'fake_share_network',
|
||||
'fake_cidr')
|
||||
self._manager.neutron_api.create_port.assert_called_once_with(
|
||||
self._manager.service_tenant_id,
|
||||
self._manager.service_network_id,
|
||||
subnet_id='fake_subnet_id',
|
||||
fixed_ip=None,
|
||||
device_owner='manila')
|
||||
self._manager._get_cidr_for_subnet.assert_called_once()
|
||||
self.assertEqual(result, fake_port)
|
||||
|
||||
def test_get_private_router(self):
|
||||
fake_net = fake_network.FakeNetwork()
|
||||
fake_subnet = fake_network.FakeSubnet(gateway_ip='fake_ip')
|
||||
fake_share_network = {'neutron_net_id': fake_net['id'],
|
||||
'neutron_subnet_id': fake_subnet['id']}
|
||||
self.stubs.Set(self._manager.db, 'share_network_get',
|
||||
mock.Mock(return_value=fake_share_network))
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet['id'],
|
||||
'ip_address': fake_subnet['gateway_ip']}],
|
||||
device_id='fake_router_id')
|
||||
fake_router = fake_network.FakeRouter(id='fake_router_id')
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
self.stubs.Set(self._manager.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[fake_port]))
|
||||
self.stubs.Set(self._manager.neutron_api, 'show_router',
|
||||
mock.Mock(return_value=fake_router))
|
||||
|
||||
result = self._manager._get_private_router(
|
||||
{'neutron_subnet_id': fake_subnet['id'],
|
||||
'neutron_net_id': fake_net['id']})
|
||||
|
||||
self._manager.neutron_api.get_subnet.\
|
||||
assert_called_once_with(fake_subnet['id'])
|
||||
self._manager.neutron_api.list_ports.\
|
||||
assert_called_once_with(network_id=fake_net['id'])
|
||||
self._manager.neutron_api.show_router.\
|
||||
assert_called_once_with(fake_router['id'])
|
||||
self.assertEqual(result, fake_router)
|
||||
|
||||
def test_get_private_router_exception(self):
|
||||
fake_net = fake_network.FakeNetwork()
|
||||
fake_subnet = fake_network.FakeSubnet(gateway_ip='fake_ip')
|
||||
fake_share_network = {'neutron_net_id': fake_net['id'],
|
||||
'neutron_subnet_id': fake_subnet['id']}
|
||||
self.stubs.Set(self._manager.db, 'share_network_get',
|
||||
mock.Mock(return_value=fake_share_network))
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
self.stubs.Set(self._manager.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._get_private_router,
|
||||
{'neutron_subnet_id': fake_subnet['id'],
|
||||
'neutron_net_id': fake_net['id']})
|
||||
|
||||
def test_setup_connectivity_with_service_instances(self):
|
||||
fake_subnet = fake_network.FakeSubnet(cidr='10.254.0.1/29')
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet['id'], 'ip_address': '10.254.0.2'}],
|
||||
mac_address='fake_mac_address')
|
||||
|
||||
self.stubs.Set(self._manager, '_get_service_port',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._manager.vif_driver, 'get_device_name',
|
||||
mock.Mock(return_value='fake_interface_name'))
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
self.stubs.Set(self._manager, '_remove_outdated_interfaces',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._manager.vif_driver, 'plug', mock.Mock())
|
||||
device_mock = mock.Mock()
|
||||
self.stubs.Set(service_instance.ip_lib, 'IPDevice',
|
||||
mock.Mock(return_value=device_mock))
|
||||
|
||||
self._manager._setup_connectivity_with_service_instances()
|
||||
|
||||
self._manager._get_service_port.assert_called_once()
|
||||
self._manager.vif_driver.get_device_name.assert_called_once_with(
|
||||
fake_port)
|
||||
self._manager.vif_driver.plug.assert_called_once_with(fake_port['id'],
|
||||
'fake_interface_name', fake_port['mac_address'])
|
||||
self._manager.neutron_api.get_subnet.assert_called_once_with(
|
||||
fake_subnet['id'])
|
||||
self._manager.vif_driver.init_l3.assert_called_once()
|
||||
service_instance.ip_lib.IPDevice.assert_called_once()
|
||||
device_mock.route.pullup_route.assert_called_once()
|
||||
self._manager._remove_outdated_interfaces.assert_called_once_with(
|
||||
device_mock)
|
||||
|
||||
def test_get_service_port(self):
|
||||
fake_service_port = fake_network.FakePort(device_id='manila-share')
|
||||
fake_service_net = fake_network.FakeNetwork(subnets=[])
|
||||
self.stubs.Set(self._manager.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._manager, '_execute',
|
||||
mock.Mock(return_value=('fake_host', '')))
|
||||
self.stubs.Set(self._manager.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_network',
|
||||
mock.Mock(return_value=fake_service_net))
|
||||
self.stubs.Set(self._manager.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = self._manager._get_service_port()
|
||||
|
||||
self._manager.neutron_api.list_ports.\
|
||||
assert_called_once_with(device_id='manila-share')
|
||||
self._manager.db.service_get_all_by_topic.assert_called_once()
|
||||
self._manager.neutron_api.create_port.assert_called_once_with(
|
||||
self._manager.service_tenant_id,
|
||||
self._manager.service_network_id,
|
||||
device_id='manila-share',
|
||||
device_owner='manila:share',
|
||||
host_id='fake_host'
|
||||
)
|
||||
self._manager.neutron_api.get_network.assert_called_once()
|
||||
self.assertFalse(self._manager.neutron_api.
|
||||
update_port_fixed_ips.called)
|
||||
self.assertEqual(result, fake_service_port)
|
||||
|
||||
def test_get_service_port_ambigious_ports(self):
|
||||
fake_service_port = fake_network.FakePort(device_id='manila-share')
|
||||
self.stubs.Set(self._manager.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[fake_service_port, fake_service_port]))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._manager._get_service_port)
|
||||
|
||||
def test_get_service_port_exists(self):
|
||||
fake_service_port = fake_network.FakePort(device_id='manila-share')
|
||||
fake_service_net = fake_network.FakeNetwork(subnets=[])
|
||||
self.stubs.Set(self._manager.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[fake_service_port]))
|
||||
self.stubs.Set(self._manager.db, 'service_get_all_by_topic',
|
||||
mock.Mock(return_value=[{'host': 'fake_host'}]))
|
||||
self.stubs.Set(self._manager.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
self.stubs.Set(self._manager.neutron_api, 'get_network',
|
||||
mock.Mock(return_value=fake_service_net))
|
||||
self.stubs.Set(self._manager.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = self._manager._get_service_port()
|
||||
|
||||
self._manager.neutron_api.list_ports.assert_called_once_with(
|
||||
device_id='manila-share')
|
||||
self.assertFalse(self._manager.db.service_get_all_by_topic.called)
|
||||
self.assertFalse(self._manager.neutron_api.create_port.called)
|
||||
self._manager.neutron_api.get_network.assert_called_once()
|
||||
self.assertFalse(self._manager.neutron_api.
|
||||
update_port_fixed_ips.called)
|
||||
self.assertEqual(result, fake_service_port)
|
||||
|
||||
def test_get_cidr_for_subnet(self):
|
||||
serv_cidr = service_instance.netaddr.IPNetwork(
|
||||
CONF.service_network_cidr)
|
||||
cidrs = serv_cidr.subnet(29)
|
||||
cidr1 = str(cidrs.next())
|
||||
cidr2 = str(cidrs.next())
|
||||
self.stubs.Set(self._manager, '_get_all_service_subnets',
|
||||
mock.Mock(return_value=[]))
|
||||
result = self._manager._get_cidr_for_subnet()
|
||||
self.assertEqual(result, cidr1)
|
||||
|
||||
fake_subnet = fake_network.FakeSubnet(cidr=cidr1)
|
||||
self.stubs.Set(self._manager, '_get_all_service_subnets',
|
||||
mock.Mock(return_value=[fake_subnet]))
|
||||
result = self._manager._get_cidr_for_subnet()
|
||||
self.assertEqual(result, cidr2)
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2014 Mirantis Inc.
|
||||
# Copyright (c) 2014 NetApp, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -12,29 +12,26 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Unit tests for the Generic driver module."""
|
||||
|
||||
import copy
|
||||
import mock
|
||||
import os
|
||||
|
||||
from manila import context
|
||||
from oslo.config import cfg
|
||||
|
||||
from manila import compute
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.network.neutron import api as neutron
|
||||
from manila import volume
|
||||
|
||||
from manila.share.configuration import Configuration
|
||||
from manila.share.drivers import generic
|
||||
from manila import test
|
||||
from manila.tests.db import fakes as db_fakes
|
||||
from manila.tests import fake_compute
|
||||
from manila.tests import fake_network
|
||||
from manila.tests import fake_utils
|
||||
from manila.tests import fake_volume
|
||||
from manila import volume
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
@ -94,13 +91,13 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
configuration=self.fake_conf)
|
||||
self._driver.service_tenant_id = 'service tenant id'
|
||||
self._driver.service_network_id = 'service network id'
|
||||
self._driver.neutron_api = fake_network.API()
|
||||
self._driver.compute_api = fake_compute.API()
|
||||
self._driver.volume_api = fake_volume.API()
|
||||
self._driver.share_networks_locks = {}
|
||||
self._driver.get_service_instance = mock.Mock()
|
||||
self._driver.share_networks_servers = {}
|
||||
self._driver.admin_context = self._context
|
||||
self._driver.vif_driver = mock.Mock()
|
||||
self._driver.instance_manager = mock.Mock()
|
||||
self.stubs.Set(generic, '_ssh_exec', mock.Mock())
|
||||
self.stubs.Set(generic, 'synchronized', mock.Mock(side_effect=
|
||||
lambda f: f))
|
||||
|
@ -114,62 +111,17 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
self.snapshot = fake_snapshot()
|
||||
|
||||
def test_do_setup(self):
|
||||
self.stubs.Set(neutron, 'API', mock.Mock())
|
||||
self.stubs.Set(volume, 'API', mock.Mock())
|
||||
self.stubs.Set(compute, 'API', mock.Mock())
|
||||
self.stubs.Set(self._driver,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._driver,
|
||||
'_get_service_network',
|
||||
mock.Mock(return_value='fake network id'))
|
||||
self.stubs.Set(generic, 'service_instance', mock.Mock())
|
||||
self.stubs.Set(self._driver, '_setup_helpers', mock.Mock())
|
||||
self._driver.do_setup(self._context)
|
||||
neutron.API.assert_called_once()
|
||||
volume.API.assert_called_once()
|
||||
compute.API.assert_called_once()
|
||||
self._driver._setup_helpers.assert_called_once()
|
||||
self._driver._setup_connectivity_with_service_instances.\
|
||||
assert_called_once()
|
||||
self.assertEqual(self._driver.service_network_id, 'fake network id')
|
||||
|
||||
def test_do_setup_exception(self):
|
||||
self.stubs.Set(neutron, 'API', mock.Mock())
|
||||
neutron.API.return_value = fake_network.API()
|
||||
self.stubs.Set(volume, 'API', mock.Mock())
|
||||
self.stubs.Set(compute, 'API', mock.Mock())
|
||||
self.stubs.Set(neutron.API, 'admin_tenant_id', mock.Mock())
|
||||
neutron.API.admin_tenant_id.side_effect = Exception
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver.do_setup, self._context)
|
||||
|
||||
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['id'] = 'fake service network id'
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[net1, net2]))
|
||||
result = self._driver._get_service_network()
|
||||
self.assertEqual(result, net1['id'])
|
||||
|
||||
def test_get_service_network_net_does_not_exists(self):
|
||||
net = fake_network.FakeNetwork()
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._driver.neutron_api, 'network_create',
|
||||
mock.Mock(return_value=net))
|
||||
result = self._driver._get_service_network()
|
||||
self.assertEqual(result, net['id'])
|
||||
|
||||
def test_get_service_network_ambiguos(self):
|
||||
net = fake_network.FakeNetwork(name=CONF.service_network_name)
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_all_tenant_networks',
|
||||
mock.Mock(return_value=[net, net]))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._get_service_network)
|
||||
|
||||
def test_setup_helpers(self):
|
||||
self._driver._helpers = {}
|
||||
CONF.set_default('share_helpers', ['NFS=fakenfs'])
|
||||
self.stubs.Set(generic.importutils, 'import_class',
|
||||
mock.Mock(return_value=self._helper_nfs))
|
||||
|
@ -184,7 +136,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
|
||||
def test_create_share(self):
|
||||
self._helper_nfs.create_export.return_value = 'fakelocation'
|
||||
methods = ('_get_service_instance', '_allocate_container',
|
||||
methods = ('get_service_instance', '_allocate_container',
|
||||
'_attach_volume', '_format_device', '_mount_device')
|
||||
for method in methods:
|
||||
self.stubs.Set(self._driver, method, mock.Mock())
|
||||
|
@ -444,541 +396,6 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
|
||||
self.assertEqual(result, '/dev/vdc')
|
||||
|
||||
def test_get_service_instance_name(self):
|
||||
result = self._driver._get_service_instance_name(self.share)
|
||||
self.assertEqual(result, CONF.service_instance_name_template %
|
||||
self.share['share_network_id'])
|
||||
|
||||
def test_get_server_ip(self):
|
||||
fake_server = fake_compute.FakeServer(networks=
|
||||
{CONF.service_network_name: '10.254.0.1'})
|
||||
|
||||
result = self._driver._get_server_ip(fake_server)
|
||||
|
||||
self.assertEqual(result,
|
||||
fake_server['networks'][CONF.service_network_name][0])
|
||||
|
||||
def test_get_server_ip_exception(self):
|
||||
fake_server = fake_compute.FakeServer(networks={})
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._get_server_ip, fake_server)
|
||||
|
||||
def test_get_service_instance(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._driver, '_ensure_or_delete_server',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._driver, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._driver, '_create_service_instance',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._driver, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
|
||||
result = self._driver._get_service_instance(self._context, self.share)
|
||||
|
||||
self.assertFalse(self._driver._ensure_or_delete_server.called)
|
||||
self._driver._get_ssh_pool.assert_called_once_with(fake_server)
|
||||
self._driver.compute_api.server_list.assert_called_once()
|
||||
self._driver._get_server_ip.assert_called_once()
|
||||
self._driver._create_service_instance.assert_called_once()
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_get_service_instance_existed_in_memory(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self._driver.share_networks_servers = {self.share['share_network_id']:
|
||||
fake_server}
|
||||
self.stubs.Set(self._driver, '_ensure_or_delete_server',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[fake_server]))
|
||||
self.stubs.Set(self._driver, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
self.stubs.Set(self._driver, '_create_service_instance',
|
||||
mock.Mock(return_value=fake_server))
|
||||
|
||||
result = self._driver._get_service_instance(self._context, self.share)
|
||||
|
||||
self._driver._ensure_or_delete_server.assert_called_once()
|
||||
self.assertFalse(self._driver._get_ssh_pool.called)
|
||||
self.assertFalse(self._driver.compute_api.server_list.called)
|
||||
self.assertFalse(self._driver._create_service_instance.called)
|
||||
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_get_service_instance_existed_in_memory_non_active(self):
|
||||
old_fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
new_fake_server = fake_compute.FakeServer()
|
||||
self._driver.share_networks_servers = {self.share['share_network_id']:
|
||||
old_fake_server}
|
||||
self.stubs.Set(self._driver, '_ensure_or_delete_server',
|
||||
mock.Mock(return_value=False))
|
||||
self.stubs.Set(self._driver, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._driver, '_create_service_instance',
|
||||
mock.Mock(return_value=new_fake_server))
|
||||
self.stubs.Set(self._driver, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
|
||||
result = self._driver._get_service_instance(self._context, self.share)
|
||||
|
||||
self._driver._ensure_or_delete_server.assert_has_calls(
|
||||
[mock.call(self._context, old_fake_server, update=True)])
|
||||
self._driver._get_ssh_pool.assert_called_once_with(new_fake_server)
|
||||
self._driver.compute_api.server_list.assert_called_once()
|
||||
self._driver._get_server_ip.assert_called_once()
|
||||
self._driver._create_service_instance.assert_called_once()
|
||||
|
||||
self.assertEqual(result, new_fake_server)
|
||||
|
||||
def test_get_service_instance_existed(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._driver, '_ensure_or_delete_server',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._driver, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_list',
|
||||
mock.Mock(return_value=[fake_server]))
|
||||
self.stubs.Set(self._driver, '_create_service_instance',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._driver, '_get_ssh_pool',
|
||||
mock.Mock(return_value=mock.Mock()))
|
||||
|
||||
result = self._driver._get_service_instance(self._context, self.share)
|
||||
|
||||
self._driver._ensure_or_delete_server.assert_called_once()
|
||||
self._driver._get_ssh_pool.assert_called_once_with(fake_server)
|
||||
self._driver.compute_api.server_list.assert_called_once()
|
||||
self._driver._get_server_ip.assert_called_once()
|
||||
self.assertFalse(self._driver._create_service_instance.called)
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_ensure_or_delete_server(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._driver, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_get',
|
||||
mock.Mock(return_value=fake_server))
|
||||
result = self._driver._ensure_or_delete_server(self._context,
|
||||
fake_server,
|
||||
update=True)
|
||||
self._driver.compute_api.server_get.\
|
||||
assert_called_once_with(self._context, fake_server['id'])
|
||||
self._driver._check_server_availability.\
|
||||
assert_called_once_with(fake_server)
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_ensure_or_delete_server_not_exists(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._driver, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_get',
|
||||
mock.Mock(side_effect=exception.InstanceNotFound(
|
||||
instance_id=fake_server['id'])))
|
||||
result = self._driver._ensure_or_delete_server(self._context,
|
||||
fake_server,
|
||||
update=True)
|
||||
self._driver.compute_api.server_get.\
|
||||
assert_called_once_with(self._context, fake_server['id'])
|
||||
self.assertFalse(self._driver._check_server_availability.called)
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_ensure_or_delete_server_exception(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._driver, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_get',
|
||||
mock.Mock(side_effect=exception.ManilaException))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._ensure_or_delete_server,
|
||||
self._context,
|
||||
fake_server,
|
||||
update=True)
|
||||
self._driver.compute_api.server_get.\
|
||||
assert_called_once_with(self._context, fake_server['id'])
|
||||
self.assertFalse(self._driver._check_server_availability.called)
|
||||
|
||||
def test_ensure_or_delete_server_non_active(self):
|
||||
fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
self.stubs.Set(self._driver, '_delete_server', mock.Mock())
|
||||
self.stubs.Set(self._driver, '_check_server_availability',
|
||||
mock.Mock(return_value=True))
|
||||
result = self._driver._ensure_or_delete_server(self._context,
|
||||
fake_server)
|
||||
self.assertFalse(self._driver._check_server_availability.called)
|
||||
self._driver._delete_server.assert_called_once_with(self._context,
|
||||
fake_server)
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_get_key_create_new(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(name=
|
||||
CONF.manila_service_keypair_name)
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_import',
|
||||
mock.Mock(return_value=fake_keypair))
|
||||
|
||||
result = self._driver._get_key(self._context)
|
||||
|
||||
self.assertEqual(result, fake_keypair.name)
|
||||
self._driver.compute_api.keypair_list.assert_called_once()
|
||||
self._driver.compute_api.keypair_import.assert_called_once()
|
||||
|
||||
def test_get_key_exists(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name,
|
||||
public_key='fake_public_key')
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[fake_keypair]))
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_import',
|
||||
mock.Mock(return_value=fake_keypair))
|
||||
self.stubs.Set(self._driver, '_execute',
|
||||
mock.Mock(return_value=('fake_public_key', '')))
|
||||
|
||||
result = self._driver._get_key(self._context)
|
||||
|
||||
self._driver.compute_api.keypair_list.assert_called_once()
|
||||
self.assertFalse(self._driver.compute_api.keypair_import.called)
|
||||
self.assertEqual(result, fake_keypair.name)
|
||||
|
||||
def test_get_key_exists_recreate(self):
|
||||
fake_keypair = fake_compute.FakeKeypair(
|
||||
name=CONF.manila_service_keypair_name,
|
||||
public_key='fake_public_key1')
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_list',
|
||||
mock.Mock(return_value=[fake_keypair]))
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_import',
|
||||
mock.Mock(return_value=fake_keypair))
|
||||
self.stubs.Set(self._driver.compute_api, 'keypair_delete', mock.Mock())
|
||||
self.stubs.Set(self._driver, '_execute',
|
||||
mock.Mock(return_value=('fake_public_key2', '')))
|
||||
|
||||
result = self._driver._get_key(self._context)
|
||||
|
||||
self._driver.compute_api.keypair_list.assert_called_once()
|
||||
self._driver.compute_api.keypair_delete.assert_called_once()
|
||||
self._driver.compute_api.keypair_import.\
|
||||
assert_called_once_with(self._context, fake_keypair.name,
|
||||
'fake_public_key2')
|
||||
self.assertEqual(result, fake_keypair.name)
|
||||
|
||||
def test_get_service_image(self):
|
||||
fake_image1 = fake_compute.FakeImage(name=CONF.service_image_name)
|
||||
fake_image2 = fake_compute.FakeImage(name='another-image')
|
||||
self.stubs.Set(self._driver.compute_api, 'image_list',
|
||||
mock.Mock(return_value=[fake_image1, fake_image2]))
|
||||
|
||||
result = self._driver._get_service_image(self._context)
|
||||
|
||||
self.assertEqual(result, fake_image1.id)
|
||||
|
||||
def test_get_service_image_not_found(self):
|
||||
self.stubs.Set(self._driver.compute_api, 'image_list',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._get_service_image,
|
||||
self._context)
|
||||
|
||||
def test_get_service_image_ambiguous(self):
|
||||
fake_image = fake_compute.FakeImage(name=CONF.service_image_name)
|
||||
self.stubs.Set(self._driver.compute_api, 'image_list',
|
||||
mock.Mock(return_value=[fake_image, fake_image]))
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._get_service_image,
|
||||
self._context)
|
||||
|
||||
def test_create_service_instance(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._driver, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._driver, '_get_key',
|
||||
mock.Mock(return_value='fake_key_name'))
|
||||
self.stubs.Set(self._driver, '_setup_network_for_instance',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._driver,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._driver.compute_api, 'server_create',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._driver, '_get_server_ip',
|
||||
mock.Mock(return_value='fake_ip'))
|
||||
self.stubs.Set(generic.socket, 'socket', mock.Mock())
|
||||
|
||||
result = self._driver._create_service_instance(self._context,
|
||||
'instance_name', self.share, None)
|
||||
|
||||
self._driver._get_service_image.assert_called_once()
|
||||
self._driver._get_key.assert_called_once()
|
||||
self._driver._setup_network_for_instance.assert_called_once()
|
||||
self._driver._setup_connectivity_with_service_instances.\
|
||||
assert_called_once()
|
||||
self._driver.compute_api.server_create.assert_called_once_with(
|
||||
self._context, 'instance_name', 'fake_image_id',
|
||||
CONF.service_instance_flavor_id, 'fake_key_name', None, None,
|
||||
nics=[{'port-id': fake_port['id']}])
|
||||
generic.socket.socket.assert_called_once()
|
||||
self.assertEqual(result, fake_server)
|
||||
|
||||
def test_create_service_instance_error(self):
|
||||
fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._driver, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._driver, '_get_key',
|
||||
mock.Mock(return_value='fake_key_name'))
|
||||
self.stubs.Set(self._driver, '_setup_network_for_instance',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._driver,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._driver.compute_api, 'server_create',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_get',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(generic.socket, 'socket', mock.Mock())
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._create_service_instance, self._context,
|
||||
'instance_name', self.share, None)
|
||||
|
||||
self._driver.compute_api.server_create.assert_called_once()
|
||||
self.assertFalse(self._driver.compute_api.server_get.called)
|
||||
self.assertFalse(generic.socket.socket.called)
|
||||
|
||||
def test_create_service_instance_failed_setup_connectivity(self):
|
||||
fake_server = fake_compute.FakeServer(status='ERROR')
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._driver, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._driver, '_get_key',
|
||||
mock.Mock(return_value='fake_key_name'))
|
||||
self.stubs.Set(self._driver, '_setup_network_for_instance',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._driver,
|
||||
'_setup_connectivity_with_service_instances',
|
||||
mock.Mock(side_effect=exception.ManilaException))
|
||||
self.stubs.Set(self._driver.neutron_api, 'delete_port', mock.Mock())
|
||||
self.stubs.Set(self._driver.compute_api, 'server_create',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._driver.compute_api, 'server_get',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(generic.socket, 'socket', mock.Mock())
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._create_service_instance,
|
||||
self._context, 'instance_name', self.share, None)
|
||||
|
||||
self._driver.neutron_api.delete_port.\
|
||||
assert_called_once_with(fake_port['id'])
|
||||
self.assertFalse(self._driver.compute_api.server_create.called)
|
||||
self.assertFalse(self._driver.compute_api.server_get.called)
|
||||
self.assertFalse(generic.socket.socket.called)
|
||||
|
||||
def test_create_service_instance_no_key_and_password(self):
|
||||
self.stubs.Set(self._driver, '_get_service_image',
|
||||
mock.Mock(return_value='fake_image_id'))
|
||||
self.stubs.Set(self._driver, '_get_key',
|
||||
mock.Mock(return_value=None))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._create_service_instance, self._context,
|
||||
'instance_name', self.share, None)
|
||||
|
||||
def test_setup_network_for_instance(self):
|
||||
fake_service_net = fake_network.FakeNetwork(subnets=[])
|
||||
fake_service_subnet = fake_network.\
|
||||
FakeSubnet(name=self.share['share_network_id'])
|
||||
fake_router = fake_network.FakeRouter()
|
||||
fake_port = fake_network.FakePort()
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_network',
|
||||
mock.Mock(return_value=fake_service_net))
|
||||
self.stubs.Set(self._driver.neutron_api, 'subnet_create',
|
||||
mock.Mock(return_value=fake_service_subnet))
|
||||
self.stubs.Set(self._driver.db, 'share_network_get',
|
||||
mock.Mock(return_value='fake_share_network'))
|
||||
self.stubs.Set(self._driver, '_get_private_router',
|
||||
mock.Mock(return_value=fake_router))
|
||||
self.stubs.Set(self._driver.neutron_api, 'router_add_interface',
|
||||
mock.Mock())
|
||||
self.stubs.Set(self._driver.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._driver, '_get_cidr_for_subnet',
|
||||
mock.Mock(return_value='fake_cidr'))
|
||||
|
||||
result = self._driver._setup_network_for_instance(self._context,
|
||||
self.share, None)
|
||||
|
||||
self._driver.neutron_api.get_network.\
|
||||
assert_called_once_with(self._driver.service_network_id)
|
||||
self._driver._get_private_router.\
|
||||
assert_called_once_with('fake_share_network')
|
||||
self._driver.neutron_api.router_add_interface.\
|
||||
assert_called_once_with('fake_router_id', 'fake_subnet_id')
|
||||
self._driver.neutron_api.subnet_create.assert_called_once_with(
|
||||
self._driver.service_tenant_id,
|
||||
self._driver.service_network_id,
|
||||
self.share['share_network_id'],
|
||||
'fake_cidr')
|
||||
self._driver.neutron_api.create_port.assert_called_once_with(
|
||||
self._driver.service_tenant_id,
|
||||
self._driver.service_network_id,
|
||||
subnet_id='fake_subnet_id',
|
||||
fixed_ip=None,
|
||||
device_owner='manila')
|
||||
self._driver._get_cidr_for_subnet.assert_called_once_with([])
|
||||
self.assertEqual(result, fake_port)
|
||||
|
||||
def test_get_private_router(self):
|
||||
fake_net = fake_network.FakeNetwork()
|
||||
fake_subnet = fake_network.FakeSubnet(gateway_ip='fake_ip')
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet['id'],
|
||||
'ip_address': fake_subnet['gateway_ip']}],
|
||||
device_id='fake_router_id')
|
||||
fake_router = fake_network.FakeRouter(id='fake_router_id')
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
self.stubs.Set(self._driver.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[fake_port]))
|
||||
self.stubs.Set(self._driver.neutron_api, 'show_router',
|
||||
mock.Mock(return_value=fake_router))
|
||||
|
||||
result = self._driver._get_private_router(
|
||||
{'neutron_subnet_id': fake_subnet['id'],
|
||||
'neutron_net_id': fake_net['id']})
|
||||
|
||||
self._driver.neutron_api.get_subnet.\
|
||||
assert_called_once_with(fake_subnet['id'])
|
||||
self._driver.neutron_api.list_ports.\
|
||||
assert_called_once_with(network_id=fake_net['id'])
|
||||
self._driver.neutron_api.show_router.\
|
||||
assert_called_once_with(fake_router['id'])
|
||||
self.assertEqual(result, fake_router)
|
||||
|
||||
def test_get_private_router_exception(self):
|
||||
fake_net = fake_network.FakeNetwork()
|
||||
fake_subnet = fake_network.FakeSubnet(gateway_ip='fake_ip')
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
self.stubs.Set(self._driver.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._get_private_router,
|
||||
{'neutron_subnet_id': fake_subnet['id'],
|
||||
'neutron_net_id': fake_net['id']})
|
||||
|
||||
def test_setup_connectivity_with_service_instances(self):
|
||||
fake_subnet = fake_network.FakeSubnet(cidr='10.254.0.1/29')
|
||||
fake_port = fake_network.FakePort(fixed_ips=[
|
||||
{'subnet_id': fake_subnet['id'], 'ip_address': '10.254.0.2'}],
|
||||
mac_address='fake_mac_address')
|
||||
|
||||
self.stubs.Set(self._driver, '_setup_service_port',
|
||||
mock.Mock(return_value=fake_port))
|
||||
self.stubs.Set(self._driver.vif_driver, 'get_device_name',
|
||||
mock.Mock(return_value='fake_interface_name'))
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_subnet',
|
||||
mock.Mock(return_value=fake_subnet))
|
||||
self.stubs.Set(self._driver, '_clean_garbage', mock.Mock())
|
||||
self.stubs.Set(self._driver.vif_driver, 'plug', mock.Mock())
|
||||
device_mock = mock.Mock()
|
||||
self.stubs.Set(generic.ip_lib, 'IPDevice',
|
||||
mock.Mock(return_value=device_mock))
|
||||
|
||||
self._driver._setup_connectivity_with_service_instances()
|
||||
|
||||
self._driver._setup_service_port.assert_called_once()
|
||||
self._driver.vif_driver.get_device_name.\
|
||||
assert_called_once_with(fake_port)
|
||||
self._driver.vif_driver.plug.assert_called_once_with(fake_port['id'],
|
||||
'fake_interface_name', fake_port['mac_address'])
|
||||
self._driver.neutron_api.get_subnet.\
|
||||
assert_called_once_with(fake_subnet['id'])
|
||||
self._driver.vif_driver.init_l3.assert_called_once()
|
||||
generic.ip_lib.IPDevice.assert_called_once()
|
||||
device_mock.route.pullup_route.assert_called_once()
|
||||
self._driver._clean_garbage.assert_called_once_with(device_mock)
|
||||
|
||||
def test_setup_service_port(self):
|
||||
fake_service_port = fake_network.FakePort(device_id='manila-share')
|
||||
fake_service_net = fake_network.FakeNetwork(subnets=[])
|
||||
self.stubs.Set(self._driver.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[]))
|
||||
self.stubs.Set(self._driver, '_execute',
|
||||
mock.Mock(return_value=('fake_host', '')))
|
||||
self.stubs.Set(self._driver.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_network',
|
||||
mock.Mock(return_value=fake_service_net))
|
||||
self.stubs.Set(self._driver.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = self._driver._setup_service_port()
|
||||
|
||||
self._driver.neutron_api.list_ports.\
|
||||
assert_called_once_with(device_id='manila-share')
|
||||
self._driver.db.service_get_all_by_topic.assert_called_once()
|
||||
self._driver.neutron_api.create_port.assert_called_once_with(
|
||||
self._driver.service_tenant_id,
|
||||
self._driver.service_network_id,
|
||||
device_id='manila-share',
|
||||
device_owner='manila:generic_driver',
|
||||
host_id='fake_host'
|
||||
)
|
||||
self._driver.neutron_api.get_network.assert_called_once()
|
||||
self.assertFalse(self._driver.neutron_api.update_port_fixed_ips.called)
|
||||
self.assertEqual(result, fake_service_port)
|
||||
|
||||
def test_setup_service_port_ambigious_ports(self):
|
||||
fake_service_port = fake_network.FakePort(device_id='manila-share')
|
||||
self.stubs.Set(self._driver.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[fake_service_port, fake_service_port]))
|
||||
self.assertRaises(exception.ManilaException,
|
||||
self._driver._setup_service_port)
|
||||
|
||||
def test_setup_service_port_exists(self):
|
||||
fake_service_port = fake_network.FakePort(device_id='manila-share')
|
||||
fake_service_net = fake_network.FakeNetwork(subnets=[])
|
||||
self.stubs.Set(self._driver.neutron_api, 'list_ports',
|
||||
mock.Mock(return_value=[fake_service_port]))
|
||||
self.stubs.Set(self._driver.db, 'service_get_all_by_topic',
|
||||
mock.Mock(return_value=[{'host': 'fake_host'}]))
|
||||
self.stubs.Set(self._driver.neutron_api, 'create_port',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
self.stubs.Set(self._driver.neutron_api, 'get_network',
|
||||
mock.Mock(return_value=fake_service_net))
|
||||
self.stubs.Set(self._driver.neutron_api, 'update_port_fixed_ips',
|
||||
mock.Mock(return_value=fake_service_port))
|
||||
|
||||
result = self._driver._setup_service_port()
|
||||
|
||||
self._driver.neutron_api.list_ports.\
|
||||
assert_called_once_with(device_id='manila-share')
|
||||
self.assertFalse(self._driver.db.service_get_all_by_topic.called)
|
||||
self.assertFalse(self._driver.neutron_api.create_port.called)
|
||||
self._driver.neutron_api.get_network.assert_called_once()
|
||||
self.assertFalse(self._driver.neutron_api.update_port_fixed_ips.called)
|
||||
self.assertEqual(result, fake_service_port)
|
||||
|
||||
def test_get_cidr_for_subnet(self):
|
||||
serv_cidr = generic.netaddr.IPNetwork(CONF.service_network_cidr)
|
||||
cidrs = serv_cidr.subnet(29)
|
||||
cidr1 = str(cidrs.next())
|
||||
cidr2 = str(cidrs.next())
|
||||
|
||||
result = self._driver._get_cidr_for_subnet([])
|
||||
self.assertEqual(result, cidr1)
|
||||
|
||||
fake_subnet = fake_network.FakeSubnet(cidr=cidr1)
|
||||
result = self._driver._get_cidr_for_subnet([fake_subnet])
|
||||
self.assertEqual(result, cidr2)
|
||||
|
||||
def test_allocate_container(self):
|
||||
fake_vol = fake_volume.FakeVolume()
|
||||
self.stubs.Set(self._driver.volume_api, 'create',
|
||||
|
@ -1036,7 +453,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
|
||||
def test_create_share_from_snapshot(self):
|
||||
self._helper_nfs.create_export.return_value = 'fakelocation'
|
||||
methods = ('_get_service_instance', '_allocate_container',
|
||||
methods = ('get_service_instance', '_allocate_container',
|
||||
'_attach_volume', '_mount_device')
|
||||
for method in methods:
|
||||
self.stubs.Set(self._driver, method, mock.Mock())
|
||||
|
@ -1049,7 +466,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
|
||||
def test_delete_share(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
self.stubs.Set(self._driver, '_get_service_instance',
|
||||
self.stubs.Set(self._driver, 'get_service_instance',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self.stubs.Set(self._driver, '_unmount_device', mock.Mock())
|
||||
self.stubs.Set(self._driver, '_detach_volume', mock.Mock())
|
||||
|
@ -1057,7 +474,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
|
||||
self._driver.delete_share(self._context, self.share)
|
||||
|
||||
self._driver._get_service_instance.assert_called_once()
|
||||
self._driver.get_service_instance.assert_called_once()
|
||||
self._driver._unmount_device.assert_called_once()
|
||||
self._driver._detach_volume.assert_called_once()
|
||||
self._driver._deallocate_container.assert_called_once()
|
||||
|
@ -1097,7 +514,7 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
|
||||
def test_ensure_share(self):
|
||||
self._helper_nfs.create_export.return_value = 'fakelocation'
|
||||
methods = ('_get_service_instance', '_get_volume',
|
||||
methods = ('get_service_instance', '_get_volume',
|
||||
'_attach_volume', '_mount_device')
|
||||
for method in methods:
|
||||
self.stubs.Set(self._driver, method, mock.Mock())
|
||||
|
@ -1108,11 +525,11 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
def test_allow_access(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
access = {'access_type': 'ip', 'access_to': 'fake_dest'}
|
||||
self.stubs.Set(self._driver, '_get_service_instance',
|
||||
self.stubs.Set(self._driver, 'get_service_instance',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self._driver.allow_access(self._context, self.share, access)
|
||||
|
||||
self._driver._get_service_instance.assert_called_once()
|
||||
self._driver.get_service_instance.assert_called_once()
|
||||
self._driver._helpers[self.share['share_proto']].\
|
||||
allow_access.assert_called_once_with(fake_server,
|
||||
self.share['name'],
|
||||
|
@ -1122,11 +539,11 @@ class GenericShareDriverTestCase(test.TestCase):
|
|||
def test_deny_access(self):
|
||||
fake_server = fake_compute.FakeServer()
|
||||
access = {'access_type': 'ip', 'access_to': 'fake_dest'}
|
||||
self.stubs.Set(self._driver, '_get_service_instance',
|
||||
self.stubs.Set(self._driver, 'get_service_instance',
|
||||
mock.Mock(return_value=fake_server))
|
||||
self._driver.deny_access(self._context, self.share, access)
|
||||
|
||||
self._driver._get_service_instance.assert_called_once()
|
||||
self._driver.get_service_instance.assert_called_once()
|
||||
self._driver._helpers[self.share['share_proto']].\
|
||||
deny_access.assert_called_once_with(fake_server,
|
||||
self.share['name'],
|
||||
|
|
Loading…
Reference in New Issue