Coverage for manila/share/drivers/dell_emc/driver.py: 92%
137 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) 2019 EMC Corporation.
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"""
17EMC specific NAS storage driver. This driver is a pluggable driver
18that allows specific EMC NAS devices to be plugged-in as the underlying
19backend. Use the Manila configuration variable "share_backend_name"
20to specify, which backend plugins to use.
21"""
23from oslo_config import cfg
24from oslo_log import log
26from manila.share import driver
27from manila.share.drivers.dell_emc import plugin_manager as manager
29EMC_NAS_OPTS = [
30 cfg.StrOpt('emc_nas_login',
31 help='User name for the EMC server.'),
32 cfg.StrOpt('emc_nas_password',
33 secret=True,
34 help='Password for the EMC server.'),
35 cfg.HostAddressOpt('emc_nas_server',
36 help='EMC server hostname or IP address.'),
37 cfg.PortOpt('emc_nas_server_port',
38 default=8080,
39 help='Port number for the EMC server.'),
40 cfg.BoolOpt('emc_nas_server_secure',
41 default=True,
42 help='Use secure connection to server.'),
43 cfg.StrOpt('emc_share_backend',
44 ignore_case=True,
45 choices=['powerscale', 'isilon', 'vnx', 'unity', 'powermax',
46 'powerstore', 'powerflex'],
47 help='Share backend.'),
48 cfg.StrOpt('emc_nas_root_dir',
49 help='The root directory where shares will be located.'),
50 cfg.BoolOpt('emc_ssl_cert_verify',
51 default=True,
52 help='If set to False the https client will not validate the '
53 'SSL certificate of the backend endpoint.'),
54 cfg.StrOpt('emc_ssl_cert_path',
55 help='Can be used to specify a non default path to a '
56 'CA_BUNDLE file or directory with certificates of trusted '
57 'CAs, which will be used to validate the backend.')
58]
60LOG = log.getLogger(__name__)
62CONF = cfg.CONF
63CONF.register_opts(EMC_NAS_OPTS)
66class EMCShareDriver(driver.ShareDriver):
67 """EMC specific NAS driver. Allows for NFS and CIFS NAS storage usage."""
69 def __init__(self, *args, **kwargs):
70 self.configuration = kwargs.get('configuration', None)
71 if self.configuration: 71 ↛ 76line 71 didn't jump to line 76 because the condition on line 71 was always true
72 self.configuration.append_config_values(EMC_NAS_OPTS)
73 self.backend_name = self.configuration.safe_get(
74 'emc_share_backend')
75 else:
76 self.backend_name = CONF.emc_share_backend
77 self.backend_name = self.backend_name or 'EMC_NAS_Storage'
78 self.plugin_manager = manager.EMCPluginManager(
79 namespace='manila.share.drivers.dell_emc.plugins')
80 LOG.info("BACKEND IS: %s", self.backend_name)
81 if self.backend_name == 'vnx': 81 ↛ 82line 81 didn't jump to line 82 because the condition on line 81 was never true
82 LOG.warning('Dell EMC VNX share driver has been deprecated and is '
83 'expected to be removed in a future release.')
84 if self.backend_name == 'isilon': 84 ↛ 85line 84 didn't jump to line 85 because the condition on line 84 was never true
85 self.backend_name = 'powerscale'
86 LOG.warning('Dell EMC isilon share driver has been deprecated and '
87 'is renamed to powerscale. It is expected '
88 'to be removed in a future release.')
89 self.plugin = self.plugin_manager.load_plugin(
90 self.backend_name,
91 configuration=self.configuration)
92 LOG.info(f"PLUGIN HAS: {self.plugin.__dict__}")
93 super(EMCShareDriver, self).__init__(
94 self.plugin.driver_handles_share_servers, *args, **kwargs)
96 self.dhss_mandatory_security_service_association = (
97 self.plugin.dhss_mandatory_security_service_association)
99 self.ipv6_implemented = getattr(self.plugin, 'ipv6_implemented', False)
101 self.revert_to_snap_support = getattr(
102 self.plugin, 'revert_to_snap_support', False)
103 self.shrink_share_support = getattr(
104 self.plugin, 'shrink_share_support', False)
105 self.manage_existing_support = getattr(
106 self.plugin, 'manage_existing_support', False)
107 self.manage_existing_with_server_support = getattr(
108 self.plugin, 'manage_existing_with_server_support', False)
109 self.manage_existing_snapshot_support = getattr(
110 self.plugin, 'manage_existing_snapshot_support', False)
111 self.manage_snapshot_with_server_support = getattr(
112 self.plugin, 'manage_snapshot_with_server_support', False)
113 self.manage_server_support = getattr(
114 self.plugin, 'manage_server_support', False)
115 self.get_share_server_network_info_support = getattr(
116 self.plugin, 'get_share_server_network_info_support', False)
118 def manage_existing(self, share, driver_options):
119 """manage an existing share"""
120 if self.manage_existing_support:
121 return self.plugin.manage_existing(share, driver_options)
122 else:
123 raise NotImplementedError()
125 def manage_existing_with_server(self, share, driver_options,
126 share_server=None):
127 """manage an existing share"""
128 if self.manage_existing_with_server_support:
129 return self.plugin.manage_existing_with_server(
130 share, driver_options, share_server)
131 else:
132 return NotImplementedError()
134 def manage_existing_snapshot(self, snapshot, driver_options):
135 """manage an existing share snapshot"""
136 if self.manage_existing_snapshot_support:
137 return self.plugin.manage_existing_snapshot(snapshot,
138 driver_options)
139 else:
140 return NotImplementedError()
142 def manage_existing_snapshot_with_server(self, snapshot, driver_options,
143 share_server=None):
144 """manage an existing share snapshot"""
145 if self.manage_snapshot_with_server_support:
146 return self.plugin.manage_existing_snapshot_with_server(
147 snapshot, driver_options, share_server=None)
148 else:
149 return NotImplementedError()
151 def manage_server(self, context, share_server, identifier,
152 driver_options):
153 if self.manage_server_support:
154 return self.plugin.manage_server(context, share_server,
155 identifier, driver_options)
156 else:
157 return NotImplementedError()
159 def get_share_server_network_info(
160 self, context, share_server, identifier, driver_options):
161 if self.get_share_server_network_info_support:
162 return self.plugin.get_share_server_network_info(
163 context, share_server, identifier, driver_options)
164 else:
165 return NotImplementedError()
167 def unmanage_server(self, server_details, security_services=None):
168 LOG.info('Dell EMC driver will unmanage share server: %s out of '
169 'OpenStack.', server_details.get('server_id'))
171 def unmanage(self, share):
172 LOG.info('Dell EMC driver will unmanage share: %s out of '
173 'OpenStack.', share.get('id'))
175 def unmanage_with_server(self, share, share_server=None):
176 LOG.info('Dell EMC driver will unmanage share: %s out of '
177 'OpenStack.', share.get('id'))
179 def unmanage_snapshot(self, snapshot):
180 LOG.info('Dell EMC driver will unmanage snapshot: %s out of '
181 'OpenStack.', snapshot.get('id'))
183 def unmanage_snapshot_with_server(self, snapshot, share_server=None):
184 LOG.info('Dell EMC driver will unmanage snapshot: %s out of '
185 'OpenStack.', snapshot.get('id'))
187 def create_share(self, context, share, share_server=None):
188 """Is called to create share."""
189 location = self.plugin.create_share(context, share, share_server)
191 return location
193 def create_share_from_snapshot(self, context, share, snapshot,
194 share_server=None, parent_share=None):
195 """Is called to create share from snapshot."""
196 location = self.plugin.create_share_from_snapshot(
197 context, share, snapshot, share_server)
199 return location
201 def extend_share(self, share, new_size, share_server=None):
202 """Is called to extend share."""
203 self.plugin.extend_share(share, new_size, share_server)
205 def shrink_share(self, share, new_size, share_server=None):
206 """Is called to shrink share."""
207 if self.shrink_share_support:
208 self.plugin.shrink_share(share, new_size, share_server)
209 else:
210 raise NotImplementedError()
212 def create_snapshot(self, context, snapshot, share_server=None):
213 """Is called to create snapshot."""
214 return self.plugin.create_snapshot(context, snapshot, share_server)
216 def delete_share(self, context, share, share_server=None):
217 """Is called to remove share."""
218 self.plugin.delete_share(context, share, share_server)
220 def delete_snapshot(self, context, snapshot, share_server=None):
221 """Is called to remove snapshot."""
222 self.plugin.delete_snapshot(context, snapshot, share_server)
224 def ensure_share(self, context, share, share_server=None):
225 """Invoked to sure that share is exported."""
226 self.plugin.ensure_share(context, share, share_server)
228 def allow_access(self, context, share, access, share_server=None):
229 """Allow access to the share."""
230 self.plugin.allow_access(context, share, access, share_server)
232 def deny_access(self, context, share, access, share_server=None):
233 """Deny access to the share."""
234 self.plugin.deny_access(context, share, access, share_server)
236 def update_access(self, context, share, access_rules, add_rules,
237 delete_rules, update_rules, share_server=None):
238 """Update access to the share."""
239 return self.plugin.update_access(context, share, access_rules,
240 add_rules, delete_rules, share_server)
242 def check_for_setup_error(self):
243 """Check for setup error."""
244 self.plugin.check_for_setup_error()
246 def do_setup(self, context):
247 """Any initialization the share driver does while starting."""
248 self.plugin.connect(self, context)
250 def _update_share_stats(self):
251 """Retrieve stats info from share."""
253 backend_name = self.configuration.safe_get(
254 'share_backend_name') or "EMC_NAS_Storage"
255 data = dict(
256 share_backend_name=backend_name,
257 vendor_name='Dell EMC',
258 storage_protocol='NFS_CIFS',
259 snapshot_support=True,
260 create_share_from_snapshot_support=True,
261 revert_to_snapshot_support=self.revert_to_snap_support)
262 self.plugin.update_share_stats(data)
263 super(EMCShareDriver, self)._update_share_stats(data)
264 LOG.info(f"Updated share stats: {self._stats}")
266 def get_network_allocations_number(self):
267 """Returns number of network allocations for creating VIFs."""
268 return self.plugin.get_network_allocations_number()
270 def _setup_server(self, network_info, metadata=None):
271 """Set up and configures share server with given network parameters."""
272 # NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
273 network_info = network_info[0]
275 return self.plugin.setup_server(network_info, metadata)
277 def _teardown_server(self, server_details, security_services=None):
278 """Teardown share server."""
279 return self.plugin.teardown_server(server_details, security_services)
281 def get_configured_ip_versions(self):
282 if self.ipv6_implemented:
283 return [4, 6]
284 else:
285 return [4]
287 def revert_to_snapshot(self, context, snapshot, share_access_rules,
288 snapshot_access_rules, share_server=None):
289 if self.revert_to_snap_support:
290 return self.plugin.revert_to_snapshot(context, snapshot,
291 share_access_rules,
292 snapshot_access_rules,
293 share_server)
294 else:
295 raise NotImplementedError()
297 def get_default_filter_function(self):
298 if hasattr(self.plugin, 'get_default_filter_function'):
299 return self.plugin.get_default_filter_function()
300 return None
302 def get_backend_info(self, context):
303 """Get driver and array configuration parameters."""
304 if hasattr(self.plugin, 'get_backend_info'): 304 ↛ 306line 304 didn't jump to line 306 because the condition on line 304 was always true
305 return self.plugin.get_backend_info(context)
306 raise NotImplementedError()
308 def ensure_shares(self, context, shares):
309 """Invoked to ensure that shares are exported."""
310 if hasattr(self.plugin, 'ensure_shares'): 310 ↛ 312line 310 didn't jump to line 312 because the condition on line 310 was always true
311 return self.plugin.ensure_shares(context, shares)
312 raise NotImplementedError()
314 def snapshot_update_access(self, context, snapshot, access_rules,
315 add_rules, delete_rules, share_server=None):
316 """Update snapshot access"""
317 if hasattr(self.plugin, 'snapshot_update_access'): 317 ↛ 326line 317 didn't jump to line 326 because the condition on line 317 was always true
318 return self.plugin.snapshot_update_access(
319 context=context,
320 snapshot=snapshot,
321 access_rules=access_rules,
322 add_rules=add_rules,
323 delete_rules=delete_rules,
324 share_server=share_server,
325 )
326 raise NotImplementedError()