Coverage for manila/share/drivers/infinidat/infinibox.py: 100%

314 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright 2022 Infinidat Ltd. 

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. 

15""" 

16INFINIDAT InfiniBox Share Driver 

17""" 

18 

19import functools 

20 

21import ipaddress 

22from oslo_config import cfg 

23from oslo_log import log as logging 

24from oslo_utils import units 

25import requests 

26 

27from manila.common import constants 

28from manila import exception 

29from manila.i18n import _ 

30from manila.share import driver 

31from manila.share import utils 

32from manila import version 

33 

34try: 

35 import capacity 

36except ImportError: 

37 capacity = None 

38 

39try: 

40 import infinisdk 

41except ImportError: 

42 infinisdk = None 

43 

44 

45LOG = logging.getLogger(__name__) 

46 

47infinidat_connection_opts = [ 

48 cfg.HostAddressOpt('infinibox_hostname', 

49 help='The name (or IP address) for the INFINIDAT ' 

50 'Infinibox storage system.'), 

51 cfg.BoolOpt('infinidat_use_ssl', 

52 help='Use SSL to connect to the INFINIDAT Infinibox storage ' 

53 'system.', 

54 default=False), 

55 cfg.BoolOpt('infinidat_suppress_ssl_warnings', 

56 help='Suppress requests library SSL certificate warnings.', 

57 default=False), ] 

58 

59infinidat_auth_opts = [ 

60 cfg.StrOpt('infinibox_login', 

61 help=('Administrative user account name used to access the ' 

62 'INFINIDAT Infinibox storage system.')), 

63 cfg.StrOpt('infinibox_password', 

64 help=('Password for the administrative user account ' 

65 'specified in the infinibox_login option.'), 

66 secret=True), ] 

67 

68infinidat_general_opts = [ 

69 cfg.StrOpt('infinidat_pool_name', 

70 help='Name of the pool from which volumes are allocated.'), 

71 cfg.StrOpt('infinidat_nas_network_space_name', 

72 help='Name of the NAS network space on the INFINIDAT ' 

73 'InfiniBox.'), 

74 cfg.BoolOpt('infinidat_thin_provision', help='Use thin provisioning.', 

75 default=True), 

76 cfg.BoolOpt('infinidat_snapdir_accessible', 

77 help=('Controls access to the .snapshot directory. ' 

78 'By default, each share allows access to its own ' 

79 '.snapshot directory, which contains files and ' 

80 'directories of each snapshot taken. To restrict ' 

81 'access to the .snapshot directory, this option ' 

82 'should be set to False.'), 

83 default=True), 

84 cfg.BoolOpt('infinidat_snapdir_visible', 

85 help=('Controls visibility of the .snapshot directory. ' 

86 'By default, each share contains the .snapshot ' 

87 'directory, which is hidden on the client side. ' 

88 'To make the .snapshot directory visible, this ' 

89 'option should be set to True.'), 

90 default=False), ] 

91 

92CONF = cfg.CONF 

93CONF.register_opts(infinidat_connection_opts) 

94CONF.register_opts(infinidat_auth_opts) 

95CONF.register_opts(infinidat_general_opts) 

96 

97_MANILA_TO_INFINIDAT_ACCESS_LEVEL = { 

98 constants.ACCESS_LEVEL_RW: 'RW', 

99 constants.ACCESS_LEVEL_RO: 'RO', 

100} 

101 

102# Max retries for the REST API client in case of a failure: 

103_API_MAX_RETRIES = 5 

104# Identifier used as the REST API User-Agent string: 

105_INFINIDAT_MANILA_IDENTIFIER = ( 

106 "manila/%s" % version.version_info.release_string()) 

107 

108 

109def infinisdk_to_manila_exceptions(func): 

110 @functools.wraps(func) 

111 def wrapper(*args, **kwargs): 

112 try: 

113 return func(*args, **kwargs) 

114 except infinisdk.core.exceptions.InfiniSDKException as ex: 

115 # string formatting of 'ex' includes http code and url 

116 msg = _('Caught exception from infinisdk: %s') % ex 

117 LOG.exception(msg) 

118 raise exception.ShareBackendException(msg=msg) 

119 return wrapper 

120 

121 

122class InfiniboxShareDriver(driver.ShareDriver): 

123 """INFINIDAT InfiniBox Share driver. 

124 

125 Version history: 

126 1.0 - initial release 

127 1.1 - added support for TLS/SSL communication 

128 1.2 - fixed host assisted migration 

129 """ 

130 

131 VERSION = '1.2' # driver version 

132 

133 def __init__(self, *args, **kwargs): 

134 super(InfiniboxShareDriver, self).__init__(False, *args, **kwargs) 

135 self.configuration.append_config_values(infinidat_connection_opts) 

136 self.configuration.append_config_values(infinidat_auth_opts) 

137 self.configuration.append_config_values(infinidat_general_opts) 

138 

139 def _setup_and_get_system_object(self, management_address, auth, use_ssl): 

140 system = infinisdk.InfiniBox(management_address, auth=auth, 

141 use_ssl=use_ssl) 

142 system.api.add_auto_retry( 

143 lambda e: isinstance( 

144 e, infinisdk.core.exceptions.APITransportFailure) and 

145 "Interrupted system call" in e.error_desc, _API_MAX_RETRIES) 

146 system.api.set_source_identifier(_INFINIDAT_MANILA_IDENTIFIER) 

147 system.login() 

148 return system 

149 

150 def do_setup(self, context): 

151 """Driver initialization""" 

152 if capacity is None: 

153 msg = _("Missing 'capacity' python module, ensure the library" 

154 " is installed and available.") 

155 raise exception.ManilaException(message=msg) 

156 if infinisdk is None: 

157 msg = _("Missing 'infinisdk' python module, ensure the library" 

158 " is installed and available.") 

159 raise exception.ManilaException(message=msg) 

160 

161 if self.configuration.safe_get('infinidat_suppress_ssl_warnings'): 

162 LOG.warning('Suppressing requests library SSL Warnings') 

163 rpu = requests.packages.urllib3 # pylint: disable=no-member 

164 rpu.disable_warnings(rpu.exceptions.InsecureRequestWarning) 

165 rpu.disable_warnings(rpu.exceptions.InsecurePlatformWarning) 

166 

167 use_ssl = self.configuration.safe_get('infinidat_use_ssl') 

168 infinibox_login = self._safe_get_from_config_or_fail('infinibox_login') 

169 infinibox_password = ( 

170 self._safe_get_from_config_or_fail('infinibox_password')) 

171 auth = (infinibox_login, infinibox_password) 

172 

173 management_address = ( 

174 self._safe_get_from_config_or_fail('infinibox_hostname')) 

175 

176 self._pool_name = ( 

177 self._safe_get_from_config_or_fail('infinidat_pool_name')) 

178 

179 self._network_space_name = ( 

180 self._safe_get_from_config_or_fail( 

181 'infinidat_nas_network_space_name')) 

182 

183 self._system = self._setup_and_get_system_object(management_address, 

184 auth, use_ssl) 

185 

186 backend_name = self.configuration.safe_get('share_backend_name') 

187 self._backend_name = backend_name or self.__class__.__name__ 

188 

189 thin_provisioning = self.configuration.infinidat_thin_provision 

190 self._provtype = "THIN" if thin_provisioning else "THICK" 

191 

192 LOG.debug('setup complete') 

193 

194 def _update_share_stats(self): 

195 """Retrieve stats info from share group.""" 

196 (free_capacity_bytes, physical_capacity_bytes, 

197 provisioned_capacity_gb) = self._get_available_capacity() 

198 

199 max_over_subscription_ratio = ( 

200 self.configuration.max_over_subscription_ratio) 

201 

202 data = dict( 

203 share_backend_name=self._backend_name, 

204 vendor_name='INFINIDAT', 

205 driver_version=self.VERSION, 

206 storage_protocol='NFS', 

207 total_capacity_gb=float(physical_capacity_bytes) / units.Gi, 

208 free_capacity_gb=float(free_capacity_bytes) / units.Gi, 

209 reserved_percentage=self.configuration.reserved_share_percentage, 

210 reserved_snapshot_percentage=( 

211 self.configuration.reserved_share_from_snapshot_percentage 

212 or self.configuration.reserved_share_percentage), 

213 reserved_share_extend_percentage=( 

214 self.configuration.reserved_share_extend_percentage 

215 or self.configuration.reserved_share_percentage), 

216 thin_provisioning=self.configuration.infinidat_thin_provision, 

217 max_over_subscription_ratio=max_over_subscription_ratio, 

218 provisioned_capacity_gb=provisioned_capacity_gb, 

219 snapshot_support=True, 

220 create_share_from_snapshot_support=True, 

221 mount_snapshot_support=True, 

222 revert_to_snapshot_support=True) 

223 

224 super(InfiniboxShareDriver, self)._update_share_stats(data) 

225 

226 def _get_available_capacity(self): 

227 # pylint: disable=no-member 

228 pool = self._get_infinidat_pool() 

229 free_capacity_bytes = (pool.get_free_physical_capacity() / 

230 capacity.byte) 

231 physical_capacity_bytes = (pool.get_physical_capacity() / 

232 capacity.byte) 

233 provisioned_capacity_gb = ( 

234 (pool.get_virtual_capacity() - pool.get_free_virtual_capacity()) / 

235 capacity.GB) 

236 # pylint: enable=no-member 

237 return (free_capacity_bytes, physical_capacity_bytes, 

238 provisioned_capacity_gb) 

239 

240 def _safe_get_from_config_or_fail(self, config_parameter): 

241 config_value = self.configuration.safe_get(config_parameter) 

242 if not config_value: # None or empty string 

243 reason = (_("%(config_parameter)s configuration parameter " 

244 "must be specified") % 

245 {'config_parameter': config_parameter}) 

246 LOG.error(reason) 

247 raise exception.BadConfigurationException(reason=reason) 

248 return config_value 

249 

250 def _verify_share_protocol(self, share): 

251 if share['share_proto'] != 'NFS': 

252 reason = (_('Unsupported share protocol: %(proto)s.') % 

253 {'proto': share['share_proto']}) 

254 LOG.error(reason) 

255 raise exception.InvalidShare(reason=reason) 

256 

257 def _verify_access_type(self, access): 

258 if access['access_type'] != 'ip': 

259 reason = _('Only "ip" access type allowed for the NFS protocol.') 

260 LOG.error(reason) 

261 raise exception.InvalidShareAccess(reason=reason) 

262 return True 

263 

264 def _make_share_name(self, manila_share): 

265 return 'openstack-shr-%s' % manila_share['id'] 

266 

267 def _make_snapshot_name(self, manila_snapshot): 

268 return 'openstack-snap-%s' % manila_snapshot['id'] 

269 

270 def _set_manila_object_metadata(self, infinidat_object, manila_object): 

271 data = {"system": "openstack", 

272 "openstack_version": version.version_info.release_string(), 

273 "manila_id": manila_object['id'], 

274 "manila_name": manila_object['name'], 

275 "host.created_by": _INFINIDAT_MANILA_IDENTIFIER} 

276 infinidat_object.set_metadata_from_dict(data) 

277 

278 @infinisdk_to_manila_exceptions 

279 def _get_infinidat_pool(self): 

280 pool = self._system.pools.safe_get(name=self._pool_name) 

281 if pool is None: 

282 msg = _('Pool "%s" not found') % self._pool_name 

283 LOG.error(msg) 

284 raise exception.ShareBackendException(msg=msg) 

285 return pool 

286 

287 @infinisdk_to_manila_exceptions 

288 def _get_infinidat_nas_network_space_ips(self): 

289 network_space = self._system.network_spaces.safe_get( 

290 name=self._network_space_name) 

291 if network_space is None: 

292 msg = _('INFINIDAT InfiniBox NAS network space "%s" ' 

293 'not found') % self._network_space_name 

294 LOG.error(msg) 

295 raise exception.ShareBackendException(msg=msg) 

296 network_space_ips = network_space.get_ips() 

297 if not network_space_ips: 

298 msg = _('INFINIDAT InfiniBox NAS network space "%s" has no IP ' 

299 'addresses defined') % self._network_space_name 

300 LOG.error(msg) 

301 raise exception.ShareBackendException(msg=msg) 

302 ip_addresses = ( 

303 [ip_munch.ip_address for ip_munch in network_space_ips if 

304 ip_munch.enabled]) 

305 if not ip_addresses: 

306 msg = _('INFINIDAT InfiniBox NAS network space "%s" has no ' 

307 'enabled IP addresses') % self._network_space_name 

308 LOG.error(msg) 

309 raise exception.ShareBackendException(msg=msg) 

310 return ip_addresses 

311 

312 def _get_full_nfs_export_paths(self, export_path): 

313 network_space_ips = self._get_infinidat_nas_network_space_ips() 

314 return ['{network_space_ip}:{export_path}'.format( 

315 network_space_ip=network_space_ip, 

316 export_path=export_path) for network_space_ip in network_space_ips] 

317 

318 @infinisdk_to_manila_exceptions 

319 def _get_infinidat_filesystem_by_name(self, name): 

320 filesystem = self._system.filesystems.safe_get(name=name) 

321 if filesystem is None: 

322 msg = (_('Filesystem not found on the Infinibox by its name: %s') % 

323 name) 

324 LOG.error(msg) 

325 raise exception.ShareResourceNotFound(share_id=name) 

326 return filesystem 

327 

328 def _get_infinidat_filesystem(self, manila_share): 

329 filesystem_name = self._make_share_name(manila_share) 

330 return self._get_infinidat_filesystem_by_name(filesystem_name) 

331 

332 def _get_infinidat_snapshot_by_name(self, name): 

333 snapshot = self._system.filesystems.safe_get(name=name) 

334 if snapshot is None: 

335 msg = (_('Snapshot not found on the Infinibox by its name: %s') % 

336 name) 

337 LOG.error(msg) 

338 raise exception.ShareSnapshotNotFound(snapshot_id=name) 

339 return snapshot 

340 

341 def _get_infinidat_snapshot(self, manila_snapshot): 

342 snapshot_name = self._make_snapshot_name(manila_snapshot) 

343 return self._get_infinidat_snapshot_by_name(snapshot_name) 

344 

345 def _get_infinidat_dataset(self, manila_object, is_snapshot): 

346 return (self._get_infinidat_snapshot(manila_object) if is_snapshot 

347 else self._get_infinidat_filesystem(manila_object)) 

348 

349 @infinisdk_to_manila_exceptions 

350 def _get_export(self, infinidat_filesystem): 

351 infinidat_exports = infinidat_filesystem.get_exports() 

352 if len(infinidat_exports) == 0: 

353 msg = _("Could not find share export") 

354 raise exception.ShareBackendException(msg=msg) 

355 elif len(infinidat_exports) > 1: 

356 msg = _("INFINIDAT filesystem has more than one active export; " 

357 "possibly not a Manila share") 

358 LOG.error(msg) 

359 raise exception.ShareBackendException(msg=msg) 

360 return infinidat_exports[0] 

361 

362 def _get_infinidat_access_level(self, access): 

363 """Translates between Manila access levels to INFINIDAT API ones""" 

364 access_level = access['access_level'] 

365 try: 

366 return _MANILA_TO_INFINIDAT_ACCESS_LEVEL[access_level] 

367 except KeyError: 

368 raise exception.InvalidShareAccessLevel(level=access_level) 

369 

370 def _get_ip_address_range(self, ip_address): 

371 """Parse single IP address or subnet into a range. 

372 

373 If the IP address string is in subnet mask format, returns a 

374 <start ip>-<end-ip> string. If the IP address contains a single IP 

375 address, returns only that IP address. 

376 """ 

377 

378 ip_address = str(ip_address) 

379 

380 # try treating the ip_address parameter as a range of IP addresses: 

381 ip_network = ipaddress.ip_network(ip_address, strict=False) 

382 ip_network_hosts = list(ip_network.hosts()) 

383 if len(ip_network_hosts) < 2: # /32, single IP address 

384 return ip_address.split('/')[0] 

385 return "{}-{}".format(ip_network_hosts[0], ip_network_hosts[-1]) 

386 

387 @infinisdk_to_manila_exceptions 

388 def _create_filesystem_export(self, infinidat_filesystem): 

389 snapdir_visible = self.configuration.infinidat_snapdir_visible 

390 infinidat_export = infinidat_filesystem.add_export( 

391 permissions=[], snapdir_visible=snapdir_visible) 

392 return self._make_export_locations(infinidat_export) 

393 

394 @infinisdk_to_manila_exceptions 

395 def _ensure_filesystem_export(self, infinidat_filesystem): 

396 try: 

397 infinidat_export = self._get_export(infinidat_filesystem) 

398 except exception.ShareBackendException: 

399 return self._create_filesystem_export(infinidat_filesystem) 

400 actual = infinidat_export.is_snapdir_visible() 

401 expected = self.configuration.infinidat_snapdir_visible 

402 if actual is not expected: 

403 LOG.debug('Update snapdir_visible for %s: %s -> %s', 

404 infinidat_filesystem.get_name(), actual, expected) 

405 infinidat_export.update_snapdir_visible(expected) 

406 return self._make_export_locations(infinidat_export) 

407 

408 @infinisdk_to_manila_exceptions 

409 def _make_export_locations(self, infinidat_export): 

410 export_paths = self._get_full_nfs_export_paths( 

411 infinidat_export.get_export_path()) 

412 export_locations = [{ 

413 'path': export_path, 

414 'is_admin_only': False, 

415 'metadata': {}, 

416 } for export_path in export_paths] 

417 return export_locations 

418 

419 @infinisdk_to_manila_exceptions 

420 def _delete_share(self, share, is_snapshot): 

421 if is_snapshot: 

422 dataset_name = self._make_snapshot_name(share) 

423 else: 

424 dataset_name = self._make_share_name(share) 

425 try: 

426 infinidat_filesystem = ( 

427 self._get_infinidat_filesystem_by_name(dataset_name)) 

428 except exception.ShareResourceNotFound: 

429 message = ("share %(share)s not found on Infinibox, skipping " 

430 "delete") 

431 LOG.warning(message, {"share": share}) 

432 return # filesystem not found 

433 try: 

434 infinidat_export = self._get_export(infinidat_filesystem) 

435 infinidat_export.safe_delete() 

436 except exception.ShareBackendException: 

437 # it is possible that the export has been deleted 

438 pass 

439 infinidat_filesystem.safe_delete() 

440 

441 @infinisdk_to_manila_exceptions 

442 def _extend_share(self, infinidat_filesystem, share, new_size): 

443 # pylint: disable=no-member 

444 new_size_capacity_units = new_size * capacity.GiB 

445 # pylint: enable=no-member 

446 old_size = infinidat_filesystem.get_size() 

447 infinidat_filesystem.resize(new_size_capacity_units - old_size) 

448 

449 @infinisdk_to_manila_exceptions 

450 def _update_access(self, manila_object, access_rules, is_snapshot): 

451 infinidat_filesystem = self._get_infinidat_dataset( 

452 manila_object, is_snapshot=is_snapshot) 

453 infinidat_export = self._get_export(infinidat_filesystem) 

454 permissions = [ 

455 {'access': self._get_infinidat_access_level(access_rule), 

456 'client': self._get_ip_address_range(access_rule['access_to']), 

457 'no_root_squash': True} for access_rule in access_rules if 

458 self._verify_access_type(access_rule)] 

459 infinidat_export.update_permissions(permissions) 

460 

461 @infinisdk_to_manila_exceptions 

462 def create_share(self, context, share, share_server=None): 

463 self._verify_share_protocol(share) 

464 

465 pool = self._get_infinidat_pool() 

466 size = share['size'] * capacity.GiB # pylint: disable=no-member 

467 name = self._make_share_name(share) 

468 snapdir_accessible = self.configuration.infinidat_snapdir_accessible 

469 infinidat_filesystem = self._system.filesystems.create( 

470 pool=pool, name=name, size=size, provtype=self._provtype, 

471 snapdir_accessible=snapdir_accessible) 

472 self._set_manila_object_metadata(infinidat_filesystem, share) 

473 return self._create_filesystem_export(infinidat_filesystem) 

474 

475 @infinisdk_to_manila_exceptions 

476 def create_share_from_snapshot(self, context, share, snapshot, 

477 share_server=None, parent_share=None): 

478 name = self._make_share_name(share) 

479 infinidat_snapshot = self._get_infinidat_snapshot(snapshot) 

480 snapdir_accessible = self.configuration.infinidat_snapdir_accessible 

481 infinidat_new_share = infinidat_snapshot.create_snapshot( 

482 name=name, write_protected=False, 

483 snapdir_accessible=snapdir_accessible) 

484 self._extend_share(infinidat_new_share, share, share['size']) 

485 return self._create_filesystem_export(infinidat_new_share) 

486 

487 @infinisdk_to_manila_exceptions 

488 def create_snapshot(self, context, snapshot, share_server=None): 

489 """Creates a snapshot.""" 

490 share = snapshot['share'] 

491 infinidat_filesystem = self._get_infinidat_filesystem(share) 

492 name = self._make_snapshot_name(snapshot) 

493 snapdir_accessible = self.configuration.infinidat_snapdir_accessible 

494 infinidat_snapshot = infinidat_filesystem.create_snapshot( 

495 name=name, snapdir_accessible=snapdir_accessible) 

496 # snapshot is created in the same size as the original share, so no 

497 # extending is needed 

498 self._set_manila_object_metadata(infinidat_snapshot, snapshot) 

499 return {'export_locations': 

500 self._create_filesystem_export(infinidat_snapshot)} 

501 

502 def delete_share(self, context, share, share_server=None): 

503 try: 

504 self._verify_share_protocol(share) 

505 except exception.InvalidShare: 

506 # cleanup shouldn't fail on wrong protocol or missing share: 

507 message = ("failed to delete share %(share)s; unsupported share " 

508 "protocol %(share_proto)s, only NFS is supported") 

509 LOG.warning(message, {"share": share, 

510 "share_proto": share['share_proto']}) 

511 return 

512 self._delete_share(share, is_snapshot=False) 

513 

514 def delete_snapshot(self, context, snapshot, share_server=None): 

515 self._delete_share(snapshot, is_snapshot=True) 

516 

517 def ensure_share(self, context, share, share_server=None): 

518 """Ensure that share is properly configured and exported.""" 

519 # will raise ShareResourceNotFound if the share was not found: 

520 infinidat_filesystem = self._get_infinidat_filesystem(share) 

521 actual = infinidat_filesystem.is_snapdir_accessible() 

522 expected = self.configuration.infinidat_snapdir_accessible 

523 if actual is not expected: 

524 LOG.debug('Update snapdir_accessible for %s: %s -> %s', 

525 infinidat_filesystem.get_name(), actual, expected) 

526 infinidat_filesystem.update_field('snapdir_accessible', expected) 

527 return self._ensure_filesystem_export(infinidat_filesystem) 

528 

529 def ensure_shares(self, context, shares): 

530 """Invoked to ensure that shares are exported.""" 

531 updates = {} 

532 for share in shares: 

533 updates[share['id']] = { 

534 'export_locations': self.ensure_share(context, share)} 

535 return updates 

536 

537 def get_backend_info(self, context): 

538 snapdir_accessible = self.configuration.infinidat_snapdir_accessible 

539 snapdir_visible = self.configuration.infinidat_snapdir_visible 

540 return { 

541 'snapdir_accessible': snapdir_accessible, 

542 'snapdir_visible': snapdir_visible 

543 } 

544 

545 def update_access(self, context, share, access_rules, add_rules, 

546 delete_rules, update_rules, share_server=None): 

547 # As the Infinibox API can bulk update export access rules, we will try 

548 # to use the access_rules list 

549 self._verify_share_protocol(share) 

550 self._update_access(share, access_rules, is_snapshot=False) 

551 

552 def get_network_allocations_number(self): 

553 return 0 

554 

555 @infinisdk_to_manila_exceptions 

556 def revert_to_snapshot(self, context, snapshot, share_access_rules, 

557 snapshot_access_rules, share_server=None): 

558 infinidat_snapshot = self._get_infinidat_snapshot(snapshot) 

559 infinidat_parent_share = self._get_infinidat_filesystem( 

560 snapshot['share']) 

561 infinidat_parent_share.restore(infinidat_snapshot) 

562 

563 def extend_share(self, share, new_size, share_server=None): 

564 infinidat_filesystem = self._get_infinidat_filesystem(share) 

565 self._extend_share(infinidat_filesystem, share, new_size) 

566 

567 def snapshot_update_access(self, context, snapshot, access_rules, 

568 add_rules, delete_rules, share_server=None): 

569 # snapshots are to be mounted in read-only mode, see: 

570 # "Add mountable snapshots" on openstack specs. 

571 access_rules, _, _ = utils.change_rules_to_readonly( 

572 access_rules, [], []) 

573 try: 

574 self._update_access(snapshot, access_rules, is_snapshot=True) 

575 except exception.InvalidShareAccess as e: 

576 raise exception.InvalidSnapshotAccess(e)