yakumo.cinder.v2.volume

Package yakumo :: Package cinder :: Package v2 :: Module volume |
[hide private]
[frames] | no frames]

# Source Code for Module yakumo.cinder.v2.volume

      1  # Copyright 2014-2017 by Akira Yoshiyama <akirayoshiyama@gmail.com>.
      2  # All Rights Reserved.
      3  #
      4  #    Licensed under the Apache License, Version 2.0 (the "License"); you may
      5  #    not use this file except in compliance with the License. You may obtain
      6  #    a copy of the License at
      7  #
      8  #         http://www.apache.org/licenses/LICENSE-2.0
      9  #
     10  #    Unless required by applicable law or agreed to in writing, software
     11  #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  #    License for the specific language governing permissions and limitations
     14  #    under the License.
     15
     16  """
     17  Resource class and its manager for volumes on Block Storage V2 API
     18  """
     19
     20  from yakumo import base
     21  from yakumo.constant import UNDEF
     22  from yakumo import mapper
     23  from yakumo import utils
     24
     25  from yakumo.cinder.v2.snapshot import Resource as Snapshot
     26  from yakumo.cinder.v2.volume_type import Resource as VolumeType
     27  from yakumo.nova.v2.image import Resource as NovaV2Image
     28  from yakumo.glance.v1.image import Resource as GlanceV1Image
     29  from yakumo.glance.v2.image import Resource as GlanceV2Image
     30
     31
     32  ATTRIBUTE_MAPPING = [
     33      ('name', 'name', mapper.Noop),
     34      ('description', 'description', mapper.Noop),
     35      ('volume_type', 'volume_type', mapper.Noop),
     36      ('size', 'size', mapper.Noop),
     37      ('availability_zone', 'availability_zone',
     38       mapper.Resource('availability_zone')),
     39      ('source_image', 'imageRef', mapper.Resource('image')),
     40      ('source_volume', 'source_volid', mapper.Resource('cinder.volume')),
     41      ('source_snapshot', 'snapshot_id',
     42       mapper.Resource('cinder.volume_snapshot')),
     43      ('source_replica', 'source_replica', mapper.Noop),
     44      ('consistencygroup', 'consistencygroup_id',
     45       mapper.Resource('cinder.consistency_group')),
     46      ('scheduler_hints', 'scheduler_hints', mapper.Noop),
     47      ('metadata', 'metadata', mapper.Noop),
     48      ('project', 'tenant_id', mapper.Resource('project')),
     49      ('project', 'os-vol-tenant-attr:tenant_id', mapper.Resource('project')),
     50      ('is_multiattach', 'multiattach', mapper.Noop),
     51      ('id', 'id', mapper.Noop),
     52      ('attachments', 'attachments', mapper.Noop),
     53      ('attachment', 'attachment', mapper.Resource('volume_attachment')),
     54      ('host', 'host', mapper.Noop),
     55      ('host', 'os-vol-host-attr:host', mapper.Noop),
     56      ('volume_replication_driver', 'os-volume-replication:driver_data',
     57       mapper.DateTime),
     58      ('replication_status', 'replication_status', mapper.Noop),
     59      ('extended_replication_status', 'os-volume-replication:extended_status',
     60       mapper.Noop),
     61      ('migration_status', 'migration_status', mapper.Noop),
     62      ('backend_volume_id', 'os-vol-mig-status-attr:name_id', mapper.Noop),
     63      ('user', 'user_id', mapper.Resource('user')),
     64      ('status', 'status', mapper.Noop),
     65      ('is_bootable', 'bootable', mapper.BoolStr),
     66      ('is_encrypted', 'encrypted', mapper.Noop),
     67      ('created_at', 'created_at', mapper.DateTime),
     68      ('updated_at', 'updated_at', mapper.DateTime),
     69  ]
     70
     71
     72 -class Resource(base.Resource):
     73      """resource class for volumes on Block Storage V2 API"""
     74
     75      _stable_state = ['available', 'in-use', 'error', 'error_deleting']
     76
     77 -    def update(self, name=UNDEF, description=UNDEF, metadata=UNDEF):
     78          """
     79          Update properties of a volume
     80
     81          @keyword name: Volume name
     82          @type name: str
     83          @keyword description: Description
     84          @type description: str
     85          @keyword metadata: Metadata (key=value)
     86          @type metadata: dict
     87          @rtype: None
     88          """
     89          super(Resource, self).update(
     90              name=name,
     91              description=description,
     92              metadata=metadata)
     93
     94 -    def get_metadata(self):
     95          """
     96          Get metadata of a volume
     97
     98          @return: Metadata
     99          @rtype: dict
    100          """
    101          ret = self._http.get(self._url_resource_path, self._id, 'metadata')
    102          return ret.get('metadata')
    103
    104 -    def set_metadata(self, **metadata):
    105          """
    106          Update metadata of a volume
    107
    108          @keyword metadata: key=value style.
    109          @type metadata: dict
    110          @rtype: None
    111          """
    112          self._http.post(self._url_resource_path, self._id, 'metadata',
    113                          data={'metadata': metadata})
    114          self.reload()
    115
    116 -    def unset_metadata(self, *keys):
    117          """
    118          Delete metadata of a volume
    119
    120          @param key: key of the metadata
    121          @type keys: [str]
    122          @rtype: None
    123          """
    124          for key in keys:
    125              self._http.delete(self._url_resource_path, self._id,
    126                                'metadata', key)
    127          self.reload()
    128
    129 -    def extend(self, size=None):
    130          """
    131          Extend a volume
    132
    133          @keyword size: new size; should be larger than the current size
    134          @type size: int
    135          @rtype: None
    136          """
    137          self._http.post(self._url_resource_path, self._id, 'action',
    138                          data=utils.get_json_body("os-extend", new_size=size))
    139
    140 -    def reset_status(self, status=None, attach_status=None,
    141                       migration_status=None):
    142          """
    143          Reset status of a volume
    144
    145          @keyword status: new status
    146          @type status: str
    147          @keyword attach_status: new attach status
    148          @type status: str
    149          @keyword migration_status: new migration status
    150          @type migration_status: str
    151          @rtype: None
    152          """
    153          self._http.post(self._url_resource_path, self._id, 'action',
    154                          data=utils.get_json_body(
    155                              "os-reset_status",
    156                              status=status,
    157                              attach_status=attach_status,
    158                              migration_status=migration_status))
    159
    160 -    def set_image_metadata(self, metadata=None):
    161          """
    162          Set image metadata
    163
    164          @keyword metadata: new metadata
    165          @type metadata: dict
    166          @rtype: None
    167          """
    168          self._http.post(self._url_resource_path, self._id, 'action',
    169                          data=utils.get_json_body("os-set_image_metadata",
    170                                                   metadata=metadata))
    171
    172 -    def delete_image_metadata(self, key=None):
    173          """
    174          Set image metadata
    175
    176          @keyword key: key to delete
    177          @type key: str
    178          @rtype: None
    179          """
    180          self._http.post(self._url_resource_path, self._id, 'action',
    181                          data=utils.get_json_body("os-unset_image_metadata",
    182                                                   key=key))
    183
    184 -    def unmanage(self):
    185          """
    186          Unmanage a volume
    187
    188          @rtype: None
    189          """
    190          self._http.post(self._url_resource_path, self._id, 'action',
    191                          data=utils.get_json_body("os-unmanage"))
    192
    193 -    def force_detach(self, attachment=None, connector=None):
    194          """
    195          Force detach a volume
    196
    197          @keyword attachment: Volume attachment
    198          @type attachment: yakumo.server.volume_attachment.Resource
    199          @keyword connector: Connector information
    200          @type connector: dict
    201          @rtype: None
    202          """
    203          self._http.post(self._url_resource_path, self._id, 'action',
    204                          data=utils.get_json_body(
    205                              "os-force_detach",
    206                              attachment=attachment,
    207                              connector=connector))
    208
    209 -    def upload(self, name=None, disk_format='raw', force=False):
    210          """
    211          Upload volume image to Glance
    212
    213          @keyword name: Image name
    214          @type name: str
    215          @keyword disk_format: Disk format (default: 'raw')
    216          @type disk_format: str
    217          @keyword force: Force creation
    218          @type force: bool
    219          """
    220          ret = self._http.post(self._url_resource_path, self._id, 'action',
    221                                data=utils.get_json_body(
    222                                    "os-volume_upload_image",
    223                                    image_name=name,
    224                                    disk_format=disk_format,
    225                                    force=force))
    226          image_id = ret.get('os-volume_upload_image', {}).get('image_id')
    227          return self._client.image.get_empty(image_id)
    228
    229
    230 -class Manager(base.Manager):
    231      """manager class for volumes on Block Storage V2 API"""
    232
    233      resource_class = Resource
    234      service_type = 'volume'
    235      _attr_mapping = ATTRIBUTE_MAPPING
    236      _json_resource_key = 'volume'
    237      _json_resources_key = 'volumes'
    238      _url_resource_list_path = '/volumes/detail'
    239      _url_resource_path = '/volumes'
    240
    241 -    def _attr2json(self, attrs):
    242          volume_type = attrs.get('volume_type')
    243          if isinstance(volume_type, VolumeType):
    244              attrs['volume_type'] = volume_type.name
    245          return super(Manager, self)._attr2json(attrs)
    246
    247 -    def _json2attr(self, json_params):
    248          ret = super(Manager, self)._json2attr(json_params)
    249          image = json_params.get('volume_image_metadata', {}).get('image_id')
    250          if image:
    251              ret['source_image'] = self._client.image.get_empty(image)
    252          volume_type = json_params.get('volume_type')
    253          if volume_type:
    254              ret['volume_type'] = self._client.volume_type.find_one(
    255                  name=volume_type)
    256          return ret
    257
    258 -    def create(self, name=UNDEF, description=UNDEF, volume_type=UNDEF,
    259                 size=UNDEF, availability_zone=UNDEF, source=UNDEF,
    260                 is_replication=UNDEF, consistency_group=UNDEF,
    261                 scheduler_hints=UNDEF, metadata=UNDEF,
    262                 project=UNDEF, is_multiattach=UNDEF):
    263          """
    264          Create a volume
    265
    266          @keyword name: Volume name
    267          @type name: str
    268          @keyword description: Description
    269          @type description: str
    270          @keyword volume_type: Volume type
    271          @type volume_type: yakumo.cinder.v2.volume_type.Resource
    272          @keyword size: Size in GB
    273          @type size: int
    274          @keyword availability_zone: Availability zone
    275          @type availability_zone: yakumo.availability_zone.Resource
    276          @keyword source: Source image/snapshot/volume (optional)
    277          @type source: one of yakumo.image.Resource,
    278          yakumo.volume_snapshot.Resource and yakumo.volume.Resource
    279          @keyword is_replication: Whether the volume is a replica of another
    280          volume
    281          @type source: bool
    282          @keyword consistency_group: Consistency group (optional)
    283          @type consistency_group: yakumo.cinder.v2.consistency_group.Resource
    284          @keyword scheduler_hints: Scheduler hints (optional)
    285          @type scheduler_hints: dict
    286          @keyword metadata: Metadata (key=value)
    287          @type metadata: dict
    288          @keyword is_multiattach: Whether multiattach is allowed
    289          @type is_multiattach: bool
    290          @return: Created volume
    291          @rtype: yakumo.cinder.v2.volume.Resource
    292          """
    293          source_image = UNDEF
    294          source_volume = UNDEF
    295          source_snapshot = UNDEF
    296          source_replica = UNDEF
    297          if isinstance(source, Resource):
    298              if is_replication is not UNDEF:
    299                  source_replica = source
    300              else:
    301                  source_volume = source
    302          elif isinstance(source, Snapshot):
    303              source_snapshot = source
    304          elif isinstance(source, (GlanceV1Image, GlanceV2Image, NovaV2Image)):
    305              source_image = source
    306          return super(Manager, self).create(
    307              name=name,
    308              description=description,
    309              volume_type=volume_type,
    310              size=size,
    311              availability_zone=availability_zone,
    312              source_image=source_image,
    313              source_volume=source_volume,
    314              source_snapshot=source_snapshot,
    315              source_replica=source_replica,
    316              consistency_group=consistency_group,
    317              scheduler_hints=scheduler_hints,
    318              metadata=metadata,
    319              is_multiattach=is_multiattach)
    320
    321 -    def manage(self, name=UNDEF, description=UNDEF, volume_type=UNDEF,
    322                 size=UNDEF, availability_zone=UNDEF, metadata=UNDEF,
    323                 ref=UNDEF, project=UNDEF, is_bootable=UNDEF):
    324          """
    325          Manage a volume
    326
    327          @keyword name: Volume name
    328          @type name: str
    329          @keyword description: Description
    330          @type description: str
    331          @keyword volume_type: Volume type
    332          @type volume_type: yakumo.cinder.v2.volume_type.Resource
    333          @keyword size: Size in GB
    334          @type size: int
    335          @keyword availability_zone: Availability zone
    336          @type availability_zone: yakumo.availability_zone.Resource
    337          @keyword metadata: Metadata (key=value)
    338          @type metadata: dict
    339          @keyword host: Reference for volume host
    340          @type host: str
    341          @keyword ref: Reference for existing volume (key=value)
    342          @type ref: dict
    343          @keyword is_bootable: Whether volume is bootable
    344          @type is_bootable: bool
    345          @return: Created volume
    346          @rtype: yakumo.cinder.v2.volume.Resource
    347          """
    348          json_attr = self._attr2json(dict(
    349              name=name,
    350              description=description,
    351              volume_type=volume_type,
    352              size=size,
    353              availability_zone=availability_zone,
    354              metadata=metadata,
    355              host=host,
    356              ref=ref,
    357              is_bootable=is_bootable))
    358          ret = self._http.post(self._url_resource_path, 'os-volume-manage',
    359                                data=utils.get_json_body("volume", **json_attr))
    360          attrs = self._json2attr(ret)
    361          return self.get_empty(attrs[self._id_attr])
    362