# Copyright 2014 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import re from tempest.lib import exceptions # Define the minimum and maximum version of the API across all of the # REST API. The format of the version is: # X.Y where: # # - X will only be changed if a significant backwards incompatible API # change is made which affects the API as whole. That is, something # that is only very very rarely incremented. # # - Y when you make any change to the API. Note that this includes # semantic changes which may not affect the input or output formats or # even originate in the API code layer. We are not distinguishing # between backwards compatible and backwards incompatible changes in # the versioning system. It must be made clear in the documentation as # to what is a backwards compatible change and what is a backwards # incompatible one. class APIVersionRequest(object): """This class represents an API Version Request. This class provides convenience methods for manipulation and comparison of version numbers that we need to do to implement microversions. :param version_string: String representation of APIVersionRequest. Correct format is 'X.Y', where 'X' and 'Y' are int values. None value should be used to create Null APIVersionRequest, which is equal to 0.0 """ # NOTE: This 'latest' version is a magic number, we assume any # projects(Nova, etc.) never achieve this number. latest_ver_major = 99999 latest_ver_minor = 99999 def __init__(self, version_string=None): """Create an API version request object.""" # NOTE(gmann): 'version_string' as String "None" will be considered as # invalid version string. self.ver_major = 0 self.ver_minor = 0 if version_string is not None: match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)$", version_string) if match: self.ver_major = int(match.group(1)) self.ver_minor = int(match.group(2)) elif version_string == 'latest': self.ver_major = self.latest_ver_major self.ver_minor = self.latest_ver_minor else: raise exceptions.InvalidAPIVersionString( version=version_string) def __str__(self): """Debug/Logging representation of object.""" return ("API Version Request: %s" % self.get_string()) def is_null(self): """Checks whether version is null. Return True if version object is null otherwise False. :returns: boolean """ return self.ver_major == 0 and self.ver_minor == 0 def _format_type_error(self, other): return TypeError("'%(other)s' should be an instance of '%(cls)s'" % {"other": other, "cls": self.__class__}) def __lt__(self, other): if not isinstance(other, APIVersionRequest): raise self._format_type_error(other) return ((self.ver_major, self.ver_minor) < (other.ver_major, other.ver_minor)) def __eq__(self, other): if not isinstance(other, APIVersionRequest): raise self._format_type_error(other) return ((self.ver_major, self.ver_minor) == (other.ver_major, other.ver_minor)) def __gt__(self, other): if not isinstance(other, APIVersionRequest): raise self._format_type_error(other) return ((self.ver_major, self.ver_minor) > (other.ver_major, other.ver_minor)) def __le__(self, other): return self < other or self == other def __ne__(self, other): return not self.__eq__(other) def __ge__(self, other): return self > other or self == other def matches(self, min_version, max_version): """Matches the version object. Returns whether the version object represents a version greater than or equal to the minimum version and less than or equal to the maximum version. :param min_version: Minimum acceptable version. :param max_version: Maximum acceptable version. :returns: boolean If min_version is null then there is no minimum limit. If max_version is null then there is no maximum limit. If self is null then raise ValueError """ if self.is_null(): raise ValueError if max_version.is_null() and min_version.is_null(): return True elif max_version.is_null(): return min_version <= self elif min_version.is_null(): return self <= max_version else: return min_version <= self <= max_version def get_string(self): """Version string representation. Converts object to string representation which if used to create an APIVersionRequest object results in the same version request. """ if self.is_null(): return None if (self.ver_major == self.latest_ver_major and self.ver_minor == self.latest_ver_minor): return 'latest' return "%s.%s" % (self.ver_major, self.ver_minor)