Skip to content

Commit c8fbb02

Browse files
author
Matthew Fisher
committed
Merge pull request #2567 from bacongobbler/2548-api-version
feat(controller): check client against API version
2 parents e0e9b71 + 3001ab0 commit c8fbb02

9 files changed

Lines changed: 1052 additions & 14 deletions

File tree

client/deis.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070

7171
__version__ = '1.1.0-dev'
7272

73+
# what version of the API is this client compatible with?
74+
__api_version__ = '1.1'
75+
7376

7477
locale.setlocale(locale.LC_ALL, '')
7578

@@ -392,10 +395,18 @@ def _dispatch(self, method, path, body=None, **kwargs):
392395
url = urlparse.urljoin(controller, path, **kwargs)
393396
headers = {
394397
'content-type': 'application/json',
395-
'X-Deis-Version': __version__.rsplit('.', 1)[0],
398+
'X-Deis-Version': __api_version__.rsplit('.', 1)[0],
396399
'Authorization': 'token {}'.format(token)
397400
}
398401
response = func(url, data=body, headers=headers)
402+
# check for version mismatch
403+
server_api_version = response.headers.get('X_DEIS_API_VERSION')
404+
if server_api_version is not None and server_api_version != __api_version__:
405+
self._logger.warning("""
406+
! WARNING: Client and server API versions do not match. Please consider upgrading.
407+
! Client version: {}
408+
! Server version: {}
409+
""".format(__api_version__, server_api_version))
399410
return response
400411

401412
def apps(self, args):

controller/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
"""
22
The **api** Django app presents a RESTful web API for interacting with the **deis** system.
33
"""
4+
5+
__version__ = '1.1.0'

controller/api/middleware.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
from django.http import HttpResponse
44
from rest_framework import status
55

6-
from deis import __version__
6+
from api import __version__
77

88

9-
class VersionMiddleware:
9+
class APIVersionMiddleware:
1010

1111
def process_request(self, request):
1212
try:
13-
# server and client version must match "x.y"
13+
# server and client version must match the major release point
1414
client_version = request.META['HTTP_X_DEIS_VERSION']
15-
server_version = __version__.rsplit('.', 1)[0]
15+
server_version = __version__.rsplit('.', 2)[0]
1616
if client_version != server_version:
1717
message = {
1818
'error': 'Client and server versions do not match. ' +
@@ -26,3 +26,8 @@ def process_request(self, request):
2626
)
2727
except KeyError:
2828
pass
29+
30+
def process_response(self, request, response):
31+
# clients shouldn't care about the patch release
32+
response['X_DEIS_API_VERSION'] = __version__.rsplit('.', 1)[0]
33+
return response

controller/api/tests/test_api_middleware.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.test import TestCase
1010
from rest_framework.authtoken.models import Token
1111

12-
from deis import __version__
12+
from api import __version__
1313

1414

1515
class APIMiddlewareTest(TestCase):
@@ -28,10 +28,12 @@ def test_x_deis_version_header_good(self):
2828
"""
2929
response = self.client.get(
3030
'/v1/apps',
31-
HTTP_X_DEIS_VERSION=__version__.rsplit('.', 1)[0],
31+
HTTP_X_DEIS_VERSION=__version__.rsplit('.', 2)[0],
3232
HTTP_AUTHORIZATION='token {}'.format(self.token),
3333
)
3434
self.assertEqual(response.status_code, 200)
35+
self.assertEqual(response.has_header('X_DEIS_API_VERSION'), True)
36+
self.assertEqual(response['X_DEIS_API_VERSION'], __version__.rsplit('.', 1)[0])
3537

3638
def test_x_deis_version_header_bad(self):
3739
"""

controller/deis/middleware.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from deis import __version__
2+
3+
4+
class PlatformVersionMiddleware:
5+
6+
def process_response(self, request, response):
7+
response['X_DEIS_PLATFORM_VERSION'] = __version__
8+
return response

controller/deis/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@
107107
'django.contrib.sessions.middleware.SessionMiddleware',
108108
'django.contrib.auth.middleware.AuthenticationMiddleware',
109109
'django.contrib.messages.middleware.MessageMiddleware',
110-
'api.middleware.VersionMiddleware',
110+
'api.middleware.APIVersionMiddleware',
111+
'deis.middleware.PlatformVersionMiddleware',
111112
# Uncomment the next line for simple clickjacking protection:
112113
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
113114
)
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
:title: Controller API v1.0
2-
:description: The v1 REST API for Deis' Controller
3-
4-
.. _controller_api_v1:
2+
:description: The v1.0 REST API for Deis' Controller
53

64
Controller API v1.0
75
===================
@@ -764,7 +762,7 @@ Example Response:
764762
765763
HTTP/1.1 201 CREATED
766764
Content-Type: application/json
767-
765+
768766
{"version": 5}
769767
770768
@@ -940,4 +938,4 @@ Example Response:
940938

941939
.. code-block:: console
942940
943-
HTTP/1.1 201 CREATED
941+
HTTP/1.1 201 CREATED

0 commit comments

Comments
 (0)