manila/manila/share/driver.py

223 lines
7.7 KiB
Python

# Copyright 2012 NetApp
# 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.
"""
Drivers for shares.
"""
import time
from oslo.config import cfg
from manila import exception
from manila.i18n import _LE
from manila import network
from manila.openstack.common import log as logging
from manila import utils
LOG = logging.getLogger(__name__)
share_opts = [
# NOTE(rushiagr): Reasonable to define this option at only one place.
cfg.IntOpt(
'num_shell_tries',
default=3,
help='Number of times to attempt to run flakey shell commands.'),
cfg.IntOpt(
'reserved_share_percentage',
default=0,
help='The percentage of backend capacity reserved.'),
cfg.StrOpt(
'share_backend_name',
default=None,
help='The backend name for a given driver implementation.'),
cfg.StrOpt(
'network_config_group',
default=None,
help="Name of the configuration group in the Manila conf file "
"to look for network config options."
"If not set, the share backend's config group will be used."
"If an option is not found within provided group, then"
"'DEFAULT' group will be used for search of option."),
]
ssh_opts = [
cfg.IntOpt(
'ssh_conn_timeout',
default=60,
help='Backend server SSH connection timeout.'),
cfg.IntOpt(
'ssh_min_pool_conn',
default=1,
help='Minimum number of connections in the SSH pool.'),
cfg.IntOpt(
'ssh_max_pool_conn',
default=10,
help='Maximum number of connections in the SSH pool.'),
]
CONF = cfg.CONF
CONF.register_opts(share_opts)
CONF.register_opts(ssh_opts)
class ExecuteMixin(object):
"""Provides an executable functionality to a driver class."""
def __init__(self, *args, **kwargs):
self.db = None
self.configuration = kwargs.get('configuration', None)
if self.configuration:
self.configuration.append_config_values(share_opts)
self.configuration.append_config_values(ssh_opts)
self.set_execute(kwargs.pop('execute', utils.execute))
def set_execute(self, execute):
self._execute = execute
def _try_execute(self, *command, **kwargs):
# NOTE(vish): Volume commands can partially fail due to timing, but
# running them a second time on failure will usually
# recover nicely.
tries = 0
while True:
try:
self._execute(*command, **kwargs)
return True
except exception.ProcessExecutionError:
tries += 1
if tries >= self.configuration.num_shell_tries:
raise
LOG.exception(_LE("Recovering from a failed execute. "
"Try number %s"), tries)
time.sleep(tries ** 2)
class ShareDriver(object):
"""Class defines interface of NAS driver."""
def __init__(self, *args, **kwargs):
super(ShareDriver, self).__init__()
self.configuration = kwargs.get('configuration', None)
if self.configuration:
self.configuration.append_config_values(share_opts)
network_config_group = (self.configuration.network_config_group or
self.configuration.config_group)
else:
network_config_group = None
self.network_api = network.API(config_group_name=network_config_group)
def create_share(self, context, share, share_server=None):
"""Is called to create share."""
raise NotImplementedError()
def create_share_from_snapshot(self, context, share, snapshot,
share_server=None):
"""Is called to create share from snapshot."""
raise NotImplementedError()
def create_snapshot(self, context, snapshot, share_server=None):
"""Is called to create snapshot."""
raise NotImplementedError()
def delete_share(self, context, share, share_server=None):
"""Is called to remove share."""
raise NotImplementedError()
def delete_snapshot(self, context, snapshot, share_server=None):
"""Is called to remove snapshot."""
raise NotImplementedError()
def ensure_share(self, context, share, share_server=None):
"""Invoked to sure that share is exported."""
raise NotImplementedError()
def allow_access(self, context, share, access, share_server=None):
"""Allow access to the share."""
raise NotImplementedError()
def deny_access(self, context, share, access, share_server=None):
"""Deny access to the share."""
raise NotImplementedError()
def check_for_setup_error(self):
"""Check for setup error."""
pass
def do_setup(self, context):
"""Any initialization the share driver does while starting."""
pass
def get_share_stats(self, refresh=False):
"""Get share status.
If 'refresh' is True, run update the stats first.
"""
if refresh:
self._update_share_status()
return self._stats
def get_network_allocations_number(self):
"""Returns number of network allocations for creating VIFs.
Drivers that use Nova for share servers should return zero (0) here
same as Generic driver does.
Because Nova will handle network resources allocation.
Drivers that handle networking itself should calculate it according
to their own requirements. It can have 1+ network interfaces.
"""
raise NotImplementedError()
def allocate_network(self, context, share_server, share_network,
count=None, **kwargs):
"""Allocate network resources using given network information."""
if count is None:
count = self.get_network_allocations_number()
if count:
kwargs.update(count=count)
self.network_api.allocate_network(
context, share_server, share_network, **kwargs)
def deallocate_network(self, context, share_server_id):
"""Deallocate network resources for the given share server."""
if self.get_network_allocations_number():
self.network_api.deallocate_network(context, share_server_id)
def setup_server(self, network_info, metadata=None):
"""Set up and configures share server with given network parameters."""
pass
def teardown_server(self, server_details, security_services=None):
"""Teardown share server."""
pass
def _update_share_status(self):
"""Retrieve status info from share group."""
LOG.debug("Updating share status")
data = {}
backend_name = self.configuration.safe_get('share_backend_name')
data["share_backend_name"] = backend_name or 'Generic_NFS'
data["vendor_name"] = 'Open Source'
data["driver_version"] = '1.0'
data["storage_protocol"] = None
data['total_capacity_gb'] = 'infinite'
data['free_capacity_gb'] = 'infinite'
data['reserved_percentage'] = 0
data['QoS_support'] = False
self._stats = data