Coverage for manila/share/driver.py: 86%

468 statements  

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

1# Copyright 2012 NetApp 

2# Copyright 2015 Mirantis inc. 

3# All Rights Reserved. 

4# 

5# Licensed under the Apache License, Version 2.0 (the "License"); you may 

6# not use this file except in compliance with the License. You may obtain 

7# a copy of the License at 

8# 

9# http://www.apache.org/licenses/LICENSE-2.0 

10# 

11# Unless required by applicable law or agreed to in writing, software 

12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

14# License for the specific language governing permissions and limitations 

15# under the License. 

16""" 

17Drivers for shares. 

18 

19""" 

20 

21import time 

22 

23from oslo_config import cfg 

24from oslo_config import types 

25from oslo_log import log 

26 

27from manila.common import constants 

28from manila import exception 

29from manila.i18n import _ 

30from manila import network 

31from manila import utils 

32 

33LOG = log.getLogger(__name__) 

34 

35share_opts = [ 

36 # NOTE(rushiagr): Reasonable to define this option at only one place. 

37 cfg.IntOpt( 

38 'num_shell_tries', 

39 default=3, 

40 help='Number of times to attempt to run flakey shell commands.'), 

41 cfg.IntOpt( 

42 'reserved_share_percentage', 

43 default=0, 

44 help="The percentage of backend capacity reserved. Used for shares " 

45 "which are not created from the snapshot."), 

46 cfg.IntOpt( 

47 'reserved_share_from_snapshot_percentage', 

48 default=0, 

49 help="The percentage of backend capacity reserved. Used for shares " 

50 "created from the snapshot. On some platforms, shares can only " 

51 "be created from the snapshot on the host where snapshot was " 

52 "taken, so we can set a lower value in this option compared to " 

53 "reserved_share_percentage, and allow to create shares from the " 

54 "snapshot on the same host up to a higher threshold."), 

55 cfg.IntOpt( 

56 'reserved_share_extend_percentage', 

57 default=0, 

58 help="The percentage of backend capacity reserved for share extend " 

59 "operation. When existing limit of 'reserved_share_percentage' " 

60 "is hit, we do not want user to create a new share but existing " 

61 "shares can be extended based on value of this parameter."), 

62 cfg.StrOpt( 

63 'share_backend_name', 

64 help='The backend name for a given driver implementation.'), 

65 cfg.StrOpt( 

66 'network_config_group', 

67 help="Name of the configuration group in the Manila conf file " 

68 "to look for network config options." 

69 "If not set, the share backend's config group will be used." 

70 "If an option is not found within provided group, then " 

71 "'DEFAULT' group will be used for search of option."), 

72 cfg.BoolOpt( 

73 'driver_handles_share_servers', 

74 help="There are two possible approaches for share drivers in Manila. " 

75 "First is when share driver is able to handle share-servers and " 

76 "second when not. Drivers can support either both or only one " 

77 "of these approaches. So, set this opt to True if share driver " 

78 "is able to handle share servers and it is desired mode else set " 

79 "False. It is set to None by default to make this choice " 

80 "intentional."), 

81 cfg.FloatOpt( 

82 'max_over_subscription_ratio', 

83 default=20.0, 

84 min=1.0, 

85 help='Float representation of the over subscription ratio ' 

86 'when thin provisioning is involved. Default ratio is ' 

87 '20.0, meaning provisioned capacity can be 20 times ' 

88 'the total physical capacity. If the ratio is 10.5, it ' 

89 'means provisioned capacity can be 10.5 times the ' 

90 'total physical capacity. A ratio of 1.0 means ' 

91 'provisioned capacity cannot exceed the total physical ' 

92 'capacity. A ratio lower than 1.0 is invalid.'), 

93 cfg.ListOpt( 

94 'migration_ignore_files', 

95 default=['lost+found'], 

96 help="List of files and folders to be ignored when migrating shares. " 

97 "Items should be names (not including any path)."), 

98 cfg.StrOpt( 

99 'share_mount_template', 

100 default='mount -vt %(proto)s %(options)s %(export)s %(path)s', 

101 help="The template for mounting shares for this backend. Must specify " 

102 "the executable with all necessary parameters for the protocol " 

103 "supported. 'proto' template element may not be required if " 

104 "included in the command. 'export' and 'path' template elements " 

105 "are required. It is advisable to separate different commands " 

106 "per backend."), 

107 cfg.StrOpt( 

108 'share_unmount_template', 

109 default='umount -v %(path)s', 

110 help="The template for unmounting shares for this backend. Must " 

111 "specify the executable with all necessary parameters for the " 

112 "protocol supported. 'path' template element is required. It is " 

113 "advisable to separate different commands per backend."), 

114 cfg.Opt( 

115 'protocol_access_mapping', 

116 type=types.Dict(types.List(types.String(), bounds=True)), 

117 default={ 

118 'ip': ['nfs'], 

119 'user': ['cifs'], 

120 }, 

121 help="Protocol access mapping for this backend. Should be a " 

122 "dictionary comprised of " 

123 "{'access_type1': ['share_proto1', 'share_proto2']," 

124 " 'access_type2': ['share_proto2', 'share_proto3']}."), 

125 cfg.StrOpt( 

126 "admin_network_config_group", 

127 help="If share driver requires to setup admin network for share, then " 

128 "define network plugin config options in some separate config " 

129 "group and set its name here. Used only with another " 

130 "option 'driver_handles_share_servers' set to 'True'."), 

131 # Replication option/s 

132 cfg.StrOpt( 

133 "replication_domain", 

134 help="A string specifying the replication domain that the backend " 

135 "belongs to. This option needs to be specified the same in the " 

136 "configuration sections of all backends that support " 

137 "replication between each other. If this option is not " 

138 "specified in the group, it means that replication is not " 

139 "enabled on the backend."), 

140 cfg.StrOpt('backend_availability_zone', 

141 default=None, 

142 help='Availability zone for this share backend. If not set, ' 

143 'the ``storage_availability_zone`` option from the ' 

144 '``[DEFAULT]`` section is used.'), 

145 cfg.StrOpt('filter_function', 

146 help='String representation for an equation that will be ' 

147 'used to filter hosts.'), 

148 cfg.StrOpt('goodness_function', 

149 help='String representation for an equation that will be ' 

150 'used to determine the goodness of a host.'), 

151 cfg.IntOpt('max_shares_per_share_server', 

152 default=-1, 

153 help="Maximum number of share instances created in a share " 

154 "server."), 

155 cfg.IntOpt('max_share_server_size', 

156 default=-1, 

157 help="Maximum sum of gigabytes a share server can have " 

158 "considering all its share instances and snapshots.") 

159] 

160 

161ssh_opts = [ 

162 cfg.IntOpt( 

163 'ssh_conn_timeout', 

164 default=60, 

165 help='Backend server SSH connection timeout.'), 

166 cfg.IntOpt( 

167 'ssh_min_pool_conn', 

168 default=1, 

169 help='Minimum number of connections in the SSH pool.'), 

170 cfg.IntOpt( 

171 'ssh_max_pool_conn', 

172 default=10, 

173 help='Maximum number of connections in the SSH pool.'), 

174] 

175 

176ganesha_opts = [ 

177 cfg.StrOpt('ganesha_config_dir', 

178 default='/etc/ganesha', 

179 help='Directory where Ganesha config files are stored.'), 

180 cfg.StrOpt('ganesha_config_path', 

181 default='$ganesha_config_dir/ganesha.conf', 

182 help='Path to main Ganesha config file.'), 

183 cfg.StrOpt('ganesha_service_name', 

184 default='ganesha.nfsd', 

185 help='Name of the ganesha nfs service.'), 

186 cfg.StrOpt('ganesha_db_path', 

187 default='$state_path/manila-ganesha.db', 

188 help='Location of Ganesha database file. ' 

189 '(Ganesha module only.)'), 

190 cfg.StrOpt('ganesha_export_dir', 

191 default='$ganesha_config_dir/export.d', 

192 help='Path to directory containing Ganesha export ' 

193 'configuration. (Ganesha module only.)'), 

194 cfg.StrOpt('ganesha_export_template_dir', 

195 default='/etc/manila/ganesha-export-templ.d', 

196 help='Path to directory containing Ganesha export ' 

197 'block templates. (Ganesha module only.)'), 

198 cfg.BoolOpt('ganesha_rados_store_enable', 

199 default=False, 

200 help='Persist Ganesha exports and export counter ' 

201 'in Ceph RADOS objects, highly available storage.'), 

202 cfg.StrOpt('ganesha_rados_store_pool_name', 

203 help='Name of the Ceph RADOS pool to store Ganesha exports ' 

204 'and export counter.'), 

205 cfg.StrOpt('ganesha_rados_export_counter', 

206 default='ganesha-export-counter', 

207 help='Name of the Ceph RADOS object used as the Ganesha ' 

208 'export counter.'), 

209 cfg.StrOpt('ganesha_rados_export_index', 

210 default='ganesha-export-index', 

211 help='Name of the Ceph RADOS object used to store a list ' 

212 'of the export RADOS object URLS.'), 

213] 

214 

215CONF = cfg.CONF 

216CONF.register_opts(share_opts) 

217CONF.register_opts(ssh_opts) 

218CONF.register_opts(ganesha_opts) 

219 

220 

221class ExecuteMixin(object): 

222 """Provides an executable functionality to a driver class.""" 

223 

224 def init_execute_mixin(self, *args, **kwargs): 

225 if self.configuration: 225 ↛ 227line 225 didn't jump to line 227 because the condition on line 225 was always true

226 self.configuration.append_config_values(ssh_opts) 

227 self.set_execute(kwargs.pop('execute', utils.execute)) 

228 

229 def set_execute(self, execute): 

230 self._execute = execute 

231 

232 def _try_execute(self, *command, **kwargs): 

233 # NOTE(vish): Volume commands can partially fail due to timing, but 

234 # running them a second time on failure will usually 

235 # recover nicely. 

236 tries = 0 

237 while True: 

238 try: 

239 self._execute(*command, **kwargs) 

240 return True 

241 except exception.ProcessExecutionError: 

242 tries += 1 

243 if tries >= self.configuration.num_shell_tries: 

244 raise 

245 LOG.exception("Recovering from a failed execute. " 

246 "Try number %s", tries) 

247 time.sleep(tries ** 2) 

248 

249 

250class GaneshaMixin(object): 

251 """Augment derived classes with Ganesha configuration.""" 

252 

253 def init_ganesha_mixin(self, *args, **kwargs): 

254 if self.configuration: 254 ↛ exitline 254 didn't return from function 'init_ganesha_mixin' because the condition on line 254 was always true

255 self.configuration.append_config_values(ganesha_opts) 

256 

257 

258class ShareDriver(object): 

259 """Class defines interface of NAS driver.""" 

260 

261 def __init__(self, driver_handles_share_servers, *args, **kwargs): 

262 """Implements base functionality for share drivers. 

263 

264 :param driver_handles_share_servers: expected boolean value or 

265 tuple/list/set of boolean values. 

266 There are two possible approaches for share drivers in Manila. 

267 First is when share driver is able to handle share-servers and 

268 second when not. 

269 Drivers can support either both (indicated by a tuple/set/list with 

270 (True, False)) or only one of these approaches. So, it is allowed 

271 to be 'True' when share driver does support handling of share 

272 servers and allowed to be 'False' when it does support usage of 

273 unhandled share-servers that are not tracked by Manila. 

274 Share drivers are allowed to work only in one of two possible 

275 driver modes, that is why only one should be chosen. 

276 :param config_opts: tuple, list or set of config option lists 

277 that should be registered in driver's configuration right after 

278 this attribute is created. Useful for usage with mixin classes. 

279 """ 

280 super(ShareDriver, self).__init__() 

281 self.configuration = kwargs.get('configuration', None) 

282 self.initialized = False 

283 self._stats = {} 

284 self.ip_versions = None 

285 self.ipv6_implemented = False 

286 # Indicates whether a driver supports update of security services for 

287 # in-use share networks. This property will be saved in every new share 

288 # server. 

289 self.security_service_update_support = False 

290 # Indicates whether a driver supports adding subnet with its 

291 # allocations to an in-use share network availability zone. This 

292 # property will be saved in every new share server. 

293 self.restore_to_target_support = False 

294 # Indicates whether a driver supports out of place restores 

295 # to a share other then the source of a given backup. 

296 self.network_allocation_update_support = False 

297 self.dhss_mandatory_security_service_association = {} 

298 self.share_replicas_migration_support = False 

299 self.encryption_support = None 

300 

301 self.pools = [] 

302 if self.configuration: 

303 self.configuration.append_config_values(share_opts) 

304 network_config_group = (self.configuration.network_config_group or 

305 self.configuration.config_group) 

306 admin_network_config_group = ( 

307 self.configuration.admin_network_config_group) 

308 else: 

309 network_config_group = None 

310 admin_network_config_group = ( 

311 CONF.admin_network_config_group) 

312 

313 self._verify_share_server_handling(driver_handles_share_servers) 

314 if self.driver_handles_share_servers: 

315 # Enable common network 

316 self.network_api = network.API( 

317 config_group_name=network_config_group) 

318 

319 # Enable admin network 

320 if admin_network_config_group: 

321 self._admin_network_api = network.API( 

322 config_group_name=admin_network_config_group, 

323 label='admin') 

324 

325 for config_opt_set in kwargs.get('config_opts', []): 

326 self.configuration.append_config_values(config_opt_set) 

327 

328 if hasattr(self, 'init_execute_mixin'): 

329 # Instance with 'ExecuteMixin' 

330 # pylint: disable=no-member 

331 self.init_execute_mixin(*args, **kwargs) 

332 if hasattr(self, 'init_ganesha_mixin'): 

333 # Instance with 'GaneshaMixin' 

334 # pylint: disable=no-member 

335 self.init_ganesha_mixin(*args, **kwargs) 

336 

337 @property 

338 def admin_network_api(self): 

339 if hasattr(self, '_admin_network_api'): 

340 return self._admin_network_api 

341 

342 @property 

343 def driver_handles_share_servers(self): 

344 if self.configuration: 

345 return self.configuration.safe_get('driver_handles_share_servers') 

346 return CONF.driver_handles_share_servers 

347 

348 @property 

349 def replication_domain(self): 

350 if self.configuration: 350 ↛ 352line 350 didn't jump to line 352 because the condition on line 350 was always true

351 return self.configuration.safe_get('replication_domain') 

352 return CONF.replication_domain 

353 

354 @property 

355 def max_shares_per_share_server(self): 

356 if self.configuration: 356 ↛ 359line 356 didn't jump to line 359 because the condition on line 356 was always true

357 return self.configuration.safe_get( 

358 'max_shares_per_share_server') or -1 

359 return CONF.max_shares_per_share_server 

360 

361 @property 

362 def max_share_server_size(self): 

363 if self.configuration: 363 ↛ 365line 363 didn't jump to line 365 because the condition on line 363 was always true

364 return self.configuration.safe_get('max_share_server_size') or -1 

365 return CONF.max_share_server_size 

366 

367 def _verify_share_server_handling(self, driver_handles_share_servers): 

368 """Verifies driver_handles_share_servers and given configuration.""" 

369 if not isinstance(self.driver_handles_share_servers, bool): 

370 raise exception.ManilaException( 

371 "Config opt 'driver_handles_share_servers' has improper " 

372 "value - '%s'. Please define it as boolean." % 

373 self.driver_handles_share_servers) 

374 elif isinstance(driver_handles_share_servers, bool): 

375 driver_handles_share_servers = [driver_handles_share_servers] 

376 elif not isinstance(driver_handles_share_servers, (tuple, list, set)): 376 ↛ 377line 376 didn't jump to line 377 because the condition on line 376 was never true

377 raise exception.ManilaException( 

378 "Improper data provided for 'driver_handles_share_servers' - " 

379 "%s" % driver_handles_share_servers) 

380 

381 if any(not isinstance(v, bool) for v in driver_handles_share_servers): 

382 raise exception.ManilaException( 

383 "Provided wrong data: %s" % driver_handles_share_servers) 

384 

385 if (self.driver_handles_share_servers not in 

386 driver_handles_share_servers): 

387 raise exception.ManilaException( 

388 "Driver does not support mode 'driver_handles_share_servers=" 

389 "%(actual)s'. It can be used only with value '%(allowed)s'." % 

390 {'actual': self.driver_handles_share_servers, 

391 'allowed': driver_handles_share_servers}) 

392 

393 def migration_check_compatibility( 

394 self, context, source_share, destination_share, 

395 share_server=None, destination_share_server=None): 

396 """Checks destination compatibility for migration of a given share. 

397 

398 .. note:: 

399 Is called to test compatibility with destination backend. 

400 

401 Driver should check if it is compatible with destination backend so 

402 driver-assisted migration can proceed. 

403 

404 :param context: The 'context.RequestContext' object for the request. 

405 :param source_share: Reference to the share to be migrated. 

406 :param destination_share: Reference to the share model to be used by 

407 migrated share. 

408 :param share_server: Share server model or None. 

409 :param destination_share_server: Destination Share server model or 

410 None. 

411 :return: A dictionary containing values indicating if destination 

412 backend is compatible, if share can remain writable during 

413 migration, if it can preserve all file metadata and if it can 

414 perform migration of given share non-disruptively. 

415 

416 Example:: 

417 

418 { 

419 'compatible': True, 

420 'writable': True, 

421 'preserve_metadata': True, 

422 'nondisruptive': True, 

423 'preserve_snapshots': True, 

424 } 

425 

426 """ 

427 return { 

428 'compatible': False, 

429 'writable': False, 

430 'preserve_metadata': False, 

431 'nondisruptive': False, 

432 'preserve_snapshots': False, 

433 } 

434 

435 def migration_start( 

436 self, context, source_share, destination_share, 

437 source_snapshots, snapshot_mappings, share_server=None, 

438 destination_share_server=None): 

439 """Starts migration of a given share to another host. 

440 

441 .. note:: 

442 Is called in source share's backend to start migration. 

443 

444 Driver should implement this method if willing to perform migration 

445 in a driver-assisted way, useful for when source share's backend driver 

446 is compatible with destination backend driver. This method should 

447 start the migration procedure in the backend and end. Following steps 

448 should be done in 'migration_continue'. 

449 

450 :param context: The 'context.RequestContext' object for the request. 

451 :param source_share: Reference to the original share model. 

452 :param destination_share: Reference to the share model to be used by 

453 migrated share. 

454 :param source_snapshots: List of snapshots owned by the source share. 

455 :param snapshot_mappings: Mapping of source snapshot IDs to 

456 destination snapshot models. 

457 :param share_server: Share server model or None. 

458 :param destination_share_server: Destination Share server model or 

459 None. 

460 """ 

461 raise NotImplementedError() 

462 

463 def migration_continue( 

464 self, context, source_share, destination_share, source_snapshots, 

465 snapshot_mappings, share_server=None, 

466 destination_share_server=None): 

467 """Continues migration of a given share to another host. 

468 

469 .. note:: 

470 Is called in source share's backend to continue migration. 

471 

472 Driver should implement this method to continue monitor the migration 

473 progress in storage and perform following steps until 1st phase is 

474 completed. 

475 

476 :param context: The 'context.RequestContext' object for the request. 

477 :param source_share: Reference to the original share model. 

478 :param destination_share: Reference to the share model to be used by 

479 migrated share. 

480 :param source_snapshots: List of snapshots owned by the source share. 

481 :param snapshot_mappings: Mapping of source snapshot IDs to 

482 destination snapshot models. 

483 :param share_server: Share server model or None. 

484 :param destination_share_server: Destination Share server model or 

485 None. 

486 :return: Boolean value to indicate if 1st phase is finished. 

487 """ 

488 raise NotImplementedError() 

489 

490 def migration_complete( 

491 self, context, source_share, destination_share, source_snapshots, 

492 snapshot_mappings, share_server=None, 

493 destination_share_server=None): 

494 """Completes migration of a given share to another host. 

495 

496 .. note:: 

497 Is called in source share's backend to complete migration. 

498 

499 If driver is implementing 2-phase migration, this method should 

500 perform the disruptive tasks related to the 2nd phase of migration, 

501 thus completing it. Driver should also delete all original share data 

502 from source backend. 

503 

504 :param context: The 'context.RequestContext' object for the request. 

505 :param source_share: Reference to the original share model. 

506 :param destination_share: Reference to the share model to be used by 

507 migrated share. 

508 :param source_snapshots: List of snapshots owned by the source share. 

509 :param snapshot_mappings: Mapping of source snapshot IDs to 

510 destination snapshot models. 

511 :param share_server: Share server model or None. 

512 :param destination_share_server: Destination Share server model or 

513 None. 

514 :return: If the migration changes the share export locations, snapshot 

515 provider locations or snapshot export locations, this method should 

516 return a dictionary with the relevant info. In such case, a 

517 dictionary containing a list of export locations and a list of 

518 model updates for each snapshot indexed by their IDs. 

519 

520 Example:: 

521 

522 { 

523 'export_locations': 

524 [ 

525 { 

526 'path': '1.2.3.4:/foo', 

527 'metadata': {}, 

528 'is_admin_only': False 

529 }, 

530 { 

531 'path': '5.6.7.8:/foo', 

532 'metadata': {}, 

533 'is_admin_only': True 

534 }, 

535 ], 

536 'snapshot_updates': 

537 { 

538 'bc4e3b28-0832-4168-b688-67fdc3e9d408': 

539 { 

540 'provider_location': '/snapshots/foo/bar_1', 

541 'export_locations': 

542 [ 

543 { 

544 'path': '1.2.3.4:/snapshots/foo/bar_1', 

545 'is_admin_only': False, 

546 }, 

547 { 

548 'path': '5.6.7.8:/snapshots/foo/bar_1', 

549 'is_admin_only': True, 

550 }, 

551 ], 

552 }, 

553 '2e62b7ea-4e30-445f-bc05-fd523ca62941': 

554 { 

555 'provider_location': '/snapshots/foo/bar_2', 

556 'export_locations': 

557 [ 

558 { 

559 'path': '1.2.3.4:/snapshots/foo/bar_2', 

560 'is_admin_only': False, 

561 }, 

562 { 

563 'path': '5.6.7.8:/snapshots/foo/bar_2', 

564 'is_admin_only': True, 

565 }, 

566 ], 

567 }, 

568 }, 

569 } 

570 

571 """ 

572 raise NotImplementedError() 

573 

574 def migration_cancel( 

575 self, context, source_share, destination_share, source_snapshots, 

576 snapshot_mappings, share_server=None, 

577 destination_share_server=None): 

578 """Cancels migration of a given share to another host. 

579 

580 .. note:: 

581 Is called in source share's backend to cancel migration. 

582 

583 If possible, driver can implement a way to cancel an in-progress 

584 migration. 

585 

586 :param context: The 'context.RequestContext' object for the request. 

587 :param source_share: Reference to the original share model. 

588 :param destination_share: Reference to the share model to be used by 

589 migrated share. 

590 :param source_snapshots: List of snapshots owned by the source share. 

591 :param snapshot_mappings: Mapping of source snapshot IDs to 

592 destination snapshot models. 

593 :param share_server: Share server model or None. 

594 :param destination_share_server: Destination Share server model or 

595 None. 

596 """ 

597 raise NotImplementedError() 

598 

599 def transfer_accept(self, context, share, new_user, new_project, 

600 access_rules=None, share_server=None): 

601 """Backend update project and user info if stored on the backend. 

602 

603 :param context: The 'context.RequestContext' object for the request. 

604 :param share: Share instance model. 

605 :param access_rules: A list of access rules for given share. 

606 :param new_user: the share will be updated with the new user id . 

607 :param new_project: the share will be updated with the new project id. 

608 :param share_server: share server for given share. 

609 """ 

610 pass 

611 

612 def migration_get_progress( 

613 self, context, source_share, destination_share, source_snapshots, 

614 snapshot_mappings, share_server=None, 

615 destination_share_server=None): 

616 """Obtains progress of migration of a given share to another host. 

617 

618 .. note:: 

619 Is called in source share's backend to obtain migration progress. 

620 

621 If possible, driver can implement a way to return migration progress 

622 information. 

623 

624 :param context: The 'context.RequestContext' object for the request. 

625 :param source_share: Reference to the original share model. 

626 :param destination_share: Reference to the share model to be used by 

627 migrated share. 

628 :param source_snapshots: List of snapshots owned by the source share. 

629 :param snapshot_mappings: Mapping of source snapshot IDs to 

630 destination snapshot models. 

631 :param share_server: Share server model or None. 

632 :param destination_share_server: Destination Share server model or 

633 None. 

634 :return: A dictionary with at least 'total_progress' field containing 

635 the percentage value. 

636 """ 

637 raise NotImplementedError() 

638 

639 def connection_get_info(self, context, share, share_server=None): 

640 """Is called to provide necessary generic migration logic. 

641 

642 :param context: The 'context.RequestContext' object for the request. 

643 :param share: Reference to the share being migrated. 

644 :param share_server: Share server model or None. 

645 :return: A dictionary with migration information. 

646 """ 

647 mount_template = self._get_mount_command(context, share, share_server) 

648 

649 unmount_template = self._get_unmount_command(context, share, 

650 share_server) 

651 

652 access_mapping = self._get_access_mapping(context, share, share_server) 

653 

654 info = { 

655 'mount': mount_template, 

656 'unmount': unmount_template, 

657 'access_mapping': access_mapping, 

658 } 

659 

660 LOG.debug("Migration info obtained for share %(share_id)s: %(info)s.", 

661 {'share_id': share['id'], 'info': str(info)}) 

662 

663 return info 

664 

665 def _get_access_mapping(self, context, share, share_server): 

666 

667 mapping = self.configuration.safe_get('protocol_access_mapping') or {} 

668 result = {} 

669 share_proto = share['share_proto'].lower() 

670 for access_type, protocols in mapping.items(): 

671 if share_proto in [y.lower() for y in protocols]: 

672 result[access_type] = result.get(access_type, []) 

673 result[access_type].append(share_proto) 

674 return result 

675 

676 def _get_mount_command(self, context, share_instance, share_server=None): 

677 """Is called to delegate mounting share logic.""" 

678 

679 mount_template = self.configuration.safe_get('share_mount_template') 

680 

681 mount_export = self._get_mount_export(share_instance, share_server) 

682 

683 format_template = { 

684 'proto': share_instance['share_proto'].lower(), 

685 'export': mount_export, 

686 'path': '%(path)s', 

687 'options': '%(options)s', 

688 } 

689 

690 return mount_template % format_template 

691 

692 def _get_mount_export(self, share_instance, share_server=None): 

693 # NOTE(ganso): If drivers want to override the export_location IP, 

694 # they can do so using this configuration. This method can also be 

695 # overridden if necessary. 

696 path = next((x['path'] for x in share_instance['export_locations'] 

697 if x['is_admin_only']), None) 

698 if not path: 

699 path = share_instance['export_locations'][0]['path'] 

700 return path 

701 

702 def _get_unmount_command(self, context, share_instance, 

703 share_server=None): 

704 return self.configuration.safe_get('share_unmount_template') 

705 

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

707 """Is called to create share.""" 

708 raise NotImplementedError() 

709 

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

711 share_server=None, parent_share=None): 

712 """Is called to create share from snapshot. 

713 

714 Creating a share from snapshot can take longer than a simple clone 

715 operation if data copy is required from one host to another. For this 

716 reason driver will be able complete this creation asynchronously, by 

717 providing a 'creating_from_snapshot' status in the model update. 

718 

719 When answering asynchronously, drivers must implement the call 

720 'get_share_status' in order to provide updates for shares with 

721 'creating_from_snapshot' status. 

722 

723 It is expected that the driver returns a model update to the share 

724 manager that contains: share status and a list of export_locations. 

725 A list of 'export_locations' is mandatory only for share in 'available' 

726 status. 

727 The current supported status are 'available' and 

728 'creating_from_snapshot'. 

729 

730 :param context: Current context 

731 :param share: Share instance model with share data. 

732 :param snapshot: Snapshot instance model . 

733 :param share_server: Share server model or None. 

734 :param parent_share: Share model from parent snapshot with share data 

735 and share server model. 

736 

737 :returns: a dictionary of updates containing current share status and 

738 its export_location (if available). 

739 

740 Example:: 

741 

742 { 

743 'status': 'available', 

744 'export_locations': [{...}, {...}], 

745 } 

746 

747 :raises: ShareBackendException. 

748 A ShareBackendException in this method will set the instance to 

749 'error' and the operation will end. 

750 """ 

751 raise NotImplementedError() 

752 

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

754 """Is called to create snapshot. 

755 

756 :param context: Current context 

757 :param snapshot: Snapshot model. Share model could be 

758 retrieved through snapshot['share']. 

759 :param share_server: Share server model or None. 

760 :return: None or a dictionary with key 'export_locations' containing 

761 a list of export locations, if snapshots can be mounted. 

762 """ 

763 raise NotImplementedError() 

764 

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

766 """Is called to remove share.""" 

767 raise NotImplementedError() 

768 

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

770 """Is called to remove snapshot. 

771 

772 :param context: Current context 

773 :param snapshot: Snapshot model. Share model could be 

774 retrieved through snapshot['share']. 

775 :param share_server: Share server model or None. 

776 """ 

777 raise NotImplementedError() 

778 

779 def get_pool(self, share): 

780 """Return pool name where the share resides on. 

781 

782 :param share: The share hosted by the driver. 

783 """ 

784 

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

786 """Invoked to ensure that share is exported. 

787 

788 Driver can use this method to update the list of export locations of 

789 the share if it changes. To do that, you should return list with 

790 export locations. 

791 

792 It is preferred if the driver implements "get_backend_info" and 

793 "ensure_shares" instead of this routine. 

794 

795 :return: None or list with export locations 

796 """ 

797 raise NotImplementedError() 

798 

799 def allow_access(self, context, share, access, share_server=None): 

800 """Allow access to the share.""" 

801 raise NotImplementedError() 

802 

803 def deny_access(self, context, share, access, share_server=None): 

804 """Deny access to the share.""" 

805 raise NotImplementedError() 

806 

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

808 delete_rules, update_rules, share_server=None): 

809 """Update access rules for given share. 

810 

811 ``access_rules`` contains all access_rules that need to be on the 

812 share. If the driver can make bulk access rule updates, it can 

813 safely ignore the ``add_rules`` and ``delete_rules`` parameters. 

814 

815 If the driver cannot make bulk access rule changes, it can rely on 

816 new rules to be present in ``add_rules`` and rules that need to be 

817 removed to be present in ``delete_rules``. 

818 

819 When a rule in ``delete_rules`` was never applied, drivers must not 

820 raise an exception, or attempt to set the rule to ``error`` state. 

821 

822 ``add_rules`` and ``delete_rules`` can be empty lists, in this 

823 situation, drivers should ensure that the rules present in 

824 ``access_rules`` are the same as those on the back end. One scenario 

825 where this situation is forced is when the access_level is changed for 

826 all existing rules (share migration and for readable replicas). 

827 

828 Drivers must be mindful of this call for share replicas. When 

829 'update_access' is called on one of the replicas, the call is likely 

830 propagated to all replicas belonging to the share, especially when 

831 individual rules are added or removed. If a particular access rule 

832 does not make sense to the driver in the context of a given replica, 

833 the driver should be careful to report a correct behavior, and take 

834 meaningful action. For example, if R/W access is requested on a 

835 replica that is part of a "readable" type replication; R/O access 

836 may be added by the driver instead of R/W. Note that raising an 

837 exception *will* result in the access_rules_status on the replica, 

838 and the share itself being "out_of_sync". Drivers can sync on the 

839 valid access rules that are provided on the ``create_replica`` and 

840 ``promote_replica`` calls. 

841 

842 :param context: Current context 

843 :param share: Share model with share data. 

844 :param access_rules: A list of access rules for given share 

845 :param add_rules: Empty List or List of access rules which should be 

846 added. access_rules already contains these rules. 

847 :param delete_rules: Empty List or List of access rules which should be 

848 removed. access_rules doesn't contain these rules. 

849 :param update_rules: Empty List or List of access rules which should be 

850 updated. access_rules already contains these rules. 

851 :param share_server: None or Share server model 

852 :returns: None, or a dictionary of updates in the format:: 

853 

854 { 

855 

856 '09960614-8574-4e03-89cf-7cf267b0bd08': { 

857 

858 'access_key': 'alice31493e5441b8171d2310d80e37e', 

859 'state': 'error', 

860 

861 }, 

862 

863 '28f6eabb-4342-486a-a7f4-45688f0c0295': { 

864 

865 'access_key': 'bob0078aa042d5a7325480fd13228b', 

866 'state': 'active', 

867 

868 }, 

869 

870 } 

871 

872 The top level keys are 'access_id' fields of the access rules that 

873 need to be updated. ``access_key``s are credentials (str) of the 

874 entities granted access. Any rule in the ``access_rules`` parameter 

875 can be updated. 

876 

877 .. important:: 

878 

879 Raising an exception in this method will force *all* rules in 

880 'applying' and 'denying' states to 'error'. 

881 

882 An access rule can be set to 'error' state, either explicitly 

883 via this return parameter or because of an exception raised in 

884 this method. Such an access rule will no longer be sent to the 

885 driver on subsequent access rule updates. When users deny that 

886 rule however, the driver will be asked to deny access to the 

887 client/s represented by the rule. We expect that a 

888 rule that was error-ed at the driver should never exist on the 

889 back end. So, do not fail the deletion request. 

890 

891 Also, it is possible that the driver may receive a request to 

892 add a rule that is already present on the back end. 

893 This can happen if the share manager service goes down 

894 while the driver is committing access rule changes. Since we 

895 cannot determine if the rule was applied successfully by the driver 

896 before the disruption, we will treat all 'applying' transitional 

897 rules as new rules and repeat the request. 

898 """ 

899 raise NotImplementedError() 

900 

901 def check_for_setup_error(self): 

902 """Check for setup error.""" 

903 pass 

904 

905 def do_setup(self, context): 

906 """Any initialization the share driver does while starting.""" 

907 

908 def get_share_stats(self, refresh=False): 

909 """Get share status. 

910 

911 If 'refresh' is True, run update the stats first. 

912 """ 

913 if refresh: 

914 self._update_share_stats() 

915 

916 return self._stats 

917 

918 def get_network_allocations_number(self): 

919 """Returns number of network allocations for creating VIFs. 

920 

921 Drivers that use Nova for share servers should return zero (0) here 

922 same as Generic driver does. 

923 Because Nova will handle network resources allocation. 

924 Drivers that handle networking itself should calculate it according 

925 to their own requirements. It can have 1+ network interfaces. 

926 """ 

927 raise NotImplementedError() 

928 

929 def get_admin_network_allocations_number(self): 

930 return 0 

931 

932 def update_network_allocation(self, context, share_server): 

933 """Update network allocation after share server creation.""" 

934 self.network_api.update_network_allocation(context, share_server) 

935 

936 def update_admin_network_allocation(self, context, share_server): 

937 """Update admin network allocation after share server creation.""" 

938 if (self.get_admin_network_allocations_number() and 938 ↛ 940line 938 didn't jump to line 940 because the condition on line 938 was never true

939 self.admin_network_api): 

940 self.admin_network_api.update_network_allocation(context, 

941 share_server) 

942 

943 def allocate_network(self, context, share_server, share_network, 

944 share_network_subnet, count=None, **kwargs): 

945 """Allocate network resources using given network information.""" 

946 if count is None: 

947 count = self.get_network_allocations_number() 

948 if count: 

949 kwargs.update(count=count) 

950 self.network_api.allocate_network( 

951 context, share_server, share_network=share_network, 

952 share_network_subnet=share_network_subnet, **kwargs) 

953 

954 def allocate_admin_network(self, context, share_server, count=None, 

955 **kwargs): 

956 """Allocate admin network resources using given network information.""" 

957 if count is None: 

958 count = self.get_admin_network_allocations_number() 

959 if count and not self.admin_network_api: 

960 msg = _("Admin network plugin is not set up.") 

961 raise exception.NetworkBadConfigurationException(reason=msg) 

962 elif count: 

963 kwargs.update(count=count) 

964 self.admin_network_api.allocate_network( 

965 context, share_server, **kwargs) 

966 

967 def deallocate_network(self, context, share_server_id, share_network=None, 

968 share_network_subnet=None): 

969 """Deallocate network resources for the given share server.""" 

970 if self.get_network_allocations_number(): 970 ↛ exitline 970 didn't return from function 'deallocate_network' because the condition on line 970 was always true

971 self.network_api.deallocate_network( 

972 context, share_server_id, share_network=share_network, 

973 share_network_subnet=share_network_subnet) 

974 

975 def choose_share_server_compatible_with_share(self, context, share_servers, 

976 share, snapshot=None, 

977 share_group=None, 

978 encryption_key_ref=None): 

979 """Method that allows driver to choose share server for provided share. 

980 

981 If compatible share-server is not found, method should return None. 

982 

983 :param context: Current context 

984 :param share_servers: list with share-server models 

985 :param share: share model 

986 :param snapshot: snapshot model 

987 :param share_group: ShareGroup model with shares 

988 :param encryption_key_ref: Encryption key reference 

989 :returns: share-server or None 

990 """ 

991 # If creating in a share group, use its share server 

992 if share_group: 992 ↛ 993line 992 didn't jump to line 993 because the condition on line 992 was never true

993 for share_server in share_servers: 

994 if (share_group.get('share_server_id') == 

995 share_server['id']): 

996 return share_server 

997 return None 

998 

999 return share_servers[0] if share_servers else None 

1000 

1001 def choose_share_server_compatible_with_share_group( 

1002 self, context, share_servers, share_group_ref, 

1003 share_group_snapshot=None): 

1004 

1005 return share_servers[0] if share_servers else None 

1006 

1007 def setup_server(self, *args, **kwargs): 

1008 if self.driver_handles_share_servers: 

1009 return self._setup_server(*args, **kwargs) 

1010 else: 

1011 LOG.debug( 

1012 "Skipping step 'setup share server', because driver is " 

1013 "enabled with mode when Manila does not handle share servers.") 

1014 

1015 def _setup_server(self, network_info, metadata=None): 

1016 """Sets up and configures share server with given network parameters. 

1017 

1018 Redefine it within share driver when it is going to handle share 

1019 servers. 

1020 

1021 :param metadata: a dictionary, for now containing a key 'request_host' 

1022 """ 

1023 raise NotImplementedError() 

1024 

1025 def manage_existing(self, share, driver_options): 

1026 """Brings an existing share under Manila management. 

1027 

1028 If the provided share is not valid, then raise a 

1029 ManageInvalidShare exception, specifying a reason for the failure. 

1030 

1031 If the provided share is not in a state that can be managed, such as 

1032 being replicated on the backend, the driver *MUST* raise 

1033 ManageInvalidShare exception with an appropriate message. 

1034 

1035 The share has a share_type, and the driver can inspect that and 

1036 compare against the properties of the referenced backend share. 

1037 If they are incompatible, raise a 

1038 ManageExistingShareTypeMismatch, specifying a reason for the failure. 

1039 

1040 This method is invoked when the share is being managed with 

1041 a share type that has ``driver_handles_share_servers`` 

1042 extra-spec set to False. 

1043 

1044 :param share: Share model 

1045 :param driver_options: Driver-specific options provided by admin. 

1046 :return: share_update dictionary with required key 'size', 

1047 which should contain size of the share. 

1048 """ 

1049 raise NotImplementedError() 

1050 

1051 def manage_existing_with_server( 

1052 self, share, driver_options, share_server=None): 

1053 """Brings an existing share under Manila management. 

1054 

1055 If the provided share is not valid, then raise a 

1056 ManageInvalidShare exception, specifying a reason for the failure. 

1057 

1058 If the provided share is not in a state that can be managed, such as 

1059 being replicated on the backend, the driver *MUST* raise 

1060 ManageInvalidShare exception with an appropriate message. 

1061 

1062 The share has a share_type, and the driver can inspect that and 

1063 compare against the properties of the referenced backend share. 

1064 If they are incompatible, raise a 

1065 ManageExistingShareTypeMismatch, specifying a reason for the failure. 

1066 

1067 This method is invoked when the share is being managed with 

1068 a share type that has ``driver_handles_share_servers`` 

1069 extra-spec set to True. 

1070 

1071 :param share: Share model 

1072 :param driver_options: Driver-specific options provided by admin. 

1073 :param share_server: Share server model or None. 

1074 :return: share_update dictionary with required key 'size', 

1075 which should contain size of the share. 

1076 """ 

1077 raise NotImplementedError() 

1078 

1079 def unmanage(self, share): 

1080 """Removes the specified share from Manila management. 

1081 

1082 Does not delete the underlying backend share. 

1083 

1084 For most drivers, this will not need to do anything. However, some 

1085 drivers might use this call as an opportunity to clean up any 

1086 Manila-specific configuration that they have associated with the 

1087 backend share. 

1088 

1089 If provided share cannot be unmanaged, then raise an 

1090 UnmanageInvalidShare exception, specifying a reason for the failure. 

1091 

1092 This method is invoked when the share is being unmanaged with 

1093 a share type that has ``driver_handles_share_servers`` 

1094 extra-spec set to False. 

1095 """ 

1096 

1097 def unmanage_with_server(self, share, share_server=None): 

1098 """Removes the specified share from Manila management. 

1099 

1100 Does not delete the underlying backend share. 

1101 

1102 For most drivers, this will not need to do anything. However, some 

1103 drivers might use this call as an opportunity to clean up any 

1104 Manila-specific configuration that they have associated with the 

1105 backend share. 

1106 

1107 If provided share cannot be unmanaged, then raise an 

1108 UnmanageInvalidShare exception, specifying a reason for the failure. 

1109 

1110 This method is invoked when the share is being unmanaged with 

1111 a share type that has ``driver_handles_share_servers`` 

1112 extra-spec set to True. 

1113 """ 

1114 

1115 def manage_existing_snapshot(self, snapshot, driver_options): 

1116 """Brings an existing snapshot under Manila management. 

1117 

1118 If provided snapshot is not valid, then raise a 

1119 ManageInvalidShareSnapshot exception, specifying a reason for 

1120 the failure. 

1121 

1122 This method is invoked when the snapshot that is being managed 

1123 belongs to a share that has its share type with 

1124 ``driver_handles_share_servers`` extra-spec set to False. 

1125 

1126 :param snapshot: ShareSnapshotInstance model with ShareSnapshot data. 

1127 

1128 Example:: 

1129 { 

1130 'id': <instance id>, 

1131 'snapshot_id': < snapshot id>, 

1132 'provider_location': <location>, 

1133 ... 

1134 } 

1135 

1136 :param driver_options: Optional driver-specific options provided 

1137 by admin. 

1138 

1139 Example:: 

1140 

1141 { 

1142 'key': 'value', 

1143 ... 

1144 } 

1145 

1146 :return: model_update dictionary with required key 'size', 

1147 which should contain size of the share snapshot, and key 

1148 'export_locations' containing a list of export locations, if 

1149 snapshots can be mounted. 

1150 """ 

1151 raise NotImplementedError() 

1152 

1153 def manage_existing_snapshot_with_server(self, snapshot, driver_options, 

1154 share_server=None): 

1155 """Brings an existing snapshot under Manila management. 

1156 

1157 If provided snapshot is not valid, then raise a 

1158 ManageInvalidShareSnapshot exception, specifying a reason for 

1159 the failure. 

1160 

1161 This method is invoked when the snapshot that is being managed 

1162 belongs to a share that has its share type with 

1163 ``driver_handles_share_servers`` extra-spec set to True. 

1164 

1165 :param snapshot: ShareSnapshotInstance model with ShareSnapshot data. 

1166 

1167 Example:: 

1168 { 

1169 'id': <instance id>, 

1170 'snapshot_id': < snapshot id>, 

1171 'provider_location': <location>, 

1172 ... 

1173 } 

1174 

1175 :param driver_options: Optional driver-specific options provided 

1176 by admin. 

1177 

1178 Example:: 

1179 

1180 { 

1181 'key': 'value', 

1182 ... 

1183 } 

1184 

1185 :param share_server: Share server model or None. 

1186 :return: model_update dictionary with required key 'size', 

1187 which should contain size of the share snapshot, and key 

1188 'export_locations' containing a list of export locations, if 

1189 snapshots can be mounted. 

1190 """ 

1191 raise NotImplementedError() 

1192 

1193 def unmanage_snapshot(self, snapshot): 

1194 """Removes the specified snapshot from Manila management. 

1195 

1196 Does not delete the underlying backend share snapshot. 

1197 

1198 For most drivers, this will not need to do anything. However, some 

1199 drivers might use this call as an opportunity to clean up any 

1200 Manila-specific configuration that they have associated with the 

1201 backend share snapshot. 

1202 

1203 If provided share snapshot cannot be unmanaged, then raise an 

1204 UnmanageInvalidShareSnapshot exception, specifying a reason for 

1205 the failure. 

1206 

1207 This method is invoked when the snapshot that is being unmanaged 

1208 belongs to a share that has its share type with 

1209 ``driver_handles_share_servers`` extra-spec set to False. 

1210 """ 

1211 

1212 def unmanage_snapshot_with_server(self, snapshot, share_server=None): 

1213 """Removes the specified snapshot from Manila management. 

1214 

1215 Does not delete the underlying backend share snapshot. 

1216 

1217 For most drivers, this will not need to do anything. However, some 

1218 drivers might use this call as an opportunity to clean up any 

1219 Manila-specific configuration that they have associated with the 

1220 backend share snapshot. 

1221 

1222 If provided share snapshot cannot be unmanaged, then raise an 

1223 UnmanageInvalidShareSnapshot exception, specifying a reason for 

1224 the failure. 

1225 

1226 This method is invoked when the snapshot that is being unmanaged 

1227 belongs to a share that has its share type with 

1228 ``driver_handles_share_servers`` extra-spec set to True. 

1229 """ 

1230 

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

1232 snapshot_access_rules, share_server=None): 

1233 """Reverts a share (in place) to the specified snapshot. 

1234 

1235 Does not delete the share snapshot. The share and snapshot must both 

1236 be 'available' for the restore to be attempted. The snapshot must be 

1237 the most recent one taken by Manila; the API layer performs this check 

1238 so the driver doesn't have to. 

1239 

1240 The share must be reverted in place to the contents of the snapshot. 

1241 Application admins should quiesce or otherwise prepare the application 

1242 for the shared file system contents to change suddenly. 

1243 

1244 :param context: Current context 

1245 :param snapshot: The snapshot to be restored 

1246 :param share_access_rules: List of all access rules for the affected 

1247 share 

1248 :param snapshot_access_rules: List of all access rules for the affected 

1249 snapshot 

1250 :param share_server: Optional -- Share server model or None 

1251 """ 

1252 raise NotImplementedError() 

1253 

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

1255 """Extends size of existing share. 

1256 

1257 :param share: Share model 

1258 :param new_size: New size of share (new_size > share['size']) 

1259 :param share_server: Optional -- Share server model 

1260 """ 

1261 raise NotImplementedError() 

1262 

1263 def shrink_share(self, share, new_size, share_server=None): 

1264 """Shrinks size of existing share. 

1265 

1266 If consumed space on share larger than new_size driver should raise 

1267 ShareShrinkingPossibleDataLoss exception: 

1268 raise ShareShrinkingPossibleDataLoss(share_id=share['id']) 

1269 

1270 :param share: Share model 

1271 :param new_size: New size of share (new_size < share['size']) 

1272 :param share_server: Optional -- Share server model 

1273 

1274 :raises ShareShrinkingPossibleDataLoss, NotImplementedError 

1275 """ 

1276 raise NotImplementedError() 

1277 

1278 def teardown_server(self, *args, **kwargs): 

1279 if self.driver_handles_share_servers: 

1280 return self._teardown_server(*args, **kwargs) 

1281 else: 

1282 LOG.debug( 

1283 "Skipping step 'teardown share server', because driver is " 

1284 "enabled with mode when Manila does not handle share servers.") 

1285 

1286 def _teardown_server(self, server_details, security_services=None): 

1287 """Tears down share server. 

1288 

1289 Redefine it within share driver when it is going to handle share 

1290 servers. 

1291 """ 

1292 raise NotImplementedError() 

1293 

1294 def _has_redefined_driver_methods(self, methods): 

1295 """Returns boolean as a result of methods presence and redefinition.""" 

1296 if not isinstance(methods, (set, list, tuple)): 1296 ↛ 1297line 1296 didn't jump to line 1297 because the condition on line 1296 was never true

1297 methods = (methods, ) 

1298 for method_name in methods: 

1299 method = getattr(type(self), method_name, None) 

1300 if (not method or method == getattr(ShareDriver, method_name)): 

1301 return False 

1302 return True 

1303 

1304 @property 

1305 def snapshots_are_supported(self): 

1306 if not hasattr(self, '_snapshots_are_supported'): 

1307 methods = ('create_snapshot', 'delete_snapshot') 

1308 # NOTE(vponomaryov): calculate default value for 

1309 # stat 'snapshot_support' based on implementation of 

1310 # appropriate methods of this base driver class. 

1311 self._snapshots_are_supported = self._has_redefined_driver_methods( 

1312 methods) 

1313 return self._snapshots_are_supported 

1314 

1315 @property 

1316 def creating_shares_from_snapshots_is_supported(self): 

1317 """Calculate default value for create_share_from_snapshot_support.""" 

1318 

1319 if not hasattr(self, '_creating_shares_from_snapshots_is_supported'): 

1320 methods = ('create_share_from_snapshot', ) 

1321 self._creating_shares_from_snapshots_is_supported = ( 

1322 self._has_redefined_driver_methods(methods)) 

1323 

1324 return ( 

1325 self._creating_shares_from_snapshots_is_supported and 

1326 self.snapshots_are_supported 

1327 ) 

1328 

1329 def _update_share_stats(self, data=None): 

1330 """Retrieve stats info from share group. 

1331 

1332 :param data: dict -- dict with key-value pairs to redefine common ones. 

1333 """ 

1334 

1335 LOG.debug("Updating share stats.") 

1336 backend_name = (self.configuration.safe_get('share_backend_name') or 

1337 CONF.share_backend_name) 

1338 

1339 # Note(zhiteng): These information are driver/backend specific, 

1340 # each driver may define these values in its own config options 

1341 # or fetch from driver specific configuration file. 

1342 common = dict( 

1343 share_backend_name=backend_name or 'Generic_NFS', 

1344 driver_handles_share_servers=self.driver_handles_share_servers, 

1345 vendor_name='Open Source', 

1346 driver_version='1.0', 

1347 storage_protocol=None, 

1348 total_capacity_gb='unknown', 

1349 free_capacity_gb='unknown', 

1350 reserved_percentage=0, 

1351 reserved_snapshot_percentage=0, 

1352 reserved_share_extend_percentage=0, 

1353 qos=False, 

1354 pools=self.pools or None, 

1355 snapshot_support=self.snapshots_are_supported, 

1356 create_share_from_snapshot_support=( 

1357 self.creating_shares_from_snapshots_is_supported), 

1358 revert_to_snapshot_support=False, 

1359 mount_snapshot_support=False, 

1360 replication_domain=self.replication_domain, 

1361 filter_function=self.get_filter_function(), 

1362 goodness_function=self.get_goodness_function(), 

1363 security_service_update_support=( 

1364 self.security_service_update_support), 

1365 network_allocation_update_support=( 

1366 self.network_allocation_update_support), 

1367 share_server_multiple_subnet_support=False, 

1368 mount_point_name_support=False, 

1369 share_replicas_migration_support=( 

1370 self.share_replicas_migration_support), 

1371 encryption_support=self.encryption_support, 

1372 ) 

1373 if isinstance(data, dict): 

1374 common.update(data) 

1375 

1376 if self.driver_handles_share_servers: 

1377 common.update({ 

1378 'max_shares_per_share_server': 

1379 self.max_shares_per_share_server, 

1380 'max_share_server_size': self.max_share_server_size 

1381 }) 

1382 

1383 sg_stats = data.get('share_group_stats', {}) if data else {} 

1384 common['share_group_stats'] = { 

1385 'consistent_snapshot_support': sg_stats.get( 

1386 'consistent_snapshot_support'), 

1387 } 

1388 

1389 self.add_ip_version_capability(common) 

1390 self._stats = common 

1391 

1392 def get_share_server_pools(self, share_server): 

1393 """Return list of pools related to a particular share server. 

1394 

1395 :param share_server: ShareServer class instance. 

1396 """ 

1397 return [] 

1398 

1399 def create_share_group(self, context, share_group_dict, share_server=None): 

1400 """Create a share group. 

1401 

1402 :param context: 

1403 :param share_group_dict: The share group details 

1404 EXAMPLE: 

1405 { 

1406 'status': 'creating', 

1407 'project_id': '13c0be6290934bd98596cfa004650049', 

1408 'user_id': 'a0314a441ca842019b0952224aa39192', 

1409 'description': None, 

1410 'deleted': 'False', 

1411 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6), 

1412 'updated_at': None, 

1413 'source_share_group_snapshot_id': 'some_fake_uuid', 

1414 'share_group_type_id': 'some_fake_uuid', 

1415 'host': 'hostname@backend_name', 

1416 'share_network_id': None, 

1417 'share_server_id': None, 

1418 'deleted_at': None, 

1419 'share_types': [<models.ShareGroupShareTypeMapping>], 

1420 'id': 'some_fake_uuid', 

1421 'name': None 

1422 } 

1423 :returns: (share_group_model_update, share_update_list) 

1424 share_group_model_update - a dict containing any values to be 

1425 updated for the SG in the database. This value may be None. 

1426 

1427 """ 

1428 LOG.debug('Created a Share Group with ID: %s.', share_group_dict['id']) 

1429 

1430 def create_share_group_from_share_group_snapshot( 

1431 self, context, share_group_dict, share_group_snapshot_dict, 

1432 share_server=None): 

1433 """Create a share group from a share group snapshot. 

1434 

1435 When creating a share from snapshot operation takes longer than a 

1436 simple clone operation, drivers will be able to complete this creation 

1437 asynchronously, by providing a 'creating_from_snapshot' status in the 

1438 returned model update. The current supported status are 'available' and 

1439 'creating_from_snapshot'. 

1440 

1441 In order to provide updates for shares with 'creating_from_snapshot' 

1442 status, drivers must implement the call 'get_share_status'. 

1443 

1444 :param context: 

1445 :param share_group_dict: The share group details 

1446 EXAMPLE: 

1447 .. code:: 

1448 

1449 { 

1450 'status': 'creating', 

1451 'project_id': '13c0be6290934bd98596cfa004650049', 

1452 'user_id': 'a0314a441ca842019b0952224aa39192', 

1453 'description': None, 

1454 'deleted': 'False', 

1455 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6), 

1456 'updated_at': None, 

1457 'source_share_group_snapshot_id': 

1458 'f6aa3b59-57eb-421e-965c-4e182538e36a', 

1459 'host': 'hostname@backend_name', 

1460 'deleted_at': None, 

1461 'shares': [<models.Share>], # The new shares being created 

1462 'share_types': [<models.ShareGroupShareTypeMapping>], 

1463 'id': 'some_fake_uuid', 

1464 'name': None 

1465 } 

1466 :param share_group_snapshot_dict: The share group snapshot details 

1467 EXAMPLE: 

1468 .. code:: 

1469 

1470 { 

1471 'status': 'available', 

1472 'project_id': '13c0be6290934bd98596cfa004650049', 

1473 'user_id': 'a0314a441ca842019b0952224aa39192', 

1474 'description': None, 

1475 'deleted': '0', 

1476 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1477 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1478 'share_group_id': 'some_fake_uuid', 

1479 'share_share_group_snapshot_members': [ 

1480 { 

1481 'status': 'available', 

1482 'user_id': 'a0314a441ca842019b0952224aa39192', 

1483 'deleted': 'False', 

1484 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1485 'share': <models.Share>, 

1486 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1487 'share_proto': 'NFS', 

1488 'project_id': '13c0be6290934bd98596cfa004650049', 

1489 'share_group_snapshot_id': 'some_fake_uuid', 

1490 'deleted_at': None, 

1491 'id': 'some_fake_uuid', 

1492 'size': 1 

1493 } 

1494 ], 

1495 'deleted_at': None, 

1496 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a', 

1497 'name': None 

1498 } 

1499 :return: (share_group_model_update, share_update_list) 

1500 share_group_model_update - a dict containing any values to be 

1501 updated for the share group in the database. This value may be None 

1502 

1503 share_update_list - a list of dictionaries containing dicts for 

1504 every share created in the share group. Any share dicts should at a 

1505 minimum contain the 'id' key and, for synchronous creation, the 

1506 'export_locations'. For asynchronous share creation this dict 

1507 must also contain the key 'status' with the value set to 

1508 'creating_from_snapshot'. The current supported status are 

1509 'available' and 'creating_from_snapshot'. 

1510 Export locations should be in the same format as returned by 

1511 a share_create. This list may be empty or None. EXAMPLE: 

1512 .. code:: 

1513 

1514 [ 

1515 { 

1516 'id': 'uuid', 

1517 'export_locations': [{...}, {...}], 

1518 }, 

1519 { 

1520 'id': 'uuid', 

1521 'export_locations': [], 

1522 'status': 'creating_from_snapshot', 

1523 }, 

1524 ] 

1525 

1526 """ 

1527 # Ensure that the share group snapshot has members 

1528 if not share_group_snapshot_dict['share_group_snapshot_members']: 

1529 return None, None 

1530 

1531 clone_list = self._collate_share_group_snapshot_info( 

1532 share_group_dict, share_group_snapshot_dict) 

1533 share_update_list = [] 

1534 

1535 LOG.debug('Creating share group from group snapshot %s.', 

1536 share_group_snapshot_dict['id']) 

1537 for clone in clone_list: 

1538 kwargs = {} 

1539 share_update_info = {} 

1540 if self.driver_handles_share_servers: 

1541 kwargs['share_server'] = share_server 

1542 model_update = ( 

1543 self.create_share_from_snapshot( 

1544 context, clone['share'], clone['snapshot'], **kwargs)) 

1545 if isinstance(model_update, dict): 

1546 status = model_update.get('status') 

1547 # NOTE(dviroel): share status is mandatory when answering 

1548 # a model update. If not provided, won't be possible to 

1549 # determine if was successfully created. 

1550 if status is None: 1550 ↛ 1551line 1550 didn't jump to line 1551 because the condition on line 1550 was never true

1551 msg = _("Driver didn't provide a share status.") 

1552 raise exception.InvalidShareInstance(reason=msg) 

1553 if status not in [constants.STATUS_AVAILABLE, 

1554 constants.STATUS_CREATING_FROM_SNAPSHOT]: 

1555 msg = _('Driver returned an invalid status: %s') % status 

1556 raise exception.InvalidShareInstance(reason=msg) 

1557 share_update_info.update({'status': status}) 

1558 export_locations = model_update.get('export_locations', []) 

1559 else: 

1560 # NOTE(dviroel): the driver that doesn't implement the new 

1561 # model_update will return only the export locations 

1562 export_locations = model_update 

1563 

1564 share_update_info.update({ 

1565 'id': clone['share']['id'], 

1566 'export_locations': export_locations, 

1567 }) 

1568 share_update_list.append(share_update_info) 

1569 return None, share_update_list 

1570 

1571 def delete_share_group(self, context, share_group_dict, share_server=None): 

1572 """Delete a share group 

1573 

1574 :param context: The request context 

1575 :param share_group_dict: The share group details 

1576 EXAMPLE: 

1577 .. code:: 

1578 

1579 { 

1580 'status': 'creating', 

1581 'project_id': '13c0be6290934bd98596cfa004650049', 

1582 'user_id': 'a0314a441ca842019b0952224aa39192', 

1583 'description': None, 

1584 'deleted': 'False', 

1585 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6), 

1586 'updated_at': None, 

1587 'source_share_group_snapshot_id': 'some_fake_uuid', 

1588 'share_share_group_type_id': 'some_fake_uuid', 

1589 'host': 'hostname@backend_name', 

1590 'deleted_at': None, 

1591 'shares': [<models.Share>], # The new shares being created 

1592 'share_types': [<models.ShareGroupShareTypeMapping>], 

1593 'id': 'some_fake_uuid', 

1594 'name': None 

1595 } 

1596 :return: share_group_model_update 

1597 share_group_model_update - a dict containing any values to be 

1598 updated for the group in the database. This value may be None. 

1599 """ 

1600 

1601 def _cleanup_group_share_snapshot(self, context, share_snapshot, 

1602 share_server): 

1603 """Deletes the snapshot of a share belonging to a group.""" 

1604 

1605 try: 

1606 self.delete_snapshot( 

1607 context, share_snapshot, share_server=share_server) 

1608 except exception.ManilaException: 

1609 msg = ('Could not delete share group snapshot member %(snap)s ' 

1610 'for share %(share)s.') 

1611 LOG.error(msg, { 

1612 'snap': share_snapshot['id'], 

1613 'share': share_snapshot['share_id'], 

1614 }) 

1615 raise 

1616 

1617 def create_share_group_snapshot(self, context, snap_dict, 

1618 share_server=None): 

1619 """Create a share group snapshot. 

1620 

1621 :param context: 

1622 :param snap_dict: The share group snapshot details 

1623 EXAMPLE: 

1624 .. code:: 

1625 

1626 { 

1627 'status': 'available', 

1628 'project_id': '13c0be6290934bd98596cfa004650049', 

1629 'user_id': 'a0314a441ca842019b0952224aa39192', 

1630 'description': None, 

1631 'deleted': '0', 

1632 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1633 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1634 'share_group_id': 'some_fake_uuid', 

1635 'share_group_snapshot_members': [ 

1636 { 

1637 'status': 'available', 

1638 'share_type_id': 'some_fake_uuid', 

1639 'user_id': 'a0314a441ca842019b0952224aa39192', 

1640 'deleted': 'False', 

1641 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1642 'share': <models.Share>, 

1643 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1644 'share_proto': 'NFS', 

1645 'share_name': 'share_some_fake_uuid', 

1646 'name': 'share-snapshot-some_fake_uuid', 

1647 'project_id': '13c0be6290934bd98596cfa004650049', 

1648 'share_group_snapshot_id': 'some_fake_uuid', 

1649 'deleted_at': None, 

1650 'share_id': 'some_fake_uuid', 

1651 'id': 'some_fake_uuid', 

1652 'size': 1, 

1653 'provider_location': None, 

1654 } 

1655 ], 

1656 'deleted_at': None, 

1657 'id': 'some_fake_uuid', 

1658 'name': None 

1659 } 

1660 :return: (share_group_snapshot_update, member_update_list) 

1661 share_group_snapshot_update - a dict containing any values to be 

1662 updated for the CGSnapshot in the database. This value may be None. 

1663 

1664 member_update_list - a list of dictionaries containing for every 

1665 member of the share group snapshot. Each dict should contains 

1666 values to be updated for the ShareGroupSnapshotMember in 

1667 the database. This list may be empty or None. 

1668 """ 

1669 LOG.debug('Attempting to create a share group snapshot %s.', 

1670 snap_dict['id']) 

1671 

1672 snapshot_members = snap_dict.get('share_group_snapshot_members', []) 

1673 if not self._stats.get('snapshot_support'): 

1674 raise exception.ShareGroupSnapshotNotSupported( 

1675 share_group=snap_dict['share_group_id']) 

1676 elif not snapshot_members: 

1677 LOG.warning('No shares in share group to create snapshot.') 

1678 return None, None 

1679 else: 

1680 share_snapshots = [] 

1681 snapshot_members_updates = [] 

1682 for member in snapshot_members: 

1683 share_snapshot = { 

1684 'snapshot_id': member['share_group_snapshot_id'], 

1685 'share_id': member['share_id'], 

1686 'share_instance_id': member['share']['id'], 

1687 'id': member['id'], 

1688 'share': member['share'], 

1689 'share_name': member['share_name'], 

1690 'name': member['name'], 

1691 'size': member['share']['size'], 

1692 'share_size': member['share']['size'], 

1693 'share_proto': member['share']['share_proto'], 

1694 'provider_location': None, 

1695 } 

1696 try: 

1697 member_update = self.create_snapshot( 

1698 context, share_snapshot, share_server=share_server) 

1699 if member_update: 

1700 member_update['id'] = member['id'] 

1701 snapshot_members_updates.append(member_update) 

1702 share_snapshots.append(share_snapshot) 

1703 except exception.ManilaException as e: 

1704 msg = ('Could not create share group snapshot. Failed ' 

1705 'to create share snapshot %(snap)s for ' 

1706 'share %(share)s.') 

1707 LOG.exception(msg, { 

1708 'snap': share_snapshot['id'], 

1709 'share': share_snapshot['share_id'] 

1710 }) 

1711 

1712 # clean up any share snapshots previously created 

1713 LOG.debug( 

1714 'Attempting to clean up snapshots due to failure.') 

1715 for share_snapshot in share_snapshots: 

1716 self._cleanup_group_share_snapshot( 

1717 context, share_snapshot, share_server) 

1718 raise e 

1719 

1720 LOG.debug('Successfully created share group snapshot %s.', 

1721 snap_dict['id']) 

1722 return None, snapshot_members_updates 

1723 

1724 def delete_share_group_snapshot(self, context, snap_dict, 

1725 share_server=None): 

1726 """Delete a share group snapshot 

1727 

1728 :param context: 

1729 :param snap_dict: The share group snapshot details 

1730 EXAMPLE: 

1731 .. code:: 

1732 

1733 { 

1734 'status': 'available', 

1735 'project_id': '13c0be6290934bd98596cfa004650049', 

1736 'user_id': 'a0314a441ca842019b0952224aa39192', 

1737 'description': None, 

1738 'deleted': '0', 

1739 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1740 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1741 'share_group_id': 'some_fake_uuid', 

1742 'share_group_snapshot_members': [ 

1743 { 

1744 'status': 'available', 

1745 'share_type_id': 'some_fake_uuid', 

1746 'share_id': 'some_fake_uuid', 

1747 'user_id': 'a0314a441ca842019b0952224aa39192', 

1748 'deleted': 'False', 

1749 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1750 'share': <models.Share>, 

1751 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1752 'share_proto': 'NFS', 

1753 'share_name':'share_some_fake_uuid', 

1754 'name': 'share-snapshot-some_fake_uuid', 

1755 'project_id': '13c0be6290934bd98596cfa004650049', 

1756 'share_group_snapshot_id': 'some_fake_uuid', 

1757 'deleted_at': None, 

1758 'id': 'some_fake_uuid', 

1759 'size': 1, 

1760 'provider_location': 'fake_provider_location_value', 

1761 } 

1762 ], 

1763 'deleted_at': None, 

1764 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a', 

1765 'name': None 

1766 } 

1767 :return: (share_group_snapshot_update, member_update_list) 

1768 share_group_snapshot_update - a dict containing any values 

1769 to be updated for the ShareGroupSnapshot in the database. 

1770 This value may be None. 

1771 """ 

1772 snapshot_members = snap_dict.get('share_group_snapshot_members', []) 

1773 LOG.debug('Deleting share group snapshot %s.', snap_dict['id']) 

1774 for member in snapshot_members: 

1775 share_snapshot = { 

1776 'snapshot_id': member['share_group_snapshot_id'], 

1777 'share_id': member['share_id'], 

1778 'share_instance_id': member['share']['id'], 

1779 'id': member['id'], 

1780 'share': member['share'], 

1781 'size': member['share']['size'], 

1782 'share_name': member['share_name'], 

1783 'name': member['name'], 

1784 'share_size': member['share']['size'], 

1785 'share_proto': member['share']['share_proto'], 

1786 'provider_location': member['provider_location'], 

1787 } 

1788 self.delete_snapshot( 

1789 context, share_snapshot, share_server=share_server) 

1790 

1791 LOG.debug('Deleted share group snapshot %s.', snap_dict['id']) 

1792 return None, None 

1793 

1794 def _collate_share_group_snapshot_info(self, share_group_dict, 

1795 share_group_snapshot_dict): 

1796 """Collate the data for a clone of the SG snapshot. 

1797 

1798 Given two data structures, a share group snapshot ( 

1799 share_group_snapshot_dict) and a new share to be cloned from 

1800 the snapshot (share_group_dict), match up both structures into a list 

1801 of dicts (share & snapshot) suitable for use by existing method 

1802 that clones individual share snapshots. 

1803 """ 

1804 clone_list = [] 

1805 for share in share_group_dict['shares']: 

1806 clone_info = {'share': share} 

1807 for share_group_snapshot_member in share_group_snapshot_dict[ 1807 ↛ 1814line 1807 didn't jump to line 1814 because the loop on line 1807 didn't complete

1808 'share_group_snapshot_members']: 

1809 if (share['source_share_group_snapshot_member_id'] == 

1810 share_group_snapshot_member['id']): 

1811 clone_info['snapshot'] = share_group_snapshot_member 

1812 break 

1813 

1814 if len(clone_info) != 2: 1814 ↛ 1815line 1814 didn't jump to line 1815 because the condition on line 1814 was never true

1815 msg = _( 

1816 "Invalid data supplied for creating share group from " 

1817 "share group snapshot " 

1818 "%s.") % share_group_snapshot_dict['id'] 

1819 raise exception.InvalidShareGroup(reason=msg) 

1820 

1821 clone_list.append(clone_info) 

1822 

1823 return clone_list 

1824 

1825 def get_periodic_hook_data(self, context, share_instances): 

1826 """Dedicated for update/extend of data for existing share instances. 

1827 

1828 Redefine this method in share driver to be able to update/change/extend 

1829 share instances data that will be used by periodic hook action. 

1830 One of possible updates is add-on of "automount" CLI commands for each 

1831 share instance for case of notification is enabled using 'hook' 

1832 approach. 

1833 

1834 :param context: Current context 

1835 :param share_instances: share instances list provided by share manager 

1836 :return: list of share instances. 

1837 """ 

1838 return share_instances 

1839 

1840 def create_replica(self, context, replica_list, new_replica, 

1841 access_rules, replica_snapshots, share_server=None): 

1842 """Replicate the active replica to a new replica on this backend. 

1843 

1844 .. note:: 

1845 This call is made on the host that the new replica is being created 

1846 upon. 

1847 

1848 :param context: Current context 

1849 :param replica_list: List of all replicas for a particular share. 

1850 This list also contains the replica to be created. The 'active' 

1851 replica will have its 'replica_state' attr set to 'active'. 

1852 

1853 Example:: 

1854 

1855 [ 

1856 { 

1857 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

1858 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

1859 'replica_state': 'in_sync', 

1860 ... 

1861 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

1862 'share_server': <models.ShareServer> or None, 

1863 }, 

1864 { 

1865 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

1866 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

1867 'replica_state': 'active', 

1868 ... 

1869 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

1870 'share_server': <models.ShareServer> or None, 

1871 }, 

1872 { 

1873 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

1874 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

1875 'replica_state': 'in_sync', 

1876 ... 

1877 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87', 

1878 'share_server': <models.ShareServer> or None, 

1879 }, 

1880 ... 

1881 ] 

1882 

1883 :param new_replica: The share replica dictionary. 

1884 

1885 Example:: 

1886 

1887 { 

1888 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

1889 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

1890 'deleted': False, 

1891 'host': 'openstack2@cmodeSSVMNFS2', 

1892 'status': 'creating', 

1893 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1894 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

1895 'terminated_at': None, 

1896 'replica_state': 'out_of_sync', 

1897 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f', 

1898 'export_locations': [ 

1899 models.ShareInstanceExportLocations, 

1900 ], 

1901 'access_rules_status': 'out_of_sync', 

1902 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f', 

1903 'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a', 

1904 'share_server': <models.ShareServer> or None, 

1905 } 

1906 

1907 :param access_rules: A list of access rules. 

1908 These are rules that other instances of the share already obey. 

1909 Drivers are expected to apply access rules to the new replica or 

1910 disregard access rules that don't apply. 

1911 

1912 Example:: 

1913 

1914 [ 

1915 { 

1916 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676', 

1917 'deleted' = False, 

1918 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

1919 'access_type' = 'ip', 

1920 'access_to' = '172.16.20.1', 

1921 'access_level' = 'rw', 

1922 } 

1923 ] 

1924 

1925 :param replica_snapshots: List of dictionaries of snapshot instances. 

1926 This includes snapshot instances of every snapshot of the share 

1927 whose 'aggregate_status' property was reported to be 'available' 

1928 when the share manager initiated this request. Each list member 

1929 will have two sub dictionaries: 'active_replica_snapshot' and 

1930 'share_replica_snapshot'. The 'active' replica snapshot corresponds 

1931 to the instance of the snapshot on any of the 'active' replicas of 

1932 the share while share_replica_snapshot corresponds to the snapshot 

1933 instance for the specific replica that will need to exist on the 

1934 new share replica that is being created. The driver needs to ensure 

1935 that this snapshot instance is truly available before transitioning 

1936 the replica from 'out_of_sync' to 'in_sync'. Snapshots instances 

1937 for snapshots that have an 'aggregate_status' of 'creating' or 

1938 'deleting' will be polled for in the ``update_replicated_snapshot`` 

1939 method. 

1940 

1941 Example:: 

1942 

1943 [ 

1944 { 

1945 'active_replica_snapshot': { 

1946 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e', 

1947 'share_instance_id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

1948 'status': 'available', 

1949 'provider_location': '/newton/share-snapshot-10e49c3e-aca9', 

1950 ... 

1951 }, 

1952 'share_replica_snapshot': { 

1953 'id': '', 

1954 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

1955 'status': 'available', 

1956 'provider_location': None, 

1957 ... 

1958 }, 

1959 } 

1960 ] 

1961 

1962 :param share_server: <models.ShareServer> or None 

1963 Share server of the replica being created. 

1964 :return: None or a dictionary. 

1965 The dictionary can contain export_locations replica_state and 

1966 access_rules_status. export_locations is a list of paths and 

1967 replica_state is one of 'active', 'in_sync', 'out_of_sync' or 

1968 'error'. 

1969 

1970 .. important:: 

1971 

1972 A backend supporting 'writable' type replication should return 

1973 'active' as the replica_state. 

1974 

1975 Export locations should be in the same format as returned during the 

1976 ``create_share`` call. 

1977 

1978 Example:: 

1979 

1980 { 

1981 'export_locations': [ 

1982 { 

1983 'path': '172.16.20.22/sample/export/path', 

1984 'is_admin_only': False, 

1985 'metadata': {'some_key': 'some_value'}, 

1986 }, 

1987 ], 

1988 'replica_state': 'in_sync', 

1989 'access_rules_status': 'in_sync', 

1990 } 

1991 

1992 """ 

1993 raise NotImplementedError() 

1994 

1995 def delete_replica(self, context, replica_list, replica_snapshots, 

1996 replica, share_server=None): 

1997 """Delete a replica. 

1998 

1999 .. note:: 

2000 This call is made on the host that hosts the replica being 

2001 deleted. 

2002 

2003 :param context: Current context 

2004 :param replica_list: List of all replicas for a particular share 

2005 This list also contains the replica to be deleted. The 'active' 

2006 replica will have its 'replica_state' attr set to 'active'. 

2007 

2008 Example:: 

2009 

2010 [ 

2011 { 

2012 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2013 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2014 'replica_state': 'in_sync', 

2015 ... 

2016 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2017 'share_server': <models.ShareServer> or None, 

2018 }, 

2019 { 

2020 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2021 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2022 'replica_state': 'active', 

2023 ... 

2024 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

2025 'share_server': <models.ShareServer> or None, 

2026 }, 

2027 { 

2028 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

2029 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2030 'replica_state': 'in_sync', 

2031 ... 

2032 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87', 

2033 'share_server': <models.ShareServer> or None, 

2034 }, 

2035 ... 

2036 ] 

2037 

2038 :param replica: Dictionary of the share replica being deleted. 

2039 

2040 Example:: 

2041 

2042 { 

2043 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

2044 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2045 'deleted': False, 

2046 'host': 'openstack2@cmodeSSVMNFS2', 

2047 'status': 'available', 

2048 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2049 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2050 'terminated_at': None, 

2051 'replica_state': 'in_sync', 

2052 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f', 

2053 'export_locations': [ 

2054 models.ShareInstanceExportLocations 

2055 ], 

2056 'access_rules_status': 'out_of_sync', 

2057 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f', 

2058 'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f', 

2059 'share_server': <models.ShareServer> or None, 

2060 } 

2061 

2062 :param replica_snapshots: List of dictionaries of snapshot instances. 

2063 The dict contains snapshot instances that are associated with the 

2064 share replica being deleted. 

2065 No model updates to snapshot instances are possible in this method. 

2066 The driver should return when the cleanup is completed on the 

2067 backend for both, the snapshots and the replica itself. Drivers 

2068 must handle situations where the snapshot may not yet have 

2069 finished 'creating' on this replica. 

2070 

2071 Example:: 

2072 

2073 [ 

2074 { 

2075 'id': '89dafd00-0999-4d23-8614-13eaa6b02a3b', 

2076 'snapshot_id': '3ce1caf7-0945-45fd-a320-714973e949d3', 

2077 'status: 'available', 

2078 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f' 

2079 ... 

2080 }, 

2081 { 

2082 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e', 

2083 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2084 'status: 'creating', 

2085 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f' 

2086 ... 

2087 }, 

2088 ... 

2089 ] 

2090 

2091 :param share_server: <models.ShareServer> or None 

2092 Share server of the replica to be deleted. 

2093 :return: None. 

2094 :raises: Exception. 

2095 Any exception raised will set the share replica's 'status' and 

2096 'replica_state' attributes to 'error_deleting'. It will not affect 

2097 snapshots belonging to this replica. 

2098 """ 

2099 raise NotImplementedError() 

2100 

2101 def promote_replica(self, context, replica_list, replica, access_rules, 

2102 share_server=None, quiesce_wait_time=None): 

2103 """Promote a replica to 'active' replica state. 

2104 

2105 .. note:: 

2106 This call is made on the host that hosts the replica being 

2107 promoted. 

2108 

2109 :param context: Current context 

2110 :param replica_list: List of all replicas for a particular share 

2111 This list also contains the replica to be promoted. The 'active' 

2112 replica will have its 'replica_state' attr set to 'active'. 

2113 

2114 Example:: 

2115 

2116 [ 

2117 { 

2118 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2119 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2120 'replica_state': 'in_sync', 

2121 ... 

2122 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2123 'share_server': <models.ShareServer> or None, 

2124 }, 

2125 { 

2126 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2127 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2128 'replica_state': 'active', 

2129 ... 

2130 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

2131 'share_server': <models.ShareServer> or None, 

2132 }, 

2133 { 

2134 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

2135 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2136 'replica_state': 'in_sync', 

2137 ... 

2138 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87', 

2139 'share_server': <models.ShareServer> or None, 

2140 }, 

2141 ... 

2142 ] 

2143 

2144 :param replica: Dictionary of the replica to be promoted. 

2145 

2146 Example:: 

2147 

2148 { 

2149 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

2150 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2151 'deleted': False, 

2152 'host': 'openstack2@cmodeSSVMNFS2', 

2153 'status': 'available', 

2154 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2155 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2156 'terminated_at': None, 

2157 'replica_state': 'in_sync', 

2158 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f', 

2159 'export_locations': [ 

2160 models.ShareInstanceExportLocations 

2161 ], 

2162 'access_rules_status': 'in_sync', 

2163 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f', 

2164 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87', 

2165 'share_server': <models.ShareServer> or None, 

2166 } 

2167 

2168 :param access_rules: A list of access rules 

2169 These access rules are obeyed by other instances of the share 

2170 

2171 Example:: 

2172 

2173 [ 

2174 { 

2175 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676', 

2176 'deleted' = False, 

2177 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2178 'access_type' = 'ip', 

2179 'access_to' = '172.16.20.1', 

2180 'access_level' = 'rw', 

2181 } 

2182 ] 

2183 

2184 :param share_server: <models.ShareServer> or None 

2185 Share server of the replica to be promoted. 

2186 :param quiesce_wait_time: time in seconds or None 

2187 Share replica promote quiesce wait time. 

2188 :return: updated_replica_list or None. 

2189 The driver can return the updated list as in the request 

2190 parameter. Changes that will be updated to the Database are: 

2191 'export_locations', 'access_rules_status' and 'replica_state'. 

2192 :raises: Exception. 

2193 This can be any exception derived from BaseException. This is 

2194 re-raised by the manager after some necessary cleanup. If the 

2195 driver raises an exception during promotion, it is assumed that 

2196 all of the replicas of the share are in an inconsistent state. 

2197 Recovery is only possible through the periodic update call and/or 

2198 administrator intervention to correct the 'status' of the affected 

2199 replicas if they become healthy again. 

2200 """ 

2201 raise NotImplementedError() 

2202 

2203 def update_replica_state(self, context, replica_list, replica, 

2204 access_rules, replica_snapshots, 

2205 share_server=None): 

2206 """Update the replica_state of a replica. 

2207 

2208 .. note:: 

2209 This call is made on the host which hosts the replica being 

2210 updated. 

2211 

2212 Drivers should fix replication relationships that were broken if 

2213 possible inside this method. 

2214 

2215 This method is called periodically by the share manager; and 

2216 whenever requested by the administrator through the 'resync' API. 

2217 

2218 :param context: Current context 

2219 :param replica_list: List of all replicas for a particular share 

2220 This list also contains the replica to be updated. The 'active' 

2221 replica will have its 'replica_state' attr set to 'active'. 

2222 

2223 Example:: 

2224 

2225 [ 

2226 { 

2227 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2228 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2229 'replica_state': 'in_sync', 

2230 ... 

2231 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2232 'share_server': <models.ShareServer> or None, 

2233 }, 

2234 { 

2235 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2236 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2237 'replica_state': 'active', 

2238 ... 

2239 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

2240 'share_server': <models.ShareServer> or None, 

2241 }, 

2242 { 

2243 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f', 

2244 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2245 'replica_state': 'in_sync', 

2246 ... 

2247 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87', 

2248 'share_server': <models.ShareServer> or None, 

2249 }, 

2250 ... 

2251 ] 

2252 

2253 :param replica: Dictionary of the replica being updated 

2254 Replica state will always be 'in_sync', 'out_of_sync', or 'error'. 

2255 Replicas in 'active' state will not be passed via this parameter. 

2256 

2257 Example:: 

2258 

2259 { 

2260 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2261 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2262 'deleted': False, 

2263 'host': 'openstack2@cmodeSSVMNFS1', 

2264 'status': 'available', 

2265 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2266 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2267 'terminated_at': None, 

2268 'replica_state': 'in_sync', 

2269 'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80', 

2270 'export_locations': [ 

2271 models.ShareInstanceExportLocations, 

2272 ], 

2273 'access_rules_status': 'in_sync', 

2274 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f', 

2275 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2276 } 

2277 

2278 :param access_rules: A list of access rules 

2279 These access rules are obeyed by other instances of the share. The 

2280 driver could attempt to sync on any un-applied access_rules. 

2281 

2282 Example:: 

2283 

2284 [ 

2285 { 

2286 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676', 

2287 'deleted' = False, 

2288 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2289 'access_type' = 'ip', 

2290 'access_to' = '172.16.20.1', 

2291 'access_level' = 'rw', 

2292 } 

2293 ] 

2294 

2295 :param replica_snapshots: List of dictionaries of snapshot instances. 

2296 This includes snapshot instances of every snapshot of the share 

2297 whose 'aggregate_status' property was reported to be 'available' 

2298 when the share manager initiated this request. Each list member 

2299 will have two sub dictionaries: 'active_replica_snapshot' and 

2300 'share_replica_snapshot'. The 'active' replica snapshot corresponds 

2301 to the instance of the snapshot on any of the 'active' replicas of 

2302 the share while share_replica_snapshot corresponds to the snapshot 

2303 instance for the specific replica being updated. The driver needs 

2304 to ensure that this snapshot instance is truly available before 

2305 transitioning from 'out_of_sync' to 'in_sync'. Snapshots instances 

2306 for snapshots that have an 'aggregate_status' of 'creating' or 

2307 'deleting' will be polled for in the update_replicated_snapshot 

2308 method. 

2309 

2310 Example:: 

2311 

2312 [ 

2313 { 

2314 'active_replica_snapshot': { 

2315 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e', 

2316 'share_instance_id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2317 'status': 'available', 

2318 'provider_location': '/newton/share-snapshot-10e49c3e-aca9', 

2319 ... 

2320 }, 

2321 'share_replica_snapshot': { 

2322 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2323 'share_instance_id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2324 'status': 'creating', 

2325 'provider_location': None, 

2326 ... 

2327 }, 

2328 } 

2329 ] 

2330 

2331 :param share_server: <models.ShareServer> or None 

2332 :return: replica_state: a str value denoting the replica_state. 

2333 Valid values are 'in_sync' and 'out_of_sync' or None (to leave the 

2334 current replica_state unchanged). 

2335 """ 

2336 raise NotImplementedError() 

2337 

2338 def create_replicated_snapshot(self, context, replica_list, 

2339 replica_snapshots, 

2340 share_server=None): 

2341 """Create a snapshot on active instance and update across the replicas. 

2342 

2343 .. note:: 

2344 This call is made on the 'active' replica's host. Drivers are 

2345 expected to transfer the snapshot created to the respective 

2346 replicas. 

2347 

2348 The driver is expected to return model updates to the share manager. 

2349 If it was able to confirm the creation of any number of the snapshot 

2350 instances passed in this interface, it can set their status to 

2351 'available' as a cue for the share manager to set the progress attr 

2352 to '100%'. 

2353 

2354 :param context: Current context 

2355 :param replica_list: List of all replicas for a particular share 

2356 The 'active' replica will have its 'replica_state' attr set to 

2357 'active'. 

2358 

2359 Example:: 

2360 

2361 [ 

2362 { 

2363 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2364 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2365 'replica_state': 'in_sync', 

2366 ... 

2367 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2368 'share_server': <models.ShareServer> or None, 

2369 }, 

2370 { 

2371 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2372 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2373 'replica_state': 'active', 

2374 ... 

2375 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

2376 'share_server': <models.ShareServer> or None, 

2377 }, 

2378 ... 

2379 ] 

2380 

2381 :param replica_snapshots: List of dictionaries of snapshot instances. 

2382 These snapshot instances track the snapshot across the replicas. 

2383 All the instances will have their status attribute set to 

2384 'creating'. 

2385 

2386 Example:: 

2387 

2388 [ 

2389 { 

2390 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a', 

2391 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2392 'status: 'creating', 

2393 'progress': '0%', 

2394 ... 

2395 }, 

2396 { 

2397 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e', 

2398 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2399 'status: 'creating', 

2400 'progress': '0%', 

2401 ... 

2402 }, 

2403 ... 

2404 ] 

2405 

2406 :param share_server: <models.ShareServer> or None 

2407 :return: List of dictionaries of snapshot instances. 

2408 The dictionaries can contain values that need to be updated on the 

2409 database for the snapshot instances being created. 

2410 :raises: Exception. 

2411 Any exception in this method will set all instances to 'error'. 

2412 """ 

2413 raise NotImplementedError() 

2414 

2415 def revert_to_replicated_snapshot(self, context, active_replica, 

2416 replica_list, active_replica_snapshot, 

2417 replica_snapshots, share_access_rules, 

2418 snapshot_access_rules, 

2419 share_server=None): 

2420 """Reverts a replicated share (in place) to the specified snapshot. 

2421 

2422 .. note:: 

2423 This call is made on the 'active' replica's host, since drivers may 

2424 not be able to revert snapshots on individual replicas. 

2425 

2426 Does not delete the share snapshot. The share and snapshot must both 

2427 be 'available' for the restore to be attempted. The snapshot must be 

2428 the most recent one taken by Manila; the API layer performs this check 

2429 so the driver doesn't have to. 

2430 

2431 The share must be reverted in place to the contents of the snapshot. 

2432 Application admins should quiesce or otherwise prepare the application 

2433 for the shared file system contents to change suddenly. 

2434 

2435 :param context: Current context 

2436 :param active_replica: The current active replica 

2437 :param replica_list: List of all replicas for a particular share 

2438 The 'active' replica will have its 'replica_state' attr set to 

2439 'active' and its 'status' set to 'reverting'. 

2440 :param active_replica_snapshot: snapshot to be restored 

2441 :param replica_snapshots: List of dictionaries of snapshot instances. 

2442 These snapshot instances track the snapshot across the replicas. 

2443 The snapshot of the active replica to be restored with have its 

2444 status attribute set to 'restoring'. 

2445 :param share_access_rules: List of access rules for the affected share. 

2446 :param snapshot_access_rules: List of access rules for the affected 

2447 snapshot. 

2448 :param share_server: Optional -- Share server model 

2449 """ 

2450 raise NotImplementedError() 

2451 

2452 def delete_replicated_snapshot(self, context, replica_list, 

2453 replica_snapshots, share_server=None): 

2454 """Delete a snapshot by deleting its instances across the replicas. 

2455 

2456 .. note:: 

2457 This call is made on the 'active' replica's host, since 

2458 drivers may not be able to delete the snapshot from an individual 

2459 replica. 

2460 

2461 The driver is expected to return model updates to the share manager. 

2462 If it was able to confirm the removal of any number of the snapshot 

2463 instances passed in this interface, it can set their status to 

2464 'deleted' as a cue for the share manager to clean up that instance 

2465 from the database. 

2466 

2467 :param context: Current context 

2468 :param replica_list: List of all replicas for a particular share 

2469 The 'active' replica will have its 'replica_state' attr set to 

2470 'active'. 

2471 

2472 Example:: 

2473 

2474 [ 

2475 { 

2476 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2477 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2478 'replica_state': 'in_sync', 

2479 ... 

2480 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2481 'share_server': <models.ShareServer> or None, 

2482 }, 

2483 { 

2484 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2485 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2486 'replica_state': 'active', 

2487 ... 

2488 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

2489 'share_server': <models.ShareServer> or None, 

2490 }, 

2491 ... 

2492 ] 

2493 

2494 :param replica_snapshots: List of dictionaries of snapshot instances. 

2495 These snapshot instances track the snapshot across the replicas. 

2496 All the instances will have their status attribute set to 

2497 'deleting'. 

2498 

2499 Example:: 

2500 

2501 [ 

2502 { 

2503 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a', 

2504 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2505 'status': 'deleting', 

2506 'progress': '100%', 

2507 ... 

2508 }, 

2509 { 

2510 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e', 

2511 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2512 'status: 'deleting', 

2513 'progress': '100%', 

2514 ... 

2515 }, 

2516 ... 

2517 ] 

2518 

2519 :param share_server: <models.ShareServer> or None 

2520 :return: List of dictionaries of snapshot instances. 

2521 The dictionaries can contain values that need to be updated on the 

2522 database for the snapshot instances being deleted. To confirm the 

2523 deletion of the snapshot instance, set the 'status' attribute of 

2524 the instance to 'deleted' (constants.STATUS_DELETED) 

2525 :raises: Exception. 

2526 Any exception in this method will set the status attribute of all 

2527 snapshot instances to 'error_deleting'. 

2528 """ 

2529 raise NotImplementedError() 

2530 

2531 def update_replicated_snapshot(self, context, replica_list, 

2532 share_replica, replica_snapshots, 

2533 replica_snapshot, share_server=None): 

2534 """Update the status of a snapshot instance that lives on a replica. 

2535 

2536 .. note:: 

2537 For DR and Readable styles of replication, this call is made on 

2538 the replica's host and not the 'active' replica's host. 

2539 

2540 This method is called periodically by the share manager. It will 

2541 query for snapshot instances that track the parent snapshot across 

2542 non-'active' replicas. Drivers can expect the status of the instance to 

2543 be 'creating' or 'deleting'. If the driver sees that a snapshot 

2544 instance has been removed from the replica's backend and the 

2545 instance status was set to 'deleting', it is expected to raise a 

2546 SnapshotResourceNotFound exception. All other exceptions will set the 

2547 snapshot instance status to 'error'. If the instance was not in 

2548 'deleting' state, raising a SnapshotResourceNotFound will set the 

2549 instance status to 'error'. 

2550 

2551 :param context: Current context 

2552 :param replica_list: List of all replicas for a particular share 

2553 The 'active' replica will have its 'replica_state' attr set to 

2554 'active'. 

2555 

2556 Example:: 

2557 

2558 [ 

2559 { 

2560 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2561 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2562 'replica_state': 'in_sync', 

2563 ... 

2564 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2565 'share_server': <models.ShareServer> or None, 

2566 }, 

2567 { 

2568 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af', 

2569 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2570 'replica_state': 'active', 

2571 ... 

2572 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094', 

2573 'share_server': <models.ShareServer> or None, 

2574 }, 

2575 ... 

2576 ] 

2577 

2578 :param share_replica: Share replica dictionary. 

2579 This replica is associated with the snapshot instance whose 

2580 status is being updated. Replicas in 'active' replica_state will 

2581 not be passed via this parameter. 

2582 

2583 Example:: 

2584 

2585 { 

2586 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2587 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f', 

2588 'deleted': False, 

2589 'host': 'openstack2@cmodeSSVMNFS1', 

2590 'status': 'available', 

2591 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2592 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58), 

2593 'terminated_at': None, 

2594 'replica_state': 'in_sync', 

2595 'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80', 

2596 'export_locations': [ 

2597 models.ShareInstanceExportLocations, 

2598 ], 

2599 'access_rules_status': 'in_sync', 

2600 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f', 

2601 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05', 

2602 } 

2603 

2604 :param replica_snapshots: List of dictionaries of snapshot instances. 

2605 These snapshot instances track the snapshot across the replicas. 

2606 This will include the snapshot instance being updated as well. 

2607 

2608 Example:: 

2609 

2610 [ 

2611 { 

2612 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a', 

2613 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2614 ... 

2615 }, 

2616 { 

2617 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e', 

2618 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2619 ... 

2620 }, 

2621 ... 

2622 ] 

2623 

2624 :param replica_snapshot: Dictionary of the snapshot instance. 

2625 This is the instance to be updated. It will be in 'creating' or 

2626 'deleting' state when sent via this parameter. 

2627 

2628 Example:: 

2629 

2630 { 

2631 'name': 'share-snapshot-18825630-574f-4912-93bb-af4611ef35a2', 

2632 'share_id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2633 'share_name': 'share-d487b88d-e428-4230-a465-a800c2cce5f8', 

2634 'status': 'creating', 

2635 'id': '18825630-574f-4912-93bb-af4611ef35a2', 

2636 'deleted': False, 

2637 'created_at': datetime.datetime(2016, 8, 3, 0, 5, 58), 

2638 'share': <models.ShareInstance>, 

2639 'updated_at': datetime.datetime(2016, 8, 3, 0, 5, 58), 

2640 'share_instance_id': 'd487b88d-e428-4230-a465-a800c2cce5f8', 

2641 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40', 

2642 'progress': '0%', 

2643 'deleted_at': None, 

2644 'provider_location': None, 

2645 } 

2646 

2647 :param share_server: <models.ShareServer> or None 

2648 :return: replica_snapshot_model_update: a dictionary. 

2649 The dictionary must contain values that need to be updated on the 

2650 database for the snapshot instance that represents the snapshot on 

2651 the replica. 

2652 :raises: exception.SnapshotResourceNotFound 

2653 Raise this exception for snapshots that are not found on the 

2654 backend and their status was 'deleting'. 

2655 """ 

2656 raise NotImplementedError() 

2657 

2658 def get_filter_function(self, pool=None): 

2659 """Get filter_function string. 

2660 

2661 Returns either the string from the driver instance or global section 

2662 in manila.conf. If nothing is specified in manila.conf, then try to 

2663 find the default filter_function. When None is returned the scheduler 

2664 will always pass the driver instance. 

2665 

2666 :param pool: pool name to get the filter or None 

2667 :return: a filter_function string or None 

2668 """ 

2669 ret_function = self.configuration.filter_function 

2670 if not ret_function: 

2671 ret_function = CONF.filter_function 

2672 if not ret_function: 

2673 kwargs = {'pool': pool} if pool else {} 

2674 # pylint: disable=assignment-from-none 

2675 ret_function = self.get_default_filter_function(**kwargs) 

2676 # pylint: enable=assignment-from-none 

2677 return ret_function 

2678 

2679 def get_goodness_function(self): 

2680 """Get good_function string. 

2681 

2682 Returns either the string from the driver instance or global section 

2683 in manila.conf. If nothing is specified in manila.conf, then try to 

2684 find the default goodness_function. When None is returned the scheduler 

2685 will give the lowest score to the driver instance. 

2686 

2687 :return: a goodness_function string or None 

2688 """ 

2689 ret_function = self.configuration.goodness_function 

2690 if not ret_function: 

2691 ret_function = CONF.goodness_function 

2692 if not ret_function: 

2693 # pylint: disable=assignment-from-none 

2694 ret_function = self.get_default_goodness_function() 

2695 # pylint: enable=assignment-from-none 

2696 return ret_function 

2697 

2698 def get_default_filter_function(self, pool=None): 

2699 """Get the default filter_function string. 

2700 

2701 Each driver could overwrite the method to return a well-known 

2702 default string if it is available. 

2703 

2704 :param pool: pool name to get the filter or None 

2705 :return: None 

2706 """ 

2707 return None 

2708 

2709 def get_default_goodness_function(self): 

2710 """Get the default goodness_function string. 

2711 

2712 Each driver could overwrite the method to return a well-known 

2713 default string if it is available. 

2714 

2715 :return: None 

2716 """ 

2717 return None 

2718 

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

2720 add_rules, delete_rules, share_server=None): 

2721 """Update access rules for given snapshot. 

2722 

2723 ``access_rules`` contains all access_rules that need to be on the 

2724 share. If the driver can make bulk access rule updates, it can 

2725 safely ignore the ``add_rules`` and ``delete_rules`` parameters. 

2726 

2727 If the driver cannot make bulk access rule changes, it can rely on 

2728 new rules to be present in ``add_rules`` and rules that need to be 

2729 removed to be present in ``delete_rules``. 

2730 

2731 When a rule in ``add_rules`` already exists in the back end, drivers 

2732 must not raise an exception. When a rule in ``delete_rules`` was never 

2733 applied, drivers must not raise an exception, or attempt to set the 

2734 rule to ``error`` state. 

2735 

2736 ``add_rules`` and ``delete_rules`` can be empty lists, in this 

2737 situation, drivers should ensure that the rules present in 

2738 ``access_rules`` are the same as those on the back end. 

2739 

2740 :param context: Current context 

2741 :param snapshot: Snapshot model with snapshot data. 

2742 :param access_rules: All access rules for given snapshot 

2743 :param add_rules: Empty List or List of access rules which should be 

2744 added. access_rules already contains these rules. 

2745 :param delete_rules: Empty List or List of access rules which should be 

2746 removed. access_rules doesn't contain these rules. 

2747 :param share_server: None or Share server model 

2748 """ 

2749 raise NotImplementedError() 

2750 

2751 def update_share_usage_size(self, context, shares): 

2752 """Invoked to get the usage size of given shares. 

2753 

2754 Driver can use this method to update the share usage size of 

2755 the shares. To do that, a dictionary of shares should be 

2756 returned. 

2757 :param shares: None or a list of all shares for updates. 

2758 :returns: An empty list or a list of dictionary of updates in the 

2759 following format. The value of "used_size" can be specified in GiB 

2760 units, as a floating point number:: 

2761 

2762 [ 

2763 { 

2764 'id': '09960614-8574-4e03-89cf-7cf267b0bd08', 

2765 'used_size': '200', 

2766 'gathered_at': datetime.datetime(2017, 8, 10, 15, 14, 6), 

2767 }, 

2768 ] 

2769 

2770 """ 

2771 LOG.debug("This backend does not support gathering 'used_size' of " 

2772 "shares created on it.") 

2773 return [] 

2774 

2775 def get_configured_ip_versions(self): 

2776 """"Get allowed IP versions. 

2777 

2778 The supported versions are returned with list, possible 

2779 values are: [4], [6], or [4, 6] 

2780 

2781 Drivers that assert ipv6_implemented = True must override 

2782 this method. If the returned list includes 4, then shares 

2783 created by this driver must have an IPv4 export location. 

2784 If the list includes 6, then shares created by the driver 

2785 must have an IPv6 export location. 

2786 

2787 Drivers should check that their storage controller actually 

2788 has IPv4/IPv6 enabled and configured properly. 

2789 """ 

2790 

2791 # For drivers that haven't implemented IPv6, assume legacy behavior 

2792 if not self.ipv6_implemented: 2792 ↛ 2795line 2792 didn't jump to line 2795 because the condition on line 2792 was always true

2793 return [4] 

2794 

2795 raise NotImplementedError() 

2796 

2797 def add_ip_version_capability(self, data): 

2798 """Add IP version support capabilities. 

2799 

2800 When DHSS is true, the capabilities are determined by driver 

2801 and configured network plugin. 

2802 When DHSS is false, the capabilities are determined by driver 

2803 only. 

2804 :param data: the capability dictionary 

2805 :returns: capability data 

2806 """ 

2807 self.ip_versions = self.get_configured_ip_versions() 

2808 if isinstance(self.ip_versions, list): 2808 ↛ 2811line 2808 didn't jump to line 2811 because the condition on line 2808 was always true

2809 self.ip_versions = set(self.ip_versions) 

2810 else: 

2811 self.ip_versions = set(list(self.ip_versions)) 

2812 

2813 if not self.ip_versions: 2813 ↛ 2814line 2813 didn't jump to line 2814 because the condition on line 2813 was never true

2814 LOG.error("Backend %s supports neither IPv4 nor IPv6.", 

2815 data['share_backend_name']) 

2816 

2817 if self.driver_handles_share_servers: 

2818 network_versions = self.network_api.enabled_ip_versions 

2819 self.ip_versions = self.ip_versions & network_versions 

2820 if not self.ip_versions: 

2821 LOG.error("The enabled IP version of the network plugin is " 

2822 "not compatible with the version supported by " 

2823 "backend %s.", data['share_backend_name']) 

2824 

2825 data['ipv4_support'] = (4 in self.ip_versions) 

2826 data['ipv6_support'] = (6 in self.ip_versions) 

2827 return data 

2828 

2829 def get_backend_info(self, context): 

2830 """Get driver and array configuration parameters. 

2831 

2832 Driver can use this method to get the special configuration info and 

2833 return for assessment. The share manager service uses this 

2834 assessment to invoke "ensure_shares" during service startup. 

2835 

2836 :returns: A dictionary containing driver-specific info. 

2837 

2838 Example:: 

2839 

2840 { 

2841 'version': '2.23' 

2842 'port': '80', 

2843 'logicalportip': '1.1.1.1', 

2844 ... 

2845 } 

2846 

2847 """ 

2848 raise NotImplementedError() 

2849 

2850 def get_optional_share_creation_data(self, share, share_server=None): 

2851 """Get info to set in shares after their creation. 

2852 

2853 Driver can use this method to get the special info and 

2854 return for assessment. The share manager service uses this 

2855 assessment to set this info to shares after the creation. 

2856 

2857 :returns: A dictionary containing driver-specific info. 

2858 

2859 Example:: 

2860 

2861 { 

2862 'metadata': {'__mount_options': 'fake_key=fake_val'} 

2863 ... 

2864 } 

2865 

2866 """ 

2867 return {} 

2868 

2869 def ensure_shares(self, context, shares): 

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

2871 

2872 Driver can use this method to update the "status" and/or list of 

2873 export locations of the shares if they change. To do that, 

2874 a dictionary of shares should be returned. In addition, the driver can 

2875 seek to "reapply_access_rules" (boolean) on a per-share basis. When 

2876 this property exists and is set to True, the share manager service 

2877 will invoke "update_access" with all the access rules from the 

2878 service database. 

2879 :shares: A list of all shares for updates. 

2880 :returns: None or a dictionary of updates in the format. 

2881 

2882 Example:: 

2883 

2884 { 

2885 '09960614-8574-4e03-89cf-7cf267b0bd08': { 

2886 'export_locations': [{...}, {...}], 

2887 'status': 'error', 

2888 'reapply_access_rules': False, 

2889 }, 

2890 

2891 '28f6eabb-4342-486a-a7f4-45688f0c0295': { 

2892 'export_locations': [{...}, {...}], 

2893 'status': 'available', 

2894 'reapply_access_rules': True, 

2895 }, 

2896 

2897 } 

2898 

2899 """ 

2900 raise NotImplementedError() 

2901 

2902 def get_share_server_network_info( 

2903 self, context, share_server, identifier, driver_options): 

2904 """Obtain network allocations used by share server. 

2905 

2906 :param context: Current context. 

2907 :param share_server: Share server model. 

2908 :param identifier: A driver-specific share server identifier 

2909 :param driver_options: Dictionary of driver options to assist managing 

2910 the share server 

2911 :return: A list containing IP addresses allocated in the backend. 

2912 

2913 Example:: 

2914 

2915 ['10.10.10.10', 'fd11::2000', '192.168.10.10'] 

2916 

2917 """ 

2918 raise NotImplementedError() 

2919 

2920 def manage_server(self, context, share_server, identifier, driver_options): 

2921 """Manage the share server and return compiled back end details. 

2922 

2923 :param context: Current context. 

2924 :param share_server: Share server model. 

2925 :param identifier: A driver-specific share server identifier 

2926 :param driver_options: Dictionary of driver options to assist managing 

2927 the share server 

2928 :return: Identifier and dictionary with back end details to be saved 

2929 in the database. 

2930 

2931 Example:: 

2932 

2933 'my_new_server_identifier',{'server_name': 'my_old_server'} 

2934 

2935 """ 

2936 raise NotImplementedError() 

2937 

2938 def unmanage_server(self, server_details, security_services=None): 

2939 """Unmanages the share server. 

2940 

2941 If a driver supports unmanaging of share servers, the driver must 

2942 override this method and return successfully. 

2943 

2944 :param server_details: share server backend details. 

2945 :param security_services: list of security services configured with 

2946 this share server. 

2947 """ 

2948 raise NotImplementedError() 

2949 

2950 def get_share_status(self, share, share_server=None): 

2951 """Invoked periodically to get the current status of a given share. 

2952 

2953 Driver can use this method to update the status of a share that is 

2954 still pending from other operations. 

2955 This method is expected to be called in a periodic interval set by the 

2956 'periodic_interval' configuration in seconds. 

2957 

2958 :param share: share to get updated status from. 

2959 :param share_server: share server model or None. 

2960 :returns: a dictionary of updates with the current share status, that 

2961 must be 'available', 'creating_from_snapshot' or 'error', a list of 

2962 export locations, if available, and a progress field which 

2963 indicates the completion of the share creation operation. 

2964 EXAMPLE:: 

2965 

2966 { 

2967 'status': 'available', 

2968 'export_locations': [{...}, {...}], 

2969 'progress': '50%' 

2970 } 

2971 

2972 :raises: ShareBackendException. 

2973 A ShareBackendException in this method will set the instance status 

2974 to 'error'. 

2975 """ 

2976 raise NotImplementedError() 

2977 

2978 def share_server_migration_start(self, context, src_share_server, 

2979 dest_share_server, shares, snapshots): 

2980 """Starts migration of a given share server to another host. 

2981 

2982 .. note:: 

2983 Is called in destination share server's backend to start migration. 

2984 

2985 Driver should implement this method if willing to perform a server 

2986 migration in driver-assisted way, useful when source share server's 

2987 backend driver is compatible with destination backend driver. This 

2988 method should start the migration procedure in the backend and return 

2989 immediately. 

2990 Following steps should be done in 'share_server_migration_continue'. 

2991 

2992 :param context: The 'context.RequestContext' object for the request. 

2993 :param src_share_server: Reference to the original share server. 

2994 :param dest_share_server: Reference to the share server to be used by 

2995 as destination. 

2996 :param shares: All shares in the source share server that should be 

2997 migrated. 

2998 :param snapshots: All snapshots in the source share server that should 

2999 be migrated. 

3000 :return: Dict with migration information to be set in the destination 

3001 share server. 

3002 

3003 Example:: 

3004 

3005 { 

3006 'backend_details': { 

3007 'migration_info_key': 'migration_info_value', 

3008 } 

3009 } 

3010 """ 

3011 raise NotImplementedError() 

3012 

3013 def share_server_migration_continue(self, context, src_share_server, 

3014 dest_share_server, shares, snapshots): 

3015 """Continues migration of a given share server to another host. 

3016 

3017 .. note:: 

3018 Is called in destination share server's backend to continue 

3019 migration. 

3020 

3021 Driver should implement this method to continue monitor the migration 

3022 progress in storage and perform following steps until 1st phase is 

3023 completed. 

3024 

3025 :param context: The 'context.RequestContext' object for the request. 

3026 :param src_share_server: Reference to the original share server. 

3027 :param dest_share_server: Reference to the share server to be used as 

3028 destination. 

3029 :param shares: All shares in the source share server that should be 

3030 migrated. 

3031 :param snapshots: All snapshots in the source share server that should 

3032 be migrated. 

3033 :return: Boolean value to indicate if 1st phase is finished. 

3034 """ 

3035 raise NotImplementedError() 

3036 

3037 def share_server_migration_get_progress(self, context, src_share_server, 

3038 dest_share_server, shares, 

3039 snapshots): 

3040 """Obtains progress of migration of a share server to another host. 

3041 

3042 .. note:: 

3043 Is called in destination share's backend to obtain migration 

3044 progress. 

3045 

3046 If possible, driver can implement a way to return migration progress 

3047 information. 

3048 

3049 :param context: The 'context.RequestContext' object for the request. 

3050 :param src_share_server: Reference to the original share server. 

3051 :param dest_share_server: Reference to the share server to be used as 

3052 destination. 

3053 :param shares: All shares in the source share server that should be 

3054 migrated. 

3055 :param snapshots: All snapshots in the source share server that should 

3056 be migrated. 

3057 :return: A dictionary with at least 'total_progress' field containing 

3058 the percentage value. 

3059 """ 

3060 raise NotImplementedError() 

3061 

3062 def share_server_migration_cancel(self, context, src_share_server, 

3063 dest_share_server, shares, snapshots): 

3064 """Cancels migration of a given share server to another host. 

3065 

3066 .. note:: 

3067 Is called in destination share server's backend to continue 

3068 migration. 

3069 

3070 If possible, driver can implement a way to cancel an in-progress 

3071 migration. 

3072 

3073 :param context: The 'context.RequestContext' object for the request. 

3074 :param src_share_server: Reference to the original share server. 

3075 :param dest_share_server: Reference to the share server to be used as 

3076 destination. 

3077 :param shares: All shares in the source share server that should be 

3078 migrated. 

3079 :param snapshots: All snapshots in the source share server that should 

3080 be migrated. 

3081 """ 

3082 raise NotImplementedError() 

3083 

3084 def share_server_migration_check_compatibility( 

3085 self, context, share_server, dest_host, old_share_network, 

3086 new_share_network, shares_request_spec): 

3087 """Checks destination compatibility for migration of a share server. 

3088 

3089 .. note:: 

3090 Is called in destination share server's backend to continue 

3091 migration. Can be called by an admin to check if a given host is 

3092 compatible or by the share manager to test compatibility with 

3093 destination backend. 

3094 

3095 Driver should check if it is compatible with destination backend so 

3096 driver-assisted migration can proceed. 

3097 

3098 :param context: The 'context.RequestContext' object for the request. 

3099 :param share_server: Share server model. 

3100 :param dest_host: Reference to the hos to be used by the migrated 

3101 share server. 

3102 :param old_share_network: Share network model where the source share 

3103 server is placed. 

3104 :param new_share_network: Share network model where the share 

3105 server is going to be migrated to. 

3106 :param shares_request_spec: Dict. Contains information about all shares 

3107 and share types that belong to the source share server. The drivers 

3108 can use this information to check if the capabilities match with 

3109 the destination backend and if there is available space to hold the 

3110 new share server and all its resource. 

3111 

3112 Example:: 

3113 

3114 { 

3115 'shares_size': 100, 

3116 'snapshots_size': 100, 

3117 'shares_req_spec': 

3118 [ 

3119 { 

3120 'share_properties': 

3121 { 

3122 'size': 10 

3123 'user_id': '2f5c1df4-5203-444e-b68e-1e60f3f26fc3' 

3124 'project_id': '0b82b278-51d6-4357-b273-0d7263982c31' 

3125 'snapshot_support': True 

3126 'create_share_from_snapshot_support': True 

3127 'revert_to_snapshot_support': False 

3128 'mount_snapshot_support': False 

3129 'share_proto': NFS 

3130 'share_type_id': '360e01c1-a4f7-4782-9676-dc013f1a2f21' 

3131 'is_public': False 

3132 'share_group_id': None 

3133 'source_share_group_snapshot_member_id': None 

3134 'snapshot_id': None 

3135 }, 

3136 'share_instance_properties': 

3137 { 

3138 'availability_zone_id': 

3139 '02377ad7-381c-4b25-a04c-6fd218f22a91', 

3140 'share_network_id': '691544aa-da83-4669-8522-22719f236e16', 

3141 'share_server_id': 'cd658413-d02c-4d1b-ac8a-b6b972e76bac', 

3142 'share_id': 'e42fec45-781e-4dcc-a4d2-44354ad5ae91', 

3143 'host': 'hostA@backend1#pool0', 

3144 'status': 'available', 

3145 }, 

3146 'share_type': 

3147 { 

3148 'id': '360e01c1-a4f7-4782-9676-dc013f1a2f21', 

3149 'name': 'dhss_false', 

3150 'is_public': False, 

3151 'extra_specs': 

3152 { 

3153 'driver_handles_share_servers': False, 

3154 } 

3155 }, 

3156 'share_id': e42fec45-781e-4dcc-a4d2-44354ad5ae91, 

3157 }, 

3158 ], 

3159 } 

3160 

3161 :return: A dictionary containing values indicating if destination 

3162 backend is compatible, if share can remain writable during 

3163 migration, if it can preserve all file metadata and if it can 

3164 perform migration of given share non-disruptively. 

3165 

3166 Example:: 

3167 

3168 { 

3169 'compatible': True, 

3170 'writable': True, 

3171 'nondisruptive': True, 

3172 'preserve_snapshots': True, 

3173 'migration_cancel': True, 

3174 'migration_get_progress': False, 

3175 } 

3176 

3177 """ 

3178 return { 

3179 'compatible': False, 

3180 'writable': False, 

3181 'nondisruptive': False, 

3182 'preserve_snapshots': False, 

3183 'migration_cancel': False, 

3184 'migration_get_progress': False, 

3185 } 

3186 

3187 def share_server_migration_complete(self, context, src_share_server, 

3188 dest_share_server, shares, snapshots, 

3189 new_network_info): 

3190 """Completes migration of a given share server to another host. 

3191 

3192 .. note:: 

3193 Is called in destination share server's backend to complete 

3194 migration. 

3195 

3196 If driver is implementing 2-phase migration, this method should 

3197 perform the disruptive tasks related to the 2nd phase of migration, 

3198 thus completing it. Driver should also delete all original data from 

3199 source backend. 

3200 

3201 It expected that all shares and snapshots will be available at the 

3202 destination share server in the end of the migration complete and all 

3203 updates provided in the returned model update. 

3204 

3205 :param context: The 'context.RequestContext' object for the request. 

3206 :param src_share_server: Reference to the original share server. 

3207 :param dest_share_server: Reference to the share server to be used as 

3208 destination. 

3209 :param shares: All shares in the source share server that should be 

3210 migrated. 

3211 :param snapshots: All snapshots in the source share server that should 

3212 be migrated. 

3213 :param new_network_info: Network allocation associated to the 

3214 destination share server. 

3215 :return: If the migration changes the shares export locations, 

3216 snapshots provider locations or snapshots export locations, this 

3217 method should return a dictionary containing a list of share 

3218 instances and snapshot instances indexed by their id's, where each 

3219 instance should provide a dict with the relevant information that 

3220 need to be updated. 

3221 

3222 Example:: 

3223 

3224 { 

3225 'share_updates': 

3226 { 

3227 '4363eb92-23ca-4888-9e24-502387816e2a': 

3228 { 

3229 'export_locations': 

3230 [ 

3231 { 

3232 'path': '1.2.3.4:/foo', 

3233 'metadata': {}, 

3234 'is_admin_only': False 

3235 }, 

3236 { 

3237 'path': '5.6.7.8:/foo', 

3238 'metadata': {}, 

3239 'is_admin_only': True 

3240 }, 

3241 ], 

3242 'pool_name': 'poolA', 

3243 }, 

3244 }, 

3245 'snapshot_updates': 

3246 { 

3247 'bc4e3b28-0832-4168-b688-67fdc3e9d408': 

3248 { 

3249 'provider_location': '/snapshots/foo/bar_1', 

3250 'export_locations': 

3251 [ 

3252 { 

3253 'path': '1.2.3.4:/snapshots/foo/bar_1', 

3254 'is_admin_only': False, 

3255 }, 

3256 { 

3257 'path': '5.6.7.8:/snapshots/foo/bar_1', 

3258 'is_admin_only': True, 

3259 }, 

3260 ], 

3261 }, 

3262 '2e62b7ea-4e30-445f-bc05-fd523ca62941': 

3263 { 

3264 'provider_location': '/snapshots/foo/bar_2', 

3265 'export_locations': 

3266 [ 

3267 { 

3268 'path': '1.2.3.4:/snapshots/foo/bar_2', 

3269 'is_admin_only': False, 

3270 }, 

3271 { 

3272 'path': '5.6.7.8:/snapshots/foo/bar_2', 

3273 'is_admin_only': True, 

3274 }, 

3275 ], 

3276 }, 

3277 } 

3278 'backend_details': 

3279 { 

3280 'new_share_server_info_key': 

3281 'new_share_server_info_value', 

3282 }, 

3283 } 

3284 

3285 """ 

3286 raise NotImplementedError() 

3287 

3288 def update_share_server_security_service( 

3289 self, context, share_server, network_info, share_instances, 

3290 share_instance_rules, new_security_service, 

3291 current_security_service=None): 

3292 """Updates share server security service configuration. 

3293 

3294 If the driver supports different security services, the user can 

3295 request the addition of a new security service, with a different type. 

3296 If the user wants to update the current security service configuration, 

3297 the driver will receive both current and new security services, which 

3298 will always be of the same type. 

3299 

3300 :param context: The 'context.RequestContext' object for the request. 

3301 :param share_server: Reference to the share server object that will be 

3302 updated. 

3303 :param network_info: All network allocation associated with the share 

3304 server that will be updated. 

3305 :param share_instances: A list of share instances that belong to the 

3306 share server that is being updated. 

3307 :param share_instance_rules: A list of access rules, grouped by share 

3308 instance, in the following format. 

3309 

3310 Example:: 

3311 

3312 [ 

3313 { 

3314 'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3', 

3315 'access_rules': 

3316 [ 

3317 { 

3318 'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3', 

3319 'access_type':'ip', 

3320 'access_key':None, 

3321 'access_to':'10.0.0.1', 

3322 'access_level':'rw' 

3323 ... 

3324 }, 

3325 ], 

3326 }, 

3327 ] 

3328 

3329 :param new_security_service: New security service object to be 

3330 configured in the share server. 

3331 :param current_security_service: When provided, represents the current 

3332 security service that will be replaced by the 

3333 'new_security_service'. 

3334 

3335 :raises: ShareBackendException. 

3336 A ShareBackendException should only be raised if the share server 

3337 failed to update the security service, compromising all its access 

3338 rules. By raising an exception, the share server and all its share 

3339 instances will be set to 'error'. 

3340 :return: None, or a dictionary of updates in the following format. 

3341 

3342 Example:: 

3343 

3344 { 

3345 '3bc10d67-2598-4122-bb62-0bdeaa8c6db3': 

3346 { 

3347 '09960614-8574-4e03-89cf-7cf267b0bd08': 

3348 { 

3349 'access_key': 'alice31493e5441b8171d2310d80e37e', 

3350 'state': 'error', 

3351 }, 

3352 '28f6eabb-4342-486a-a7f4-45688f0c0295': 

3353 { 

3354 'access_key': 'bob0078aa042d5a7325480fd13228b', 

3355 'state': 'active', 

3356 }, 

3357 }, 

3358 } 

3359 

3360 The top level keys are share_instance_id's which should provide 

3361 another dictionary of access rules to be updated, indexed by their 

3362 'access_id'. The inner access rules dictionary should only contain the 

3363 access rules that need to be updated. 

3364 """ 

3365 raise NotImplementedError() 

3366 

3367 def check_update_share_server_security_service( 

3368 self, context, share_server, network_info, share_instances, 

3369 share_instance_rules, new_security_service, 

3370 current_security_service=None): 

3371 """Check if the current share server security service is supported. 

3372 

3373 If the driver supports different security services, the user can 

3374 request the addition of a new security service, with a different type. 

3375 If the user wants to update the current security service configuration, 

3376 the driver will receive both current and new security services, which 

3377 will always be of the same type. 

3378 

3379 :param context: The 'context.RequestContext' object for the request. 

3380 :param share_server: Reference to the share server object that will be 

3381 updated. 

3382 :param network_info: All network allocation associated with the share 

3383 server that will be updated. 

3384 :param share_instances: A list of share instances that belong to the 

3385 share server that is affected by the update. 

3386 :param share_instance_rules: A list of access rules, grouped by share 

3387 instance, in the following format. 

3388 

3389 Example:: 

3390 

3391 [ 

3392 { 

3393 'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3', 

3394 'access_rules': 

3395 [ 

3396 { 

3397 'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3', 

3398 'access_type':'ip', 

3399 'access_key':None, 

3400 'access_to':'10.0.0.1', 

3401 'access_level':'rw' 

3402 ... 

3403 }, 

3404 ], 

3405 }, 

3406 ] 

3407 

3408 :param new_security_service: New security service object to be 

3409 configured in the share server. 

3410 :param current_security_service: When provided, represents the current 

3411 security service that will be replaced by the 

3412 'new_security_service'. 

3413 

3414 :return: 'True' if the driver support the requested update, 'False' 

3415 otherwise. 

3416 """ 

3417 raise NotImplementedError() 

3418 

3419 def check_update_share_server_network_allocations( 

3420 self, context, share_server, current_network_allocations, 

3421 new_share_network_subnet, security_services, share_instances, 

3422 share_instances_rules): 

3423 """"Check if the share server network allocation update is supported. 

3424 

3425 :param context: The 'context.RequestContext' object for the request. 

3426 :param share_server: Reference to the share server object that will be 

3427 updated. 

3428 :param current_network_allocations: All network allocations associated 

3429 with the share server that will be updated: 

3430 

3431 Example:: 

3432 

3433 { 

3434 'admin_network_allocations': 

3435 [ 

3436 { 

3437 'ip_address': '10.193.154.11', 

3438 'ip_version': 4, 

3439 'cidr': '10.193.154.0/28', 

3440 'gateway': '10.193.154.1', 

3441 'mtu': 1500, 

3442 'network_type': 'vlan', 

3443 'segmentation_id': 3000, 

3444 'mac_address': ' AA:AA:AA:AA:AA:AA', 

3445 ... 

3446 }, 

3447 ], 

3448 'subnets': 

3449 [ 

3450 { 

3451 'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67', 

3452 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3', 

3453 'neutron_subnet_id': '3bc10d67-2598-4122-bb62', 

3454 'network_allocations': 

3455 [ 

3456 { 

3457 'ip_address': '10.193.154.10', 

3458 'ip_version': 4, 

3459 'cidr': '10.193.154.0/28', 

3460 'gateway': '10.193.154.1', 

3461 'mtu': 1500, 

3462 'network_type': 'vlan', 

3463 'segmentation_id': 3000, 

3464 'mac_address': ' AA:AA:AA:AA:AA:AA', 

3465 ... 

3466 }, 

3467 ], 

3468 }, 

3469 ], 

3470 } 

3471 

3472 :param new_share_network_subnet: dict containing the subnet data that 

3473 has to be checked if it can be added to the share server: 

3474 

3475 Example:: 

3476 

3477 { 

3478 'availability_zone_id': '0bdeaa8c6db3-3bc10d67', 

3479 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3', 

3480 'neutron_subnet_id': '3bc10d67-2598-4122-bb62', 

3481 'ip_version': 4, 

3482 'cidr': '10.193.154.0/28', 

3483 'gateway': '10.193.154.1', 

3484 'mtu': 1500, 

3485 'network_type': 'vlan', 

3486 'segmentation_id': 3000, 

3487 } 

3488 

3489 :param security_services: list of security services configured with 

3490 this share server. 

3491 :param share_instances: A list of share instances that belong to the 

3492 share server that is affected by the update. 

3493 :param share_instances_rules: A list of access rules, grouped by share 

3494 instance, in the following format. 

3495 

3496 Example:: 

3497 

3498 [ 

3499 { 

3500 'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3', 

3501 'access_rules': 

3502 [ 

3503 { 

3504 'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3', 

3505 'access_type':'ip', 

3506 'access_key':None, 

3507 'access_to':'10.0.0.1', 

3508 'access_level':'rw' 

3509 ... 

3510 }, 

3511 ], 

3512 }, 

3513 ] 

3514 

3515 :return Boolean indicating whether the update is possible or not. It is 

3516 the driver responsibility to log the reason why not accepting the 

3517 update. 

3518 """ 

3519 raise NotImplementedError() 

3520 

3521 def update_share_server_network_allocations( 

3522 self, context, share_server, current_network_allocations, 

3523 new_network_allocations, security_services, shares, snapshots): 

3524 """Updates a share server's network allocations. 

3525 

3526 :param context: The 'context.RequestContext' object for the request. 

3527 :param share_server: reference to the share server that have to update 

3528 network allocations. 

3529 :param current_network_allocations: all network allocations associated 

3530 with the share server that will be updated 

3531 

3532 Example:: 

3533 

3534 { 

3535 'admin_network_allocations': 

3536 [ 

3537 { 

3538 'ip_address': '10.193.154.11', 

3539 'ip_version': 4, 

3540 'cidr': '10.193.154.0/28', 

3541 'gateway': '10.193.154.1', 

3542 'mtu': 1500, 

3543 'network_type': 'vlan', 

3544 'segmentation_id': 3000, 

3545 'mac_address': ' AA:AA:AA:AA:AA:AA', 

3546 }, 

3547 ... 

3548 ], 

3549 'subnets': 

3550 [ 

3551 { 

3552 'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67', 

3553 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3', 

3554 'neutron_subnet_id': '3bc10d67-2598-4122-bb62', 

3555 'network_allocations': 

3556 [ 

3557 { 

3558 'ip_address': '10.193.154.10', 

3559 'ip_version': 4, 

3560 'cidr': '10.193.154.0/28', 

3561 'gateway': '10.193.154.1', 

3562 'mtu': 1500, 

3563 'network_type': 'vlan', 

3564 'segmentation_id': 3000, 

3565 'mac_address': ' AA:AA:AA:AA:AA:AA', 

3566 }, 

3567 ... 

3568 ], 

3569 }, 

3570 ], 

3571 } 

3572 

3573 :param new_network_allocations: allocations that must be configured in 

3574 the share server. 

3575 

3576 Example:: 

3577 

3578 { 

3579 'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67', 

3580 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3', 

3581 'neutron_subnet_id': '3bc10d67-2598-4122-bb62', 

3582 'network_allocations': 

3583 [ 

3584 { 

3585 'ip_address': '10.193.154.10', 

3586 'ip_version': 4, 

3587 'cidr': '10.193.154.0/28', 

3588 'gateway': '10.193.154.1', 

3589 'mtu': 1500, 

3590 'network_type': 'vlan', 

3591 'segmentation_id': 3000, 

3592 'mac_address': 'AA:AA:AA:AA:AA:AA', 

3593 ... 

3594 }, 

3595 ], 

3596 }, 

3597 

3598 :param security_services: list of security services configured with 

3599 this share server. 

3600 :param shares: All shares in the share server. 

3601 :param snapshots: All snapshots in the share server. 

3602 

3603 :raises: Exception. 

3604 By raising an exception, the share server and all its shares and 

3605 snapshots instances will be set to 'error'. The error can contain 

3606 the field 'details_data' as a dict with the key 'server_details' 

3607 containing the backend details dict that will be saved to share 

3608 server. 

3609 

3610 :return If the update changes the shares export locations or snapshots 

3611 export locations, this method should return a dictionary 

3612 containing a list of share instances and snapshot instances 

3613 indexed by their id's, where each instance should provide a 

3614 dict with the relevant information that need to be updated. 

3615 Also, the returned dict can contain the updated back end 

3616 details to be saved in the database. 

3617 

3618 Example:: 

3619 

3620 { 

3621 'share_updates': 

3622 { 

3623 '4363eb92-23ca-4888-9e24-502387816e2a': 

3624 [ 

3625 { 

3626 'path': '1.2.3.4:/foo', 

3627 'metadata': {}, 

3628 'is_admin_only': False 

3629 }, 

3630 { 

3631 'path': '5.6.7.8:/foo', 

3632 'metadata': {}, 

3633 'is_admin_only': True 

3634 }, 

3635 ], 

3636 ... 

3637 }, 

3638 'snapshot_updates': 

3639 { 

3640 'bc4e3b28-0832-4168-b688-67fdc3e9d408': 

3641 { 

3642 'provider_location': '/snapshots/foo/bar_1', 

3643 'export_locations': 

3644 [ 

3645 { 

3646 'path': '1.2.3.4:/snapshots/foo/bar_1', 

3647 'is_admin_only': False, 

3648 }, 

3649 { 

3650 'path': '5.6.7.8:/snapshots/foo/bar_1', 

3651 'is_admin_only': True, 

3652 }, 

3653 ], 

3654 }, 

3655 '2e62b7ea-4e30-445f-bc05-fd523ca62941': 

3656 { 

3657 'provider_location': '/snapshots/foo/bar_2', 

3658 'export_locations': 

3659 [ 

3660 { 

3661 'path': '1.2.3.4:/snapshots/foo/bar_2', 

3662 'is_admin_only': False, 

3663 }, 

3664 { 

3665 'path': '5.6.7.8:/snapshots/foo/bar_2', 

3666 'is_admin_only': True, 

3667 }, 

3668 ], 

3669 }, 

3670 } 

3671 'server_details': 

3672 { 

3673 'new_share_server_info_key': 

3674 'new_share_server_info_value', 

3675 }, 

3676 } 

3677 

3678 """ 

3679 raise NotImplementedError() 

3680 

3681 def create_backup(self, context, share_instance, backup, 

3682 share_server=None): 

3683 """Starts backup of a given share_instance into backup. 

3684 

3685 Driver should implement this method if willing to perform backup of 

3686 share_instance. This method should start the backup procedure in the 

3687 backend and end. Following steps should be done in 

3688 'create_backup_continue'. 

3689 

3690 :param context: The 'context.RequestContext' object for the request. 

3691 :param share_instance: Reference to the original share instance. 

3692 :param backup: Share backup model. 

3693 :param share_server: share server in case of dhss_true 

3694 """ 

3695 raise NotImplementedError() 

3696 

3697 def create_backup_continue(self, context, share_instance, backup, 

3698 share_server=None): 

3699 """Continue backup of a given share_instance into backup. 

3700 

3701 Driver must implement this method if it supports 'create_backup' 

3702 method. This method should continue the remaining backup procedure 

3703 in the backend and report the progress of backup. 

3704 

3705 :param context: The 'context.RequestContext' object for the request. 

3706 :param share_instance: Reference to the original share instance. 

3707 :param backup: Share backup model. 

3708 :param share_server: share server in case of dhss_true 

3709 """ 

3710 raise NotImplementedError() 

3711 

3712 def delete_backup(self, context, backup, share_instance, 

3713 share_server=None): 

3714 """Is called to remove backup.""" 

3715 raise NotImplementedError() 

3716 

3717 def restore_backup(self, context, backup, share_instance, 

3718 share_server=None): 

3719 """Starts restoring backup into a given share_instance. 

3720 

3721 Driver should implement this method if willing to perform restore of 

3722 backup into a share_instance. This method should start the backup 

3723 restore procedure in the backend and end. Following steps should be 

3724 done in 'restore_backup_continue'. 

3725 

3726 :param context: The 'context.RequestContext' object for the request. 

3727 :param share_instance: Reference to the original share instance. 

3728 :param backup: Share backup model. 

3729 :param share_server: share server in case of dhss_true 

3730 """ 

3731 raise NotImplementedError() 

3732 

3733 def restore_backup_continue(self, context, backup, share_instance, 

3734 share_server=None): 

3735 """Continue restore of a given backup into share_instance. 

3736 

3737 Driver must implement this method if it supports 'restore_backup' 

3738 method. This method should continue the remaining restore procedure 

3739 in the backend and report the progress of backup restore. 

3740 

3741 :param context: The 'context.RequestContext' object for the request. 

3742 :param share_instance: Reference to the original share instance. 

3743 :param backup: Share backup model. 

3744 :param share_server: share server in case of dhss_true 

3745 """ 

3746 raise NotImplementedError() 

3747 

3748 def update_share_from_metadata(self, context, share, metadata, 

3749 share_server=None): 

3750 """Update the share from metadata. 

3751 

3752 Driver must implement this method if needs to perform some action 

3753 on given resource (i.e. share) based on provided metadata. 

3754 

3755 :param context: The 'context.RequestContext' object for the request. 

3756 :param share: Share instance model with share data. 

3757 :param metadata: Dict contains key-value pair where driver will 

3758 perform necessary action based on key. 

3759 :param share_server: Reference to the share server. 

3760 """ 

3761 raise NotImplementedError() 

3762 

3763 def update_share_network_subnet_from_metadata(self, context, 

3764 share_network, 

3765 share_network_subnet, 

3766 share_server, metadata): 

3767 """Update the share network subnet from metadata. 

3768 

3769 Driver must implement this method if it can perform some action on 

3770 given resource (i.e. share network subnet) based on provided metadata. 

3771 

3772 :param context: The 'context.RequestContext' object for the request. 

3773 :param share_network: share network model 

3774 :param share_network_subnet: share network subnet model 

3775 :param share_server: share-server model. 

3776 :param metadata: Dict contains key-value pair where driver will 

3777 perform necessary action based on key. 

3778 """ 

3779 raise NotImplementedError()