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. 12from openstack import exceptions 13from openstack import resource 14from openstack import utils 15 16 17class Backup(resource.Resource): 18 """Volume Backup""" 19 resource_key = "backup" 20 resources_key = "backups" 21 base_path = "/backups" 22 23 # TODO(gtema): Starting from ~3.31(3.45) Cinder seems to support also fuzzy 24 # search (name~, status~, volume_id~). But this is not documented 25 # officially and seem to require microversion be set 26 _query_mapping = resource.QueryParameters( 27 'all_tenants', 'limit', 'marker', 'project_id', 28 'name', 'status', 'volume_id', 29 'sort_key', 'sort_dir') 30 31 # capabilities 32 allow_fetch = True 33 allow_create = True 34 allow_delete = True 35 allow_list = True 36 allow_get = True 37 38 #: Properties 39 #: backup availability zone 40 availability_zone = resource.Body("availability_zone") 41 #: The container backup in 42 container = resource.Body("container") 43 #: The date and time when the resource was created. 44 created_at = resource.Body("created_at") 45 #: data timestamp 46 #: The time when the data on the volume was first saved. 47 #: If it is a backup from volume, it will be the same as created_at 48 #: for a backup. If it is a backup from a snapshot, 49 #: it will be the same as created_at for the snapshot. 50 data_timestamp = resource.Body('data_timestamp') 51 #: backup description 52 description = resource.Body("description") 53 #: Backup fail reason 54 fail_reason = resource.Body("fail_reason") 55 #: Force backup 56 force = resource.Body("force", type=bool) 57 #: has_dependent_backups 58 #: If this value is true, there are other backups depending on this backup. 59 has_dependent_backups = resource.Body('has_dependent_backups', type=bool) 60 #: Indicates whether the backup mode is incremental. 61 #: If this value is true, the backup mode is incremental. 62 #: If this value is false, the backup mode is full. 63 is_incremental = resource.Body("is_incremental", type=bool) 64 #: A list of links associated with this volume. *Type: list* 65 links = resource.Body("links", type=list) 66 #: The backup metadata. New in version 3.43 67 metadata = resource.Body('metadata', type=dict) 68 #: backup name 69 name = resource.Body("name") 70 #: backup object count 71 object_count = resource.Body("object_count", type=int) 72 #: The UUID of the owning project. 73 #: New in version 3.18 74 project_id = resource.Body('os-backup-project-attr:project_id') 75 #: The size of the volume, in gibibytes (GiB). 76 size = resource.Body("size", type=int) 77 #: The UUID of the source volume snapshot. 78 snapshot_id = resource.Body("snapshot_id") 79 #: backup status 80 #: values: creating, available, deleting, error, restoring, error_restoring 81 status = resource.Body("status") 82 #: The date and time when the resource was updated. 83 updated_at = resource.Body("updated_at") 84 #: The UUID of the project owner. New in 3.56 85 user_id = resource.Body('user_id') 86 #: The UUID of the volume. 87 volume_id = resource.Body("volume_id") 88 89 def create(self, session, prepend_key=True, base_path=None, **params): 90 """Create a remote resource based on this instance. 91 92 :param session: The session to use for making this request. 93 :type session: :class:`~keystoneauth1.adapter.Adapter` 94 :param prepend_key: A boolean indicating whether the resource_key 95 should be prepended in a resource creation 96 request. Default to True. 97 :param str base_path: Base part of the URI for creating resources, if 98 different from 99 :data:`~openstack.resource.Resource.base_path`. 100 :param dict params: Additional params to pass. 101 :return: This :class:`Resource` instance. 102 :raises: :exc:`~openstack.exceptions.MethodNotSupported` if 103 :data:`Resource.allow_create` is not set to ``True``. 104 """ 105 if not self.allow_create: 106 raise exceptions.MethodNotSupported(self, "create") 107 108 session = self._get_session(session) 109 microversion = self._get_microversion_for(session, 'create') 110 requires_id = (self.create_requires_id 111 if self.create_requires_id is not None 112 else self.create_method == 'PUT') 113 114 if self.create_exclude_id_from_body: 115 self._body._dirty.discard("id") 116 117 if self.create_method == 'POST': 118 request = self._prepare_request(requires_id=requires_id, 119 prepend_key=prepend_key, 120 base_path=base_path) 121 # NOTE(gtema) this is a funny example of when attribute 122 # is called "incremental" on create, "is_incremental" on get 123 # and use of "alias" or "aka" is not working for such conflict, 124 # since our preferred attr name is exactly "is_incremental" 125 body = request.body 126 if 'is_incremental' in body['backup']: 127 body['backup']['incremental'] = \ 128 body['backup'].pop('is_incremental') 129 response = session.post(request.url, 130 json=request.body, headers=request.headers, 131 microversion=microversion, params=params) 132 else: 133 # Just for safety of the implementation (since PUT removed) 134 raise exceptions.ResourceFailure( 135 msg="Invalid create method: %s" % self.create_method) 136 137 has_body = (self.has_body if self.create_returns_body is None 138 else self.create_returns_body) 139 self.microversion = microversion 140 self._translate_response(response, has_body=has_body) 141 # direct comparision to False since we need to rule out None 142 if self.has_body and self.create_returns_body is False: 143 # fetch the body if it's required but not returned by create 144 return self.fetch(session) 145 return self 146 147 def restore(self, session, volume_id=None, name=None): 148 """Restore current backup to volume 149 150 :param session: openstack session 151 :param volume_id: The ID of the volume to restore the backup to. 152 :param name: The name for new volume creation to restore. 153 :return: Updated backup instance 154 """ 155 url = utils.urljoin(self.base_path, self.id, "restore") 156 body = {'restore': {}} 157 if volume_id: 158 body['restore']['volume_id'] = volume_id 159 if name: 160 body['restore']['name'] = name 161 if not (volume_id or name): 162 raise exceptions.SDKException('Either of `name` or `volume_id`' 163 ' must be specified.') 164 response = session.post(url, 165 json=body) 166 self._translate_response(response, has_body=False) 167 return self 168 169 170BackupDetail = Backup 171