1# Licensed under the Apache License, Version 2.0 (the "License"); you may 2# not use this file except in compliance with the License. You may obtain 3# a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations 11# under the License. 12 13from openstack.block_storage import _base_proxy 14from openstack.block_storage.v3 import availability_zone 15from openstack.block_storage.v3 import backup as _backup 16from openstack.block_storage.v3 import capabilities as _capabilities 17from openstack.block_storage.v3 import extension as _extension 18from openstack.block_storage.v3 import group_type as _group_type 19from openstack.block_storage.v3 import limits as _limits 20from openstack.block_storage.v3 import resource_filter as _resource_filter 21from openstack.block_storage.v3 import snapshot as _snapshot 22from openstack.block_storage.v3 import stats as _stats 23from openstack.block_storage.v3 import type as _type 24from openstack.block_storage.v3 import volume as _volume 25from openstack import exceptions 26from openstack import resource 27 28 29class Proxy(_base_proxy.BaseBlockStorageProxy): 30 31 def get_snapshot(self, snapshot): 32 """Get a single snapshot 33 34 :param snapshot: The value can be the ID of a snapshot or a 35 :class:`~openstack.volume.v3.snapshot.Snapshot` 36 instance. 37 38 :returns: One :class:`~openstack.volume.v3.snapshot.Snapshot` 39 :raises: :class:`~openstack.exceptions.ResourceNotFound` 40 when no resource can be found. 41 """ 42 return self._get(_snapshot.Snapshot, snapshot) 43 44 def find_snapshot(self, name_or_id, ignore_missing=True, **attrs): 45 """Find a single snapshot 46 47 :param snapshot: The name or ID a snapshot 48 :param bool ignore_missing: When set to ``False`` 49 :class:`~openstack.exceptions.ResourceNotFound` will be raised 50 when the snapshot does not exist. 51 52 :returns: One :class:`~openstack.volume.v3.snapshot.Snapshot` 53 :raises: :class:`~openstack.exceptions.ResourceNotFound` 54 when no resource can be found. 55 """ 56 return self._find(_snapshot.Snapshot, name_or_id, 57 ignore_missing=ignore_missing) 58 59 def snapshots(self, details=True, **query): 60 """Retrieve a generator of snapshots 61 62 :param bool details: When set to ``False`` 63 :class:`~openstack.block_storage.v3.snapshot.Snapshot` 64 objects will be returned. The default, ``True``, will cause 65 more attributes to be returned. 66 :param kwargs query: Optional query parameters to be sent to limit 67 the snapshots being returned. Available parameters include: 68 69 * name: Name of the snapshot as a string. 70 * all_projects: Whether return the snapshots in all projects. 71 * project_id: Filter the snapshots by project. 72 * volume_id: volume id of a snapshot. 73 * status: Value of the status of the snapshot so that you can 74 filter on "available" for example. 75 76 :returns: A generator of snapshot objects. 77 """ 78 base_path = '/snapshots/detail' if details else None 79 return self._list(_snapshot.Snapshot, base_path=base_path, **query) 80 81 def create_snapshot(self, **attrs): 82 """Create a new snapshot from attributes 83 84 :param dict attrs: Keyword arguments which will be used to create 85 a :class:`~openstack.volume.v3.snapshot.Snapshot`, 86 comprised of the properties on the Snapshot class. 87 88 :returns: The results of snapshot creation 89 :rtype: :class:`~openstack.volume.v3.snapshot.Snapshot` 90 """ 91 return self._create(_snapshot.Snapshot, **attrs) 92 93 def delete_snapshot(self, snapshot, ignore_missing=True): 94 """Delete a snapshot 95 96 :param snapshot: The value can be either the ID of a snapshot or a 97 :class:`~openstack.volume.v3.snapshot.Snapshot` 98 instance. 99 :param bool ignore_missing: When set to ``False`` 100 :class:`~openstack.exceptions.ResourceNotFound` will be 101 raised when the snapshot does not exist. 102 When set to ``True``, no exception will be set when 103 attempting to delete a nonexistent snapshot. 104 105 :returns: ``None`` 106 """ 107 self._delete(_snapshot.Snapshot, snapshot, 108 ignore_missing=ignore_missing) 109 110 def get_type(self, type): 111 """Get a single type 112 113 :param type: The value can be the ID of a type or a 114 :class:`~openstack.volume.v3.type.Type` instance. 115 116 :returns: One :class:`~openstack.volume.v3.type.Type` 117 :raises: :class:`~openstack.exceptions.ResourceNotFound` 118 when no resource can be found. 119 """ 120 return self._get(_type.Type, type) 121 122 def find_type(self, name_or_id, ignore_missing=True, **attrs): 123 """Find a single volume type 124 125 :param snapshot: The name or ID a volume type 126 :param bool ignore_missing: When set to ``False`` 127 :class:`~openstack.exceptions.ResourceNotFound` will be raised 128 when the type does not exist. 129 130 :returns: One :class:`~openstack.volume.v3.type.Type` 131 :raises: :class:`~openstack.exceptions.ResourceNotFound` 132 when no resource can be found. 133 """ 134 return self._find(_type.Type, name_or_id, 135 ignore_missing=ignore_missing) 136 137 def types(self, **query): 138 """Retrieve a generator of volume types 139 140 :returns: A generator of volume type objects. 141 """ 142 return self._list(_type.Type, **query) 143 144 def create_type(self, **attrs): 145 """Create a new type from attributes 146 147 :param dict attrs: Keyword arguments which will be used to create 148 a :class:`~openstack.volume.v3.type.Type`, 149 comprised of the properties on the Type class. 150 151 :returns: The results of type creation 152 :rtype: :class:`~openstack.volume.v3.type.Type` 153 """ 154 return self._create(_type.Type, **attrs) 155 156 def delete_type(self, type, ignore_missing=True): 157 """Delete a type 158 159 :param type: The value can be either the ID of a type or a 160 :class:`~openstack.volume.v3.type.Type` instance. 161 :param bool ignore_missing: When set to ``False`` 162 :class:`~openstack.exceptions.ResourceNotFound` will be 163 raised when the type does not exist. 164 When set to ``True``, no exception will be set when 165 attempting to delete a nonexistent type. 166 167 :returns: ``None`` 168 """ 169 self._delete(_type.Type, type, ignore_missing=ignore_missing) 170 171 def update_type(self, type, **attrs): 172 """Update a type 173 174 :param type: The value can be either the ID of a type or a 175 :class:`~openstack.volume.v3.type.Type` instance. 176 :param dict attrs: The attributes to update on the type 177 represented by ``value``. 178 179 :returns: The updated type 180 :rtype: :class:`~openstack.volume.v3.type.Type` 181 """ 182 return self._update(_type.Type, type, **attrs) 183 184 def update_type_extra_specs(self, type, **attrs): 185 """Update the extra_specs for a type 186 187 :param type: The value can be either the ID of a type or a 188 :class:`~openstack.volume.v3.type.Type` instance. 189 :param dict attrs: The extra_spec attributes to update on the 190 type represented by ``value``. 191 192 :returns: A dict containing updated extra_specs 193 194 """ 195 res = self._get_resource(_type.Type, type) 196 extra_specs = res.set_extra_specs(self, **attrs) 197 result = _type.Type.existing(id=res.id, extra_specs=extra_specs) 198 return result 199 200 def delete_type_extra_specs(self, type, keys): 201 """Delete the extra_specs for a type 202 203 Note: This method will do a HTTP DELETE request for every key in keys. 204 205 :param type: The value can be either the ID of a type or a 206 :class:`~openstack.volume.v3.type.Type` instance. 207 :param keys: The keys to delete 208 209 :returns: ``None`` 210 """ 211 res = self._get_resource(_type.Type, type) 212 return res.delete_extra_specs(self, keys) 213 214 def get_type_encryption(self, volume_type_id): 215 """Get the encryption details of a volume type 216 217 :param volume_type_id: The value can be the ID of a type or a 218 :class:`~openstack.volume.v3.type.Type` 219 instance. 220 221 :returns: One :class:`~openstack.volume.v3.type.TypeEncryption` 222 :raises: :class:`~openstack.exceptions.ResourceNotFound` 223 when no resource can be found. 224 """ 225 volume_type = self._get_resource(_type.Type, volume_type_id) 226 227 return self._get(_type.TypeEncryption, 228 volume_type_id=volume_type.id, 229 requires_id=False) 230 231 def create_type_encryption(self, volume_type, **attrs): 232 """Create new type encryption from attributes 233 234 :param volume_type: The value can be the ID of a type or a 235 :class:`~openstack.volume.v3.type.Type` 236 instance. 237 238 :param dict attrs: Keyword arguments which will be used to create 239 a :class:`~openstack.volume.v3.type.TypeEncryption`, 240 comprised of the properties on the TypeEncryption 241 class. 242 243 :returns: The results of type encryption creation 244 :rtype: :class:`~openstack.volume.v3.type.TypeEncryption` 245 """ 246 volume_type = self._get_resource(_type.Type, volume_type) 247 248 return self._create(_type.TypeEncryption, 249 volume_type_id=volume_type.id, **attrs) 250 251 def delete_type_encryption(self, encryption=None, 252 volume_type=None, ignore_missing=True): 253 """Delete type encryption attributes 254 255 :param encryption: The value can be None or a 256 :class:`~openstack.volume.v3.type.TypeEncryption` 257 instance. If encryption_id is None then 258 volume_type_id must be specified. 259 260 :param volume_type: The value can be the ID of a type or a 261 :class:`~openstack.volume.v3.type.Type` 262 instance. Required if encryption_id is None. 263 264 :param bool ignore_missing: When set to ``False`` 265 :class:`~openstack.exceptions.ResourceNotFound` will be 266 raised when the type does not exist. 267 When set to ``True``, no exception will be set when 268 attempting to delete a nonexistent type. 269 270 :returns: ``None`` 271 """ 272 273 if volume_type: 274 volume_type = self._get_resource(_type.Type, volume_type) 275 encryption = self._get(_type.TypeEncryption, 276 volume_type=volume_type.id, 277 requires_id=False) 278 279 self._delete(_type.TypeEncryption, encryption, 280 ignore_missing=ignore_missing) 281 282 def update_type_encryption(self, encryption=None, 283 volume_type=None, **attrs): 284 """Update a type 285 :param encryption: The value can be None or a 286 :class:`~openstack.volume.v3.type.TypeEncryption` 287 instance. If encryption_id is None then 288 volume_type_id must be specified. 289 290 :param volume_type: The value can be the ID of a type or a 291 :class:`~openstack.volume.v3.type.Type` 292 instance. Required if encryption_id is None. 293 :param dict attrs: The attributes to update on the type encryption. 294 295 :returns: The updated type encryption 296 :rtype: :class:`~openstack.volume.v3.type.TypeEncryption` 297 """ 298 299 if volume_type: 300 volume_type = self._get_resource(_type.Type, volume_type) 301 encryption = self._get(_type.TypeEncryption, 302 volume_type=volume_type.id, 303 requires_id=False) 304 305 return self._update(_type.TypeEncryption, encryption, **attrs) 306 307 def get_volume(self, volume): 308 """Get a single volume 309 310 :param volume: The value can be the ID of a volume or a 311 :class:`~openstack.volume.v3.volume.Volume` instance. 312 313 :returns: One :class:`~openstack.volume.v3.volume.Volume` 314 :raises: :class:`~openstack.exceptions.ResourceNotFound` 315 when no resource can be found. 316 """ 317 return self._get(_volume.Volume, volume) 318 319 def find_volume(self, name_or_id, ignore_missing=True, **attrs): 320 """Find a single volume 321 322 :param snapshot: The name or ID a volume 323 :param bool ignore_missing: When set to ``False`` 324 :class:`~openstack.exceptions.ResourceNotFound` will be raised 325 when the volume does not exist. 326 327 :returns: One :class:`~openstack.volume.v3.volume.Volume` 328 :raises: :class:`~openstack.exceptions.ResourceNotFound` 329 when no resource can be found. 330 """ 331 return self._find(_volume.Volume, name_or_id, 332 ignore_missing=ignore_missing) 333 334 def volumes(self, details=True, **query): 335 """Retrieve a generator of volumes 336 337 :param bool details: When set to ``False`` no extended attributes 338 will be returned. The default, ``True``, will cause objects with 339 additional attributes to be returned. 340 :param kwargs query: Optional query parameters to be sent to limit 341 the volumes being returned. Available parameters include: 342 343 * name: Name of the volume as a string. 344 * all_projects: Whether return the volumes in all projects 345 * status: Value of the status of the volume so that you can filter 346 on "available" for example. 347 348 :returns: A generator of volume objects. 349 """ 350 base_path = '/volumes/detail' if details else None 351 return self._list(_volume.Volume, base_path=base_path, **query) 352 353 def create_volume(self, **attrs): 354 """Create a new volume from attributes 355 356 :param dict attrs: Keyword arguments which will be used to create 357 a :class:`~openstack.volume.v3.volume.Volume`, 358 comprised of the properties on the Volume class. 359 360 :returns: The results of volume creation 361 :rtype: :class:`~openstack.volume.v3.volume.Volume` 362 """ 363 return self._create(_volume.Volume, **attrs) 364 365 def delete_volume(self, volume, ignore_missing=True): 366 """Delete a volume 367 368 :param volume: The value can be either the ID of a volume or a 369 :class:`~openstack.volume.v3.volume.Volume` instance. 370 :param bool ignore_missing: When set to ``False`` 371 :class:`~openstack.exceptions.ResourceNotFound` will be 372 raised when the volume does not exist. 373 When set to ``True``, no exception will be set when 374 attempting to delete a nonexistent volume. 375 376 :returns: ``None`` 377 """ 378 self._delete(_volume.Volume, volume, ignore_missing=ignore_missing) 379 380 def extend_volume(self, volume, size): 381 """Extend a volume 382 383 :param volume: The value can be either the ID of a volume or a 384 :class:`~openstack.volume.v3.volume.Volume` instance. 385 :param size: New volume size 386 387 :returns: None 388 """ 389 volume = self._get_resource(_volume.Volume, volume) 390 volume.extend(self, size) 391 392 def set_volume_readonly(self, volume, readonly=True): 393 """Set a volume's read-only flag. 394 395 :param name_or_id: Name, unique ID of the volume or a volume dict. 396 :param bool readonly: Whether the volume should be a read-only volume 397 or not 398 399 :raises: OpenStackCloudTimeout if wait time exceeded. 400 :raises: OpenStackCloudException on operation error. 401 """ 402 volume = self._get_resource(_volume.Volume, volume) 403 volume.set_readonly(self, readonly) 404 405 def retype_volume(self, volume, new_type, migration_policy="never"): 406 """Retype the volume. 407 408 :param name_or_id: Name, unique ID of the volume or a volume dict. 409 :param new_type: The new volume type that volume is changed with. 410 :param migration_policy: Specify if the volume should be migrated when 411 it is re-typed. Possible values are on-demand 412 or never. Default: never. 413 414 :raises: OpenStackCloudTimeout if wait time exceeded. 415 :raises: OpenStackCloudException on operation error. 416 """ 417 volume = self._get_resource(_volume.Volume, volume) 418 volume.retype(self, new_type, migration_policy) 419 420 def backend_pools(self, **query): 421 """Returns a generator of cinder Back-end storage pools 422 423 :param kwargs query: Optional query parameters to be sent to limit 424 the resources being returned. 425 426 :returns A generator of cinder Back-end storage pools objects 427 """ 428 return self._list(_stats.Pools, **query) 429 430 def backups(self, details=True, **query): 431 """Retrieve a generator of backups 432 433 :param bool details: When set to ``False`` 434 no additional details will be returned. The default, ``True``, 435 will cause objects with additional attributes to be returned. 436 :param dict query: Optional query parameters to be sent to limit the 437 resources being returned: 438 439 * offset: pagination marker 440 * limit: pagination limit 441 * sort_key: Sorts by an attribute. A valid value is 442 name, status, container_format, disk_format, size, id, 443 created_at, or updated_at. Default is created_at. 444 The API uses the natural sorting direction of the 445 sort_key attribute value. 446 * sort_dir: Sorts by one or more sets of attribute and sort 447 direction combinations. If you omit the sort direction 448 in a set, default is desc. 449 * project_id: Project ID to query backups for. 450 451 :returns: A generator of backup objects. 452 """ 453 base_path = '/backups/detail' if details else None 454 return self._list(_backup.Backup, base_path=base_path, **query) 455 456 def get_backup(self, backup): 457 """Get a backup 458 459 :param backup: The value can be the ID of a backup 460 or a :class:`~openstack.block_storage.v3.backup.Backup` 461 instance. 462 463 :returns: Backup instance 464 :rtype: :class:`~openstack.block_storage.v3.backup.Backup` 465 """ 466 return self._get(_backup.Backup, backup) 467 468 def find_backup(self, name_or_id, ignore_missing=True, **attrs): 469 """Find a single backup 470 471 :param snapshot: The name or ID a backup 472 :param bool ignore_missing: When set to ``False`` 473 :class:`~openstack.exceptions.ResourceNotFound` will be raised 474 when the backup does not exist. 475 476 :returns: One :class:`~openstack.volume.v3.backup.Backup` 477 :raises: :class:`~openstack.exceptions.ResourceNotFound` 478 when no resource can be found. 479 """ 480 return self._find(_backup.Backup, name_or_id, 481 ignore_missing=ignore_missing) 482 483 def create_backup(self, **attrs): 484 """Create a new Backup from attributes with native API 485 486 :param dict attrs: Keyword arguments which will be used to create 487 a :class:`~openstack.block_storage.v3.backup.Backup` 488 comprised of the properties on the Backup class. 489 490 :returns: The results of Backup creation 491 :rtype: :class:`~openstack.block_storage.v3.backup.Backup` 492 """ 493 return self._create(_backup.Backup, **attrs) 494 495 def delete_backup(self, backup, ignore_missing=True): 496 """Delete a CloudBackup 497 498 :param backup: The value can be the ID of a backup or a 499 :class:`~openstack.block_storage.v3.backup.Backup` instance 500 :param bool ignore_missing: When set to ``False`` 501 :class:`~openstack.exceptions.ResourceNotFound` will be raised when 502 the zone does not exist. 503 When set to ``True``, no exception will be set when attempting to 504 delete a nonexistent zone. 505 506 :returns: ``None`` 507 """ 508 self._delete(_backup.Backup, backup, 509 ignore_missing=ignore_missing) 510 511 def restore_backup(self, backup, volume_id=None, name=None): 512 """Restore a Backup to volume 513 514 :param backup: The value can be the ID of a backup or a 515 :class:`~openstack.block_storage.v3.backup.Backup` instance 516 :param volume_id: The ID of the volume to restore the backup to. 517 :param name: The name for new volume creation to restore. 518 519 :returns: Updated backup instance 520 :rtype: :class:`~openstack.block_storage.v3.backup.Backup` 521 """ 522 backup = self._get_resource(_backup.Backup, backup) 523 return backup.restore(self, volume_id=volume_id, name=name) 524 525 def get_limits(self): 526 """Retrieves limits 527 528 :returns: A Limit object, including both 529 :class:`~openstack.block_storage.v3.limits.AbsoluteLimit` and 530 :class:`~openstack.block_storage.v3.limits.RateLimit` 531 :rtype: :class:`~openstack.block_storage.v3.limits.Limit` 532 """ 533 return self._get(_limits.Limit, requires_id=False) 534 535 def get_capabilities(self, host): 536 """Get a backend's capabilites 537 538 :param host: Specified backend to obtain volume stats and properties. 539 540 :returns: One :class: 541 `~openstack.block_storage.v3.capabilites.Capabilities` instance. 542 :raises: :class:`~openstack.exceptions.ResourceNotFound` when no 543 resource can be found. 544 """ 545 return self._get(_capabilities.Capabilities, host) 546 547 def availability_zones(self): 548 """Return a generator of availability zones 549 550 :returns: A generator of availability zone 551 :rtype: :class:`~openstack.block_storage.v3.availability_zone.\ 552 AvailabilityZone` 553 """ 554 555 return self._list(availability_zone.AvailabilityZone) 556 557 def get_group_type(self, group_type): 558 """Get a specific group type 559 560 :param group_type: The value can be the ID of a group type 561 or a :class:`~openstack.block_storage.v3.group_type.GroupType` 562 instance. 563 564 :returns: One :class: 565 `~openstack.block_storage.v3.group_type.GroupType` instance. 566 :raises: :class:`~openstack.exceptions.ResourceNotFound` when no 567 resource can be found. 568 """ 569 return self._get(_group_type.GroupType, group_type) 570 571 def find_group_type(self, name_or_id, ignore_missing=True): 572 """Find a single group type 573 574 :param name_or_id: The name or ID of a group type. 575 :param bool ignore_missing: When set to ``False`` 576 :class:`~openstack.exceptions.ResourceNotFound` will be raised 577 when the group type does not exist. 578 579 :returns: One :class:`~openstack.block_storage.v3.group_type 580 .GroupType' 581 :raises: :class:`~openstack.exceptions.ResourceNotFound` 582 when no resource can be found. 583 """ 584 return self._find( 585 _group_type.GroupType, name_or_id, ignore_missing=ignore_missing) 586 587 def group_types(self, **query): 588 """Retrive a generator of group types 589 590 :param dict query: Optional query parameters to be sent to limit the 591 resources being returned: 592 593 * sort: Comma-separated list of sort keys and optional sort 594 directions in the form of <key> [:<direction>]. A valid 595 direction is asc (ascending) or desc (descending). 596 * limit: Requests a page size of items. Returns a number of items 597 up to a limit value. Use the limit parameter to make an 598 initial limited request and use the ID of the last-seen item 599 from the response as the marker parameter value in a 600 subsequent limited request. 601 * offset: Used in conjunction with limit to return a slice of 602 items. Is where to start in the list. 603 * marker: The ID of the last-seen item. 604 605 :returns: A generator of group type objects. 606 """ 607 return self._list(_group_type.GroupType, **query) 608 609 def create_group_type(self, **attrs): 610 """Create a group type 611 612 :param dict attrs: Keyword arguments which will be used to create 613 a :class:`~openstack.block_storage.v3.group_type.GroupType' 614 comprised of the properties on the GroupType class. 615 616 :returns: The results of group type creation. 617 :rtype: :class:`~openstack.block_storage.v3.group_type.GroupTye'. 618 """ 619 return self._create(_group_type.GroupType, **attrs) 620 621 def delete_group_type(self, group_type, ignore_missing=True): 622 """Delete a group type 623 624 :param group_type: The value can be the ID of a group type 625 or a :class:`~openstack.block_storage.v3.group_type.GroupType` 626 instance. 627 :param bool ignore_missing: When set to ``False`` 628 :class:`~openstack.exceptions.ResourceNotFound` will be raised when 629 the zone does not exist. 630 When set to ``True``, no exception will be set when attempting to 631 delete a nonexistent zone. 632 633 :returns: ''None'' 634 """ 635 self._delete( 636 _group_type.GroupType, group_type, ignore_missing=ignore_missing) 637 638 def update_group_type(self, group_type, **attrs): 639 """Update a group_type 640 641 :param group_type: The value can be the ID of a group type or a 642 :class:`~openstack.block_storage.v3.group_type.GroupType` 643 instance. 644 :param dict attrs: The attributes to update on the group type. 645 646 :returns: The updated group type. 647 :rtype: :class:`~openstack.block_storage.v3.group_type.GroupType` 648 """ 649 return self._update( 650 _group_type.GroupType, group_type, **attrs) 651 652 def wait_for_status(self, res, status='ACTIVE', failures=None, 653 interval=2, wait=120): 654 """Wait for a resource to be in a particular status. 655 656 :param res: The resource to wait on to reach the specified status. 657 The resource must have a ``status`` attribute. 658 :type resource: A :class:`~openstack.resource.Resource` object. 659 :param status: Desired status. 660 :param failures: Statuses that would be interpreted as failures. 661 :type failures: :py:class:`list` 662 :param interval: Number of seconds to wait before to consecutive 663 checks. Default to 2. 664 :param wait: Maximum number of seconds to wait before the change. 665 Default to 120. 666 :returns: The resource is returned on success. 667 :raises: :class:`~openstack.exceptions.ResourceTimeout` if transition 668 to the desired status failed to occur in specified seconds. 669 :raises: :class:`~openstack.exceptions.ResourceFailure` if the resource 670 has transited to one of the failure statuses. 671 :raises: :class:`~AttributeError` if the resource does not have a 672 ``status`` attribute. 673 """ 674 failures = ['Error'] if failures is None else failures 675 return resource.wait_for_status( 676 self, res, status, failures, interval, wait) 677 678 def wait_for_delete(self, res, interval=2, wait=120): 679 """Wait for a resource to be deleted. 680 681 :param res: The resource to wait on to be deleted. 682 :type resource: A :class:`~openstack.resource.Resource` object. 683 :param interval: Number of seconds to wait before to consecutive 684 checks. Default to 2. 685 :param wait: Maximum number of seconds to wait before the change. 686 Default to 120. 687 :returns: The resource is returned on success. 688 :raises: :class:`~openstack.exceptions.ResourceTimeout` if transition 689 to delete failed to occur in the specified seconds. 690 """ 691 return resource.wait_for_delete(self, res, interval, wait) 692 693 def resource_filters(self, **query): 694 """Retrieve a generator of resource filters 695 696 :returns: A generator of resource filters. 697 """ 698 return self._list(_resource_filter.ResourceFilter, **query) 699 700 def extensions(self): 701 """Return a generator of extensions 702 703 :returns: A generator of extension 704 :rtype: :class:`~openstack.block_storage.v3.extension.\ 705 Extension` 706 """ 707 return self._list(_extension.Extension) 708 709 def _get_cleanup_dependencies(self): 710 return { 711 'block_storage': { 712 'before': [] 713 } 714 } 715 716 def _service_cleanup(self, dry_run=True, client_status_queue=None, 717 identified_resources=None, 718 filters=None, resource_evaluation_fn=None): 719 backups = [] 720 for obj in self.backups(details=False): 721 need_delete = self._service_cleanup_del_res( 722 self.delete_backup, 723 obj, 724 dry_run=dry_run, 725 client_status_queue=client_status_queue, 726 identified_resources=identified_resources, 727 filters=filters, 728 resource_evaluation_fn=resource_evaluation_fn) 729 if not dry_run and need_delete: 730 backups.append(obj) 731 732 # Before deleting snapshots need to wait for backups to be deleted 733 for obj in backups: 734 try: 735 self.wait_for_delete(obj) 736 except exceptions.SDKException: 737 # Well, did our best, still try further 738 pass 739 740 snapshots = [] 741 for obj in self.snapshots(details=False): 742 need_delete = self._service_cleanup_del_res( 743 self.delete_snapshot, 744 obj, 745 dry_run=dry_run, 746 client_status_queue=client_status_queue, 747 identified_resources=identified_resources, 748 filters=filters, 749 resource_evaluation_fn=resource_evaluation_fn) 750 if not dry_run and need_delete: 751 snapshots.append(obj) 752 753 # Before deleting volumes need to wait for snapshots to be deleted 754 for obj in snapshots: 755 try: 756 self.wait_for_delete(obj) 757 except exceptions.SDKException: 758 # Well, did our best, still try further 759 pass 760 761 for obj in self.volumes(details=True): 762 self._service_cleanup_del_res( 763 self.delete_volume, 764 obj, 765 dry_run=dry_run, 766 client_status_queue=client_status_queue, 767 identified_resources=identified_resources, 768 filters=filters, 769 resource_evaluation_fn=resource_evaluation_fn) 770