Coverage for watcher/api/controllers/base.py: 94%

57 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-17 12:22 +0000

1# -*- encoding: utf-8 -*- 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 

12# implied. 

13# See the License for the specific language governing permissions and 

14# limitations under the License. 

15 

16import datetime 

17import functools 

18 

19import microversion_parse 

20from webob import exc 

21import wsme 

22from wsme import types as wtypes 

23 

24 

25class APIBase(wtypes.Base): 

26 

27 created_at = wsme.wsattr(datetime.datetime, readonly=True) 

28 """The time in UTC at which the object is created""" 

29 

30 updated_at = wsme.wsattr(datetime.datetime, readonly=True) 

31 """The time in UTC at which the object is updated""" 

32 

33 deleted_at = wsme.wsattr(datetime.datetime, readonly=True) 

34 """The time in UTC at which the object is deleted""" 

35 

36 def as_dict(self): 

37 """Render this object as a dict of its fields.""" 

38 return dict((k, getattr(self, k)) 

39 for k in self.fields 

40 if hasattr(self, k) and 

41 getattr(self, k) != wsme.Unset) 

42 

43 def unset_fields_except(self, except_list=None): 

44 """Unset fields so they don't appear in the message body. 

45 

46 :param except_list: A list of fields that won't be touched. 

47 

48 """ 

49 if except_list is None: 49 ↛ 50line 49 didn't jump to line 50 because the condition on line 49 was never true

50 except_list = [] 

51 

52 for k in self.as_dict(): 

53 if k not in except_list: 

54 setattr(self, k, wsme.Unset) 

55 

56 

57@functools.total_ordering 

58class Version(object): 

59 """API Version object.""" 

60 

61 string = 'OpenStack-API-Version' 

62 """HTTP Header string carrying the requested version""" 

63 

64 min_string = 'OpenStack-API-Minimum-Version' 

65 """HTTP response header""" 

66 

67 max_string = 'OpenStack-API-Maximum-Version' 

68 """HTTP response header""" 

69 

70 def __init__(self, headers, default_version, latest_version): 

71 """Create an API Version object from the supplied headers. 

72 

73 :param headers: webob headers 

74 :param default_version: version to use if not specified in headers 

75 :param latest_version: version to use if latest is requested 

76 :raises: webob.HTTPNotAcceptable 

77 

78 """ 

79 (self.major, self.minor) = Version.parse_headers( 

80 headers, default_version, latest_version) 

81 

82 def __repr__(self): 

83 return '%s.%s' % (self.major, self.minor) 

84 

85 @staticmethod 

86 def parse_headers(headers, default_version, latest_version): 

87 """Determine the API version requested based on the headers supplied. 

88 

89 :param headers: webob headers 

90 :param default_version: version to use if not specified in headers 

91 :param latest_version: version to use if latest is requested 

92 :returns: a tuple of (major, minor) version numbers 

93 :raises: webob.HTTPNotAcceptable 

94 

95 """ 

96 version_str = microversion_parse.get_version( 

97 headers, 

98 service_type='infra-optim') 

99 

100 minimal_version = (1, 0) 

101 

102 if version_str is None: 

103 # If requested header is wrong, Watcher answers with the minimal 

104 # supported version. 

105 return minimal_version 

106 

107 if version_str.lower() == 'latest': 

108 parse_str = latest_version 

109 else: 

110 parse_str = version_str 

111 

112 try: 

113 version = tuple(int(i) for i in parse_str.split('.')) 

114 except ValueError: 

115 version = minimal_version 

116 

117 # NOTE (alexchadin): Old python-watcherclient sends requests with 

118 # value of version header is "1". It should be transformed to 1.0 as 

119 # it was supposed to be. 

120 if len(version) == 1 and version[0] == 1: 

121 version = minimal_version 

122 

123 if len(version) != 2: 

124 raise exc.HTTPNotAcceptable( 

125 "Invalid value for %s header" % Version.string) 

126 return version 

127 

128 def __gt__(self, other): 

129 return (self.major, self.minor) > (other.major, other.minor) 

130 

131 def __eq__(self, other): 

132 return (self.major, self.minor) == (other.major, other.minor) 

133 

134 def __ne__(self, other): 

135 return not self.__eq__(other)