Coverage for manila/share/drivers/infortrend/driver.py: 87%
67 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 Infortrend Technology, 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.
16from oslo_config import cfg
17from oslo_log import log
19from manila import exception
20from manila.i18n import _
21from manila.share import driver
22from manila.share.drivers.infortrend import infortrend_nas
24LOG = log.getLogger(__name__)
26infortrend_nas_opts = [
27 cfg.HostAddressOpt('infortrend_nas_ip',
28 required=True,
29 help='Infortrend NAS IP for management.'),
30 cfg.StrOpt('infortrend_nas_user',
31 default='manila',
32 help='User for the Infortrend NAS server.'),
33 cfg.StrOpt('infortrend_nas_password',
34 secret=True,
35 help='Password for the Infortrend NAS server. '
36 'This is not necessary '
37 'if infortrend_nas_ssh_key is set.'),
38 cfg.StrOpt('infortrend_nas_ssh_key',
39 help='SSH key for the Infortrend NAS server. '
40 'This is not necessary '
41 'if infortrend_nas_password is set.'),
42 cfg.ListOpt('infortrend_share_pools',
43 required=True,
44 help='Comma separated list of Infortrend NAS pools.'),
45 cfg.ListOpt('infortrend_share_channels',
46 required=True,
47 help='Comma separated list of Infortrend channels.'),
48 cfg.IntOpt('infortrend_ssh_timeout',
49 default=30,
50 help='SSH timeout in seconds.'),
51]
53CONF = cfg.CONF
54CONF.register_opts(infortrend_nas_opts)
57class InfortrendNASDriver(driver.ShareDriver):
59 """Infortrend Share Driver for GS/GSe Family using NASCLI.
61 Version history:
62 1.0.0 - Initial driver
63 """
65 VERSION = "1.0.0"
66 PROTOCOL = "NFS_CIFS"
68 def __init__(self, *args, **kwargs):
69 super(InfortrendNASDriver, self).__init__(False, *args, **kwargs)
70 self.configuration.append_config_values(infortrend_nas_opts)
72 nas_ip = self.configuration.safe_get('infortrend_nas_ip')
73 username = self.configuration.safe_get('infortrend_nas_user')
74 password = self.configuration.safe_get('infortrend_nas_password')
75 ssh_key = self.configuration.safe_get('infortrend_nas_ssh_key')
76 timeout = self.configuration.safe_get('infortrend_ssh_timeout')
77 self.backend_name = self.configuration.safe_get('share_backend_name')
79 if not (password or ssh_key):
80 msg = _('Either infortrend_nas_password or infortrend_nas_ssh_key '
81 'should be set.')
82 raise exception.InvalidParameterValue(err=msg)
84 pool_dict = self._init_pool_dict()
85 channel_dict = self._init_channel_dict()
86 self.ift_nas = infortrend_nas.InfortrendNAS(nas_ip, username, password,
87 ssh_key, timeout,
88 pool_dict, channel_dict)
90 def _init_pool_dict(self):
91 pools_names = self.configuration.safe_get('infortrend_share_pools')
93 return {el: {} for el in pools_names}
95 def _init_channel_dict(self):
96 channels = self.configuration.safe_get('infortrend_share_channels')
98 return {el: '' for el in channels}
100 def do_setup(self, context):
101 """Any initialization the share driver does while starting."""
102 LOG.debug('Infortrend NAS do_setup start.')
103 self.ift_nas.do_setup()
105 def check_for_setup_error(self):
106 """Check for setup error."""
107 LOG.debug('Infortrend NAS check_for_setup_error start.')
108 self.ift_nas.check_for_setup_error()
110 def _update_share_stats(self):
111 """Retrieve stats info from share group."""
113 LOG.debug('Updating Infortrend backend [%s].', self.backend_name)
115 data = dict(
116 share_backend_name=self.backend_name,
117 vendor_name='Infortrend',
118 driver_version=self.VERSION,
119 storage_protocol=self.PROTOCOL,
120 reserved_percentage=self.configuration.reserved_share_percentage,
121 reserved_snapshot_percentage=(
122 self.configuration.reserved_share_from_snapshot_percentage
123 or self.configuration.reserved_share_percentage),
124 reserved_share_extend_percentage=(
125 self.configuration.reserved_share_extend_percentage
126 or self.configuration.reserved_share_percentage),
127 pools=self.ift_nas.update_pools_stats())
128 LOG.debug('Infortrend pools status: %s', data['pools'])
130 super(InfortrendNASDriver, self)._update_share_stats(data)
132 def update_access(self, context, share, access_rules, add_rules,
133 delete_rules, update_rules, share_server=None):
134 """Update access rules for given share.
136 :param context: Current context
137 :param share: Share model with share data.
138 :param access_rules: All access rules for given share
139 :param add_rules: Empty List or List of access rules which should be
140 added. access_rules already contains these rules.
141 :param delete_rules: Empty List or List of access rules which should be
142 removed. access_rules doesn't contain these rules.
143 :param update_rules: Empty List or List of access rules which should be
144 updated. access_rules already contains these rules.
145 :param share_server: Not used by this driver.
147 :returns: None, or a dictionary of ``access_id``, ``access_key`` as
148 key: value pairs for the rules added, where, ``access_id``
149 is the UUID (string) of the access rule, and ``access_key``
150 is the credential (string) of the entity granted access.
151 During recovery after error, the returned dictionary must
152 contain ``access_id``, ``access_key`` for all the rules that
153 the driver is ordered to resync, i.e. rules in the
154 ``access_rules`` parameter.
155 """
157 return self.ift_nas.update_access(share, access_rules, add_rules,
158 delete_rules, share_server)
160 def create_share(self, context, share, share_server=None):
161 """Create a share."""
163 LOG.debug('Creating share: %s.', share['id'])
165 return self.ift_nas.create_share(share, share_server)
167 def delete_share(self, context, share, share_server=None):
168 """Remove a share."""
170 LOG.debug('Deleting share: %s.', share['id'])
172 return self.ift_nas.delete_share(share, share_server)
174 def get_pool(self, share):
175 """Return pool name where the share resides on.
177 :param share: The share hosted by the driver.
178 """
179 return self.ift_nas.get_pool(share)
181 def ensure_share(self, context, share, share_server=None):
182 """Invoked to ensure that share is exported.
184 Driver can use this method to update the list of export locations of
185 the share if it changes. To do that, you should return list with
186 export locations.
188 :return None or list with export locations
189 """
190 return self.ift_nas.ensure_share(share, share_server)
192 def manage_existing(self, share, driver_options):
193 """Brings an existing share under Manila management.
195 If the provided share is not valid, then raise a
196 ManageInvalidShare exception, specifying a reason for the failure.
198 If the provided share is not in a state that can be managed, such as
199 being replicated on the backend, the driver *MUST* raise
200 ManageInvalidShare exception with an appropriate message.
202 The share has a share_type, and the driver can inspect that and
203 compare against the properties of the referenced backend share.
204 If they are incompatible, raise a
205 ManageExistingShareTypeMismatch, specifying a reason for the failure.
207 :param share: Share model
208 :param driver_options: Driver-specific options provided by admin.
209 :return: share_update dictionary with required key 'size',
210 which should contain size of the share.
211 """
212 LOG.debug(
213 'Manage existing for share: %(share)s,', {
214 'share': share['share_id'],
215 })
216 return self.ift_nas.manage_existing(share, driver_options)
218 def unmanage(self, share):
219 """Removes the specified share from Manila management.
221 Does not delete the underlying backend share.
223 For most drivers, this will not need to do anything. However, some
224 drivers might use this call as an opportunity to clean up any
225 Manila-specific configuration that they have associated with the
226 backend share.
228 If provided share cannot be unmanaged, then raise an
229 UnmanageInvalidShare exception, specifying a reason for the failure.
231 This method is invoked when the share is being unmanaged with
232 a share type that has ``driver_handles_share_servers``
233 extra-spec set to False.
234 """
235 LOG.debug(
236 'Unmanage share: %(share)s', {
237 'share': share['share_id'],
238 })
239 return self.ift_nas.unmanage(share)
241 def extend_share(self, share, new_size, share_server=None):
242 """Extends size of existing share.
244 :param share: Share model
245 :param new_size: New size of share (new_size > share['size'])
246 :param share_server: Optional -- Share server model
247 """
248 return self.ift_nas.extend_share(share, new_size, share_server)
250 def shrink_share(self, share, new_size, share_server=None):
251 """Shrinks size of existing share.
253 If consumed space on share larger than new_size driver should raise
254 ShareShrinkingPossibleDataLoss exception:
255 raise ShareShrinkingPossibleDataLoss(share_id=share['id'])
257 :param share: Share model
258 :param new_size: New size of share (new_size < share['size'])
259 :param share_server: Optional -- Share server model
261 :raises ShareShrinkingPossibleDataLoss, NotImplementedError
262 """
263 return self.ift_nas.shrink_share(share, new_size, share_server)