f27538323b
The extant Manila driver for cDOT supports multi-svm mode only (i.e. driver_handles_share_servers = True). This commit adds a single-svm cDOT driver (driver_handles_share_servers = False) for simpler operation without network plug-ins. To work in this mode the storage admin must pre-create a vserver with the desired LIFs and protocols configured, and specify the vserver in the config variable 'netapp_vserver'. To configure this driver, use a config like the following: [cmode] share_driver = manila.share.drivers.netapp.common.NetAppDriver driver_handles_share_servers = False netapp_storage_family = ontap_cluster netapp_server_hostname=192.168.228.42 netapp_login=admin netapp_password=cluster3 netapp_server_port=443 netapp_transport_type=https netapp_aggregate_name_search_pattern=manila netapp_vserver = manila_svm Implements blueprint netapp-cdot-driver-without-handling-share-servers Change-Id: I0cfafe3d64a9a9b52f1eca9f28a0e937b3b84f44
227 lines
7.4 KiB
Python
227 lines
7.4 KiB
Python
# Copyright (c) 2015 Bob Callaway. All rights reserved.
|
|
# Copyright (c) 2015 Tom Barron. All rights reserved.
|
|
# Copyright (c) 2015 Clinton Knight. 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.
|
|
"""Utilities for NetApp drivers."""
|
|
|
|
import collections
|
|
import decimal
|
|
import platform
|
|
|
|
from oslo_concurrency import processutils as putils
|
|
from oslo_log import log
|
|
import six
|
|
|
|
from manila import exception
|
|
from manila.i18n import _, _LI, _LW
|
|
from manila import version
|
|
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
VALID_TRACE_FLAGS = ['method', 'api']
|
|
TRACE_METHOD = False
|
|
TRACE_API = False
|
|
|
|
|
|
def validate_driver_instantiation(**kwargs):
|
|
"""Checks if a driver is instantiated other than by the unified driver.
|
|
|
|
Helps check direct instantiation of netapp drivers.
|
|
Call this function in every netapp block driver constructor.
|
|
"""
|
|
if kwargs and kwargs.get('netapp_mode') == 'proxy':
|
|
return
|
|
LOG.warning(_LW('Please use NetAppDriver in the configuration file '
|
|
'to load the driver instead of directly specifying '
|
|
'the driver module name.'))
|
|
|
|
|
|
def check_flags(required_flags, configuration):
|
|
"""Ensure that the flags we care about are set."""
|
|
for flag in required_flags:
|
|
if getattr(configuration, flag, None) is None:
|
|
msg = _('Configuration value %s is not set.') % flag
|
|
raise exception.InvalidInput(reason=msg)
|
|
|
|
|
|
def round_down(value, precision):
|
|
"""Round a number downward using a specified level of precision.
|
|
|
|
Example: round_down(float(total_space_in_bytes) / units.Gi, '0.01')
|
|
"""
|
|
return float(decimal.Decimal(six.text_type(value)).quantize(
|
|
decimal.Decimal(precision), rounding=decimal.ROUND_DOWN))
|
|
|
|
|
|
def setup_tracing(trace_flags_string):
|
|
global TRACE_METHOD
|
|
global TRACE_API
|
|
TRACE_METHOD = False
|
|
TRACE_API = False
|
|
if trace_flags_string:
|
|
flags = trace_flags_string.split(',')
|
|
flags = [flag.strip() for flag in flags]
|
|
for invalid_flag in list(set(flags) - set(VALID_TRACE_FLAGS)):
|
|
LOG.warning(_LW('Invalid trace flag: %s') % invalid_flag)
|
|
TRACE_METHOD = 'method' in flags
|
|
TRACE_API = 'api' in flags
|
|
|
|
|
|
def trace(f):
|
|
def trace_wrapper(self, *args, **kwargs):
|
|
if TRACE_METHOD:
|
|
LOG.debug('Entering method %s', f.__name__)
|
|
result = f(self, *args, **kwargs)
|
|
if TRACE_METHOD:
|
|
LOG.debug('Leaving method %s', f.__name__)
|
|
return result
|
|
return trace_wrapper
|
|
|
|
|
|
def convert_to_list(value):
|
|
|
|
if value is None:
|
|
return []
|
|
elif isinstance(value, six.string_types):
|
|
return [value]
|
|
elif isinstance(value, collections.Iterable):
|
|
return list(value)
|
|
else:
|
|
return [value]
|
|
|
|
|
|
class OpenStackInfo(object):
|
|
"""OS/distribution, release, and version.
|
|
|
|
NetApp uses these fields as content for EMS log entry.
|
|
"""
|
|
|
|
PACKAGE_NAME = 'python-manila'
|
|
|
|
def __init__(self):
|
|
self._version = 'unknown version'
|
|
self._release = 'unknown release'
|
|
self._vendor = 'unknown vendor'
|
|
self._platform = 'unknown platform'
|
|
|
|
def _update_version_from_version_string(self):
|
|
try:
|
|
self._version = version.version_info.version_string()
|
|
except Exception:
|
|
pass
|
|
|
|
def _update_release_from_release_string(self):
|
|
try:
|
|
self._release = version.version_info.release_string()
|
|
except Exception:
|
|
pass
|
|
|
|
def _update_platform(self):
|
|
try:
|
|
self._platform = platform.platform()
|
|
except Exception:
|
|
pass
|
|
|
|
@staticmethod
|
|
def _get_version_info_version():
|
|
return version.version_info.version
|
|
|
|
@staticmethod
|
|
def _get_version_info_release():
|
|
return version.version_info.release
|
|
|
|
def _update_info_from_version_info(self):
|
|
try:
|
|
ver = self._get_version_info_version()
|
|
if ver:
|
|
self._version = ver
|
|
except Exception:
|
|
pass
|
|
try:
|
|
rel = self._get_version_info_release()
|
|
if rel:
|
|
self._release = rel
|
|
except Exception:
|
|
pass
|
|
|
|
# RDO, RHEL-OSP, Mirantis on Redhat, SUSE.
|
|
def _update_info_from_rpm(self):
|
|
LOG.debug('Trying rpm command.')
|
|
try:
|
|
out, err = putils.execute("rpm", "-q", "--queryformat",
|
|
"'%{version}\t%{release}\t%{vendor}'",
|
|
self.PACKAGE_NAME)
|
|
if not out:
|
|
LOG.info(_LI('No rpm info found for %(pkg)s package.') % {
|
|
'pkg': self.PACKAGE_NAME})
|
|
return False
|
|
parts = out.split()
|
|
self._version = parts[0]
|
|
self._release = parts[1]
|
|
self._vendor = ' '.join(parts[2::])
|
|
return True
|
|
except Exception as e:
|
|
LOG.info(_LI('Could not run rpm command: %(msg)s.') % {
|
|
'msg': e})
|
|
return False
|
|
|
|
# Ubuntu, Mirantis on Ubuntu.
|
|
def _update_info_from_dpkg(self):
|
|
LOG.debug('Trying dpkg-query command.')
|
|
try:
|
|
_vendor = None
|
|
out, err = putils.execute("dpkg-query", "-W", "-f='${Version}'",
|
|
self.PACKAGE_NAME)
|
|
if not out:
|
|
LOG.info(_LI(
|
|
'No dpkg-query info found for %(pkg)s package.') % {
|
|
'pkg': self.PACKAGE_NAME})
|
|
return False
|
|
# Debian format: [epoch:]upstream_version[-debian_revision]
|
|
deb_version = out
|
|
# In case epoch or revision is missing, copy entire string.
|
|
_release = deb_version
|
|
if ':' in deb_version:
|
|
deb_epoch, upstream_version = deb_version.split(':')
|
|
_release = upstream_version
|
|
if '-' in deb_version:
|
|
deb_revision = deb_version.split('-')[1]
|
|
_vendor = deb_revision
|
|
self._release = _release
|
|
if _vendor:
|
|
self._vendor = _vendor
|
|
return True
|
|
except Exception as e:
|
|
LOG.info(_LI('Could not run dpkg-query command: %(msg)s.') % {
|
|
'msg': e})
|
|
return False
|
|
|
|
def _update_openstack_info(self):
|
|
self._update_version_from_version_string()
|
|
self._update_release_from_release_string()
|
|
self._update_platform()
|
|
# Some distributions override with more meaningful information.
|
|
self._update_info_from_version_info()
|
|
# See if we have still more targeted info from rpm or apt.
|
|
found_package = self._update_info_from_rpm()
|
|
if not found_package:
|
|
self._update_info_from_dpkg()
|
|
|
|
def info(self):
|
|
self._update_openstack_info()
|
|
return '%(version)s|%(release)s|%(vendor)s|%(platform)s' % {
|
|
'version': self._version, 'release': self._release,
|
|
'vendor': self._vendor, 'platform': self._platform}
|