Coverage for manila/share/drivers/glusterfs/glusterfs_native.py: 99%
75 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright (c) 2014 Red Hat, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
16""" GlusterFS native protocol (glusterfs) driver for shares.
18Manila share is a GlusterFS volume. Unlike the generic driver, this
19does not use service VM approach. Instances directly talk with the
20GlusterFS backend storage pool. Instance use the 'glusterfs' protocol
21to mount the GlusterFS share. Access to the share is allowed via
22SSL Certificates. Only the instance which has the SSL trust established
23with the GlusterFS backend can mount and hence use the share.
25Supports working with multiple glusterfs volumes.
26"""
28import re
30from oslo_log import log
32from manila.common import constants
33from manila import exception
34from manila.i18n import _
35from manila.share import driver
36from manila.share.drivers.glusterfs import common
37from manila.share.drivers.glusterfs import layout
38from manila import utils
40LOG = log.getLogger(__name__)
43ACCESS_TYPE_CERT = 'cert'
44AUTH_SSL_ALLOW = 'auth.ssl-allow'
45CLIENT_SSL = 'client.ssl'
46NFS_EXPORT_VOL = 'nfs.export-volumes'
47SERVER_SSL = 'server.ssl'
48DYNAMIC_AUTH = 'server.dynamic-auth'
51class GlusterfsNativeShareDriver(driver.ExecuteMixin,
52 layout.GlusterfsShareDriverBase):
53 """GlusterFS native protocol (glusterfs) share driver.
55 Executes commands relating to Shares.
56 Supports working with multiple glusterfs volumes.
58 API version history:
60 1.0 - Initial version.
61 1.1 - Support for working with multiple gluster volumes.
62 """
64 GLUSTERFS_VERSION_MIN = (3, 6)
66 _supported_access_levels = (constants.ACCESS_LEVEL_RW, )
67 _supported_access_types = (ACCESS_TYPE_CERT, )
68 supported_layouts = ('layout_volume.GlusterfsVolumeMappedLayout',)
69 supported_protocols = ('GLUSTERFS',)
71 def __init__(self, *args, **kwargs):
72 super(GlusterfsNativeShareDriver, self).__init__(
73 False, *args, **kwargs)
74 LOG.warning('GlusterFS native share driver has been deprecated and is '
75 'expected to be removed in a future release.')
76 self._helpers = None
77 self.backend_name = self.configuration.safe_get(
78 'share_backend_name') or 'GlusterFS-Native'
80 def _setup_via_manager(self, share_mgr, share_mgr_parent=None):
81 # Enable gluster volumes for SSL access only.
83 gluster_mgr = share_mgr['manager']
84 gluster_mgr_parent = (share_mgr_parent or {}).get('manager', None)
86 ssl_allow_opt = (gluster_mgr_parent if gluster_mgr_parent else
87 gluster_mgr).get_vol_option(
88 AUTH_SSL_ALLOW)
89 if not ssl_allow_opt:
90 # Not having AUTH_SSL_ALLOW set is a problematic edge case.
91 # - In GlusterFS 3.6, it implies that access is allowed to
92 # none, including intra-service access, which causes
93 # problems internally in GlusterFS
94 # - In GlusterFS 3.7, it implies that access control is
95 # disabled, which defeats the purpose of this driver --
96 # so to avoid these possibilities, we throw an error in this case.
97 msg = (_("Option %(option)s is not defined on gluster volume. "
98 "Volume: %(volname)s") %
99 {'volname': gluster_mgr.volume,
100 'option': AUTH_SSL_ALLOW})
101 LOG.error(msg)
102 raise exception.GlusterfsException(msg)
104 gluster_actions = []
105 if gluster_mgr_parent:
106 # The clone of the snapshot, a new volume, retains the authorized
107 # access list of the snapshotted volume/share, which includes TLS
108 # identities of the backend servers, Manila hosts and clients.
109 # Retain the identities of the GlusterFS servers and Manila host,
110 # and exclude those of the clients in the authorized access list of
111 # the new volume. The TLS identities of GlusterFS servers are
112 # determined as those that are prefixed by 'glusterfs-server'.
113 # And the TLS identity of the Manila host is identified as the
114 # one that has 'manila-host' as the prefix.
115 # Wrt. GlusterFS' parsing of auth.ssl-allow, please see code from
116 # https://github.com/gluster/glusterfs/blob/v3.6.2/
117 # xlators/protocol/auth/login/src/login.c#L80
118 # until end of gf_auth() function
119 old_access_list = re.split('[ ,]', ssl_allow_opt)
120 glusterfs_server_CN_pattern = r'\Aglusterfs-server'
121 manila_host_CN_pattern = r'\Amanila-host'
122 regex = re.compile(
123 r'%(pattern1)s|%(pattern2)s' % {
124 'pattern1': glusterfs_server_CN_pattern,
125 'pattern2': manila_host_CN_pattern})
126 access_to = ','.join(filter(regex.match, old_access_list))
127 gluster_actions.append((AUTH_SSL_ALLOW, access_to))
129 for option, value in (
130 (NFS_EXPORT_VOL, False), (CLIENT_SSL, True), (SERVER_SSL, True)
131 ):
132 gluster_actions.append((option, value))
134 for action in gluster_actions:
135 gluster_mgr.set_vol_option(*action)
137 gluster_mgr.set_vol_option(DYNAMIC_AUTH, True, ignore_failure=True)
139 # SSL enablement requires a fresh volume start
140 # to take effect
141 if gluster_mgr_parent:
142 # in this case the volume is not started
143 # yet (will only be started after this func
144 # returns), so we have nothing to do here
145 pass
146 else:
147 common._restart_gluster_vol(gluster_mgr)
149 return gluster_mgr.export
151 @utils.synchronized("glusterfs_native_access", external=False)
152 def _update_access_via_manager(self, gluster_mgr, context, share,
153 add_rules, delete_rules,
154 recovery=False, share_server=None):
155 """Update access rules, authorize SSL CNs (Common Names)."""
157 # Fetch existing authorized CNs, the value of Gluster option
158 # 'auth.ssl-allow' that is available as a comma separated string.
159 # wrt. GlusterFS' parsing of auth.ssl-allow, please see code from
160 # https://github.com/gluster/glusterfs/blob/v3.6.2/
161 # xlators/protocol/auth/login/src/login.c#L80
162 # until end of gf_auth() function
163 ssl_allow_opt = gluster_mgr.get_vol_option(AUTH_SSL_ALLOW)
165 existing_rules_set = set(re.split('[ ,]', ssl_allow_opt))
166 add_rules_set = {rule['access_to'] for rule in add_rules}
167 for rule in add_rules_set:
168 if re.search('[ ,]', rule):
169 raise exception.GlusterfsException(
170 _("Invalid 'access_to' '%s': common names used for "
171 "GlusterFS authentication should not contain comma "
172 "or whitespace.") % rule)
173 delete_rules_set = {rule['access_to'] for rule in delete_rules}
174 new_rules_set = (
175 (existing_rules_set | add_rules_set) - delete_rules_set)
177 # Addition or removal of CNs in the authorized list through the
178 # Gluster CLI, used by 'GlusterManager' objects, can only be done by
179 # replacing the existing list with the newly modified list.
180 ssl_allow_opt = ','.join(sorted(new_rules_set))
181 gluster_mgr.set_vol_option(AUTH_SSL_ALLOW, ssl_allow_opt)
183 # When the Gluster option, DYNAMIC_AUTH is not enabled for the gluster
184 # volume/manila share, the removal of CN of a client does not affect
185 # the client's existing connection to the volume until the volume is
186 # restarted.
187 if delete_rules: 187 ↛ exitline 187 didn't return from function '_update_access_via_manager' because the condition on line 187 was always true
188 dynauth = gluster_mgr.get_vol_option(DYNAMIC_AUTH, boolean=True)
189 if not dynauth:
190 common._restart_gluster_vol(gluster_mgr)
192 def _update_share_stats(self):
193 """Send stats info for the GlusterFS volume."""
195 data = dict(
196 share_backend_name=self.backend_name,
197 vendor_name='Red Hat',
198 driver_version='1.1',
199 storage_protocol='glusterfs',
200 reserved_percentage=self.configuration.reserved_share_percentage,
201 reserved_snapshot_percentage=(
202 self.configuration.reserved_share_from_snapshot_percentage or
203 self.configuration.reserved_share_percentage),
204 reserved_share_extend_percentage=(
205 self.configuration.reserved_share_extend_percentage or
206 self.configuration.reserved_share_percentage))
208 # We don't use a service mount to get stats data.
209 # Instead we use glusterfs quota feature and use that to limit
210 # the share to its expected share['size'].
212 # TODO(deepakcs): Change below once glusterfs supports volume
213 # specific stats via the gluster cli.
214 data['total_capacity_gb'] = 'unknown'
215 data['free_capacity_gb'] = 'unknown'
217 super(GlusterfsNativeShareDriver, self)._update_share_stats(data)
219 def get_network_allocations_number(self):
220 return 0