6879bd0720
This patch allows an OpenStack environment to run as a secure NAS environment from the client and server perspective, including having root squash enabled and not running file operations as the 'root' user. This also sets Cinder file permissions as 660: removing other/world file access. The "nas_secure_file_permissions" option controls the setting of file permissions when Cinder volumes are created. The option defaults to "auto" to gracefully handle upgrade scenarios. When set to "auto", a check is done during Cinder startup to determine if there are existing Cinder volumes: no volumes will set the option to 'true', and use secure file permissions. The detection of existing volumes will set the option to 'false', and use the current insecure method of handling file permissions. The "nas_secure_file_operations" option controls whether file operations are run as the 'root' user or the current OpenStack 'process' user. The option defaults to "auto" to gracefully handle upgrade scenarios. When set to "auto", a check is done during Cinder startup to determine if there are existing Cinder volumes: no volumes will set the option to 'true', be secure and do NOT run as the 'root' user. The detection of existing volumes will set the option to 'false', and use the current method of running operations as the 'root' user. For new installations, a 'marker file' is written so that subsequent restarts of Cinder will know what the original determination had been. This patch enables this functionality only for the NFS driver. Other similar drivers can use this code to enable the same functionality with the same config options. DocImpact Change-Id: I3d25f593beab7f5462576b14ab62d13d8c53e7c6 Implements: blueprint secure-nfs Partial-Bug: 1260679
182 lines
6.4 KiB
Python
182 lines
6.4 KiB
Python
# Copyright (c) 2012 NetApp, Inc.
|
|
# Copyright (c) 2012 OpenStack Foundation
|
|
# 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.
|
|
"""
|
|
Unified driver for NetApp storage systems.
|
|
|
|
Supports call to multiple storage systems of different families and protocols.
|
|
"""
|
|
|
|
from cinder import exception
|
|
from cinder.i18n import _
|
|
from cinder.openstack.common import importutils
|
|
from cinder.openstack.common import log as logging
|
|
from cinder.volume import driver
|
|
from cinder.volume.drivers.netapp.options import netapp_proxy_opts
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
# NOTE(singn): Holds family:{protocol:driver} registration information.
|
|
# Plug in new families and protocols to support new drivers.
|
|
# No other code modification required.
|
|
netapp_unified_plugin_registry =\
|
|
{'ontap_cluster':
|
|
{
|
|
'iscsi':
|
|
'cinder.volume.drivers.netapp.iscsi.NetAppDirectCmodeISCSIDriver',
|
|
'nfs': 'cinder.volume.drivers.netapp.nfs.NetAppDirectCmodeNfsDriver'
|
|
},
|
|
'ontap_7mode':
|
|
{
|
|
'iscsi':
|
|
'cinder.volume.drivers.netapp.iscsi.NetAppDirect7modeISCSIDriver',
|
|
'nfs':
|
|
'cinder.volume.drivers.netapp.nfs.NetAppDirect7modeNfsDriver'
|
|
},
|
|
'eseries':
|
|
{
|
|
'iscsi':
|
|
'cinder.volume.drivers.netapp.eseries.iscsi.Driver'
|
|
},
|
|
}
|
|
|
|
# NOTE(singn): Holds family:protocol information.
|
|
# Protocol represents the default protocol driver option
|
|
# in case no protocol is specified by the user in configuration.
|
|
netapp_family_default =\
|
|
{
|
|
'ontap_cluster': 'nfs',
|
|
'ontap_7mode': 'nfs',
|
|
'eseries': 'iscsi'
|
|
}
|
|
|
|
|
|
class NetAppDriver(object):
|
|
""""NetApp unified block storage driver.
|
|
|
|
Acts as a mediator to NetApp storage drivers.
|
|
Proxies requests based on the storage family and protocol configured.
|
|
Override the proxy driver method by adding method in this driver.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(NetAppDriver, self).__init__()
|
|
self.configuration = kwargs.get('configuration', None)
|
|
if self.configuration:
|
|
self.configuration.append_config_values(netapp_proxy_opts)
|
|
else:
|
|
raise exception.InvalidInput(
|
|
reason=_("Required configuration not found"))
|
|
self.driver = NetAppDriverFactory.create_driver(
|
|
self.configuration.netapp_storage_family,
|
|
self.configuration.netapp_storage_protocol,
|
|
*args, **kwargs)
|
|
|
|
def __setattr__(self, name, value):
|
|
"""Sets the attribute."""
|
|
if getattr(self, 'driver', None):
|
|
self.driver.__setattr__(name, value)
|
|
return
|
|
object.__setattr__(self, name, value)
|
|
|
|
def __getattr__(self, name):
|
|
""""Gets the attribute."""
|
|
drv = object.__getattribute__(self, 'driver')
|
|
return getattr(drv, name)
|
|
|
|
|
|
class NetAppDriverFactory(object):
|
|
"""Factory to instantiate appropriate NetApp driver."""
|
|
|
|
@staticmethod
|
|
def create_driver(
|
|
storage_family, storage_protocol, *args, **kwargs):
|
|
""""Creates an appropriate driver based on family and protocol."""
|
|
fmt = {'storage_family': storage_family,
|
|
'storage_protocol': storage_protocol}
|
|
LOG.info(_('Requested unified config: %(storage_family)s and '
|
|
'%(storage_protocol)s') % fmt)
|
|
storage_family = storage_family.lower()
|
|
family_meta = netapp_unified_plugin_registry.get(storage_family)
|
|
if family_meta is None:
|
|
raise exception.InvalidInput(
|
|
reason=_('Storage family %s is not supported')
|
|
% storage_family)
|
|
if storage_protocol is None:
|
|
storage_protocol = netapp_family_default.get(storage_family)
|
|
fmt['storage_protocol'] = storage_protocol
|
|
if storage_protocol is None:
|
|
raise exception.InvalidInput(
|
|
reason=_('No default storage protocol found'
|
|
' for storage family %(storage_family)s')
|
|
% fmt)
|
|
storage_protocol = storage_protocol.lower()
|
|
driver_loc = family_meta.get(storage_protocol)
|
|
if driver_loc is None:
|
|
raise exception.InvalidInput(
|
|
reason=_('Protocol %(storage_protocol)s is not supported'
|
|
' for storage family %(storage_family)s')
|
|
% fmt)
|
|
NetAppDriverFactory.check_netapp_driver(driver_loc)
|
|
kwargs = kwargs or {}
|
|
kwargs['netapp_mode'] = 'proxy'
|
|
driver = importutils.import_object(driver_loc, *args, **kwargs)
|
|
LOG.info(_('NetApp driver of family %(storage_family)s and protocol'
|
|
' %(storage_protocol)s loaded') % fmt)
|
|
return driver
|
|
|
|
@staticmethod
|
|
def check_netapp_driver(location):
|
|
"""Checks if the driver requested is a netapp driver."""
|
|
if location.find(".netapp.") == -1:
|
|
raise exception.InvalidInput(
|
|
reason=_("Only loading netapp drivers supported."))
|
|
|
|
|
|
class Deprecated(driver.VolumeDriver):
|
|
"""Deprecated driver for NetApp.
|
|
|
|
This driver is used for mapping deprecated
|
|
drivers to itself in manager. It prevents cinder
|
|
from getting errored out in case of upgrade scenarios
|
|
and also suggests further steps.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self._log_deprecated_warn()
|
|
|
|
def _log_deprecated_warn(self):
|
|
"""Logs appropriate warning and suggestion."""
|
|
|
|
link = "https://communities.netapp.com/groups/openstack"
|
|
msg = _("The configured NetApp driver is deprecated."
|
|
" Please refer the link to resolve the issue '%s'.")
|
|
LOG.warn(msg % link)
|
|
|
|
def check_for_setup_error(self):
|
|
pass
|
|
|
|
def ensure_export(self, context, volume):
|
|
pass
|
|
|
|
def get_volume_stats(self, refresh=False):
|
|
"""Return the current state of the volume service. If 'refresh' is
|
|
True, run the update first.
|
|
"""
|
|
self._log_deprecated_warn()
|
|
return None
|