1# Copyright 2014 IBM Corp.
2# Copyright 2015 Clinton Knight
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
17import re
18
19from cinder.api.openstack import versioned_method
20from cinder import exception
21from cinder.i18n import _
22from cinder import utils
23
24# Define the minimum and maximum version of the API across all of the
25# REST API. The format of the version is:
26# X.Y where:
27#
28# - X will only be changed if a significant backwards incompatible API
29# change is made which affects the API as whole. That is, something
30# that is only very very rarely incremented.
31#
32# - Y when you make any change to the API. Note that this includes
33# semantic changes which may not affect the input or output formats or
34# even originate in the API code layer. We are not distinguishing
35# between backwards compatible and backwards incompatible changes in
36# the versioning system. It must be made clear in the documentation as
37# to what is a backwards compatible change and what is a backwards
38# incompatible one.
39
40#
41# You must update the API version history string below with a one or
42# two line description as well as update rest_api_version_history.rst
43REST_API_VERSION_HISTORY = """
44
45    REST API Version History:
46
47    * 3.0 - Includes all V2 APIs and extensions. V1 API is still supported.
48    * 3.0 - Versions API updated to reflect beginning of microversions epoch.
49    * 3.1 - Adds visibility and protected to _volume_upload_image parameters.
50    * 3.2 - Bootable filters in volume GET call no longer treats all values
51            passed to it as true.
52    * 3.3 - Add user messages APIs.
53    * 3.4 - Adds glance_metadata filter to list/detail volumes in _get_volumes.
54    * 3.5 - Add pagination support to messages API.
55    * 3.6 - Allows to set empty description and empty name for consistency
56            group in consisgroup-update operation.
57    * 3.7 - Add cluster API and cluster_name field to service list API
58    * 3.8 - Adds resources from volume_manage and snapshot_manage extensions.
59    * 3.9 - Add backup update interface.
60    * 3.10 - Add group_id filter to list/detail volumes in _get_volumes.
61    * 3.11 - Add group types and group specs API.
62    * 3.12 - Add volumes summary API.
63    * 3.13 - Add generic volume groups API.
64    * 3.14 - Add group snapshot and create group from src APIs.
65    * 3.15 - Inject the response's `Etag` header to avoid the lost update
66             problem with volume metadata.
67    * 3.16 - Migrate volume now supports cluster
68    * 3.17 - Getting manageable volumes and snapshots now accepts cluster.
69    * 3.18 - Add backup project attribute.
70    * 3.19 - Add API reset status actions 'reset_status' to group snapshot.
71    * 3.20 - Add API reset status actions 'reset_status' to generic
72             volume group.
73    * 3.21 - Show provider_id in detailed view of a volume for admin.
74    * 3.22 - Add filtering based on metadata for snapshot listing.
75    * 3.23 - Allow passing force parameter to volume delete.
76    * 3.24 - Add workers/cleanup endpoint.
77    * 3.25 - Add ``volumes`` field to group list/detail and group show.
78    * 3.26 - Add failover action and cluster listings accept new filters and
79             return new data.
80    * 3.27 - Add attachment API
81    * 3.28 - Add filters support to get_pools
82    * 3.29 - Add filter, sorter and pagination support in group snapshot.
83    * 3.30 - Support sort snapshots with "name".
84    * 3.31 - Add support for configure resource query filters.
85    * 3.32 - Add set-log and get-log service actions.
86    * 3.33 - Add ``resource_filters`` API to retrieve configured
87             resource filters.
88    * 3.34 - Add like filter support in ``volume``, ``backup``, ``snapshot``,
89             ``message``, ``attachment``, ``group`` and ``group-snapshot``
90             list APIs.
91    * 3.35 - Add ``volume-type`` filter to Get-Pools API.
92    * 3.36 - Add metadata to volumes/summary response body.
93    * 3.37 - Support sort backup by "name".
94    * 3.38 - Add replication group API (Tiramisu).
95    * 3.39 - Add ``project_id`` admin filters support to limits.
96    * 3.40 - Add volume revert to its latest snapshot support.
97    * 3.41 - Add ``user_id`` field to snapshot list/detail and snapshot show.
98    * 3.42 - Add ability to extend 'in-use' volume. User should be aware of the
99             whole environment before using this feature because it's dependent
100             on several external factors below:
101             1. nova-compute version - needs to be the latest for Pike.
102             2. only the libvirt compute driver supports this currently.
103             3. only iscsi and fibre channel volume types are supported
104                on the nova side currently.
105             Administrator can disable this ability by updating the
106             'volume:extend_attached_volume' policy rule. Extend in reserved
107             state is intentionally NOT allowed.
108    * 3.43 - Support backup CRUD with metadata.
109    * 3.44 - Add attachment-complete.
110    * 3.45 - Add ``count`` field to volume, backup and snapshot list and
111             detail APIs.
112    * 3.46 - Support create volume by Nova specific image (0 size image).
113    * 3.47 - Support create volume from backup.
114    * 3.48 - Add ``shared_targets`` and ``service_uuid`` fields to volume.
115    * 3.49 - Support report backend storage state in service list.
116    * 3.50 - Add multiattach capability
117"""
118
119# The minimum and maximum versions of the API supported
120# The default api version request is defined to be the
121# minimum version of the API supported.
122# Explicitly using /v2 endpoints will still work
123_MIN_API_VERSION = "3.0"
124_MAX_API_VERSION = "3.50"
125_LEGACY_API_VERSION2 = "2.0"
126UPDATED = "2017-09-19T20:18:14Z"
127
128
129# NOTE(cyeoh): min and max versions declared as functions so we can
130# mock them for unittests. Do not use the constants directly anywhere
131# else.
132def min_api_version():
133    return APIVersionRequest(_MIN_API_VERSION)
134
135
136def max_api_version():
137    return APIVersionRequest(_MAX_API_VERSION)
138
139
140def legacy_api_version2():
141    return APIVersionRequest(_LEGACY_API_VERSION2)
142
143
144class APIVersionRequest(utils.ComparableMixin):
145    """This class represents an API Version Request.
146
147    This class includes convenience methods for manipulation
148    and comparison of version numbers as needed to implement
149    API microversions.
150    """
151
152    def __init__(self, version_string=None, experimental=False):
153        """Create an API version request object."""
154        self._ver_major = None
155        self._ver_minor = None
156
157        if version_string is not None:
158            match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)$",
159                             version_string)
160            if match:
161                self._ver_major = int(match.group(1))
162                self._ver_minor = int(match.group(2))
163            else:
164                raise exception.InvalidAPIVersionString(version=version_string)
165
166    def __str__(self):
167        """Debug/Logging representation of object."""
168        return ("API Version Request Major: %(major)s, Minor: %(minor)s"
169                % {'major': self._ver_major, 'minor': self._ver_minor})
170
171    def __bool__(self):
172        return (self._ver_major or self._ver_minor) is not None
173
174    __nonzero__ = __bool__
175
176    def _cmpkey(self):
177        """Return the value used by ComparableMixin for rich comparisons."""
178        return self._ver_major, self._ver_minor
179
180    def matches_versioned_method(self, method):
181        """Compares this version to that of a versioned method."""
182
183        if type(method) != versioned_method.VersionedMethod:
184            msg = _('An API version request must be compared '
185                    'to a VersionedMethod object.')
186            raise exception.InvalidParameterValue(err=msg)
187
188        return self.matches(method.start_version,
189                            method.end_version,
190                            method.experimental)
191
192    def matches(self, min_version, max_version=None, experimental=False):
193        """Compares this version to the specified min/max range.
194
195        Returns whether the version object represents a version
196        greater than or equal to the minimum version and less than
197        or equal to the maximum version.
198
199        If min_version is null then there is no minimum limit.
200        If max_version is null then there is no maximum limit.
201        If self is null then raise ValueError.
202
203        :param min_version: Minimum acceptable version.
204        :param max_version: Maximum acceptable version.
205        :param experimental: Whether to match experimental APIs.
206        :returns: boolean
207        """
208
209        if not self:
210            raise ValueError
211
212        if isinstance(min_version, str):
213            min_version = APIVersionRequest(version_string=min_version)
214        if isinstance(max_version, str):
215            max_version = APIVersionRequest(version_string=max_version)
216
217        if not min_version and not max_version:
218            return True
219
220        if not max_version:
221            return min_version <= self
222        if not min_version:
223            return self <= max_version
224        return min_version <= self <= max_version
225
226    def get_string(self):
227        """Returns a string representation of this object.
228
229        If this method is used to create an APIVersionRequest,
230        the resulting object will be an equivalent request.
231        """
232        if not self:
233            raise ValueError
234        return ("%(major)s.%(minor)s" %
235                {'major': self._ver_major, 'minor': self._ver_minor})
236