]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: replace string version with class 43543/head
authorErnesto Puerta <epuertat@redhat.com>
Fri, 24 Sep 2021 15:46:42 +0000 (17:46 +0200)
committerNizamudeen A <nia@redhat.com>
Mon, 18 Oct 2021 10:46:00 +0000 (16:16 +0530)
* APIVersion:
  * Moved to a separate file
  * Added doctests
  * Added sentinel values:
    * DEFAULT = 1.0
    * EXPERIMENTAL = 0.1
    * NONE = 0.0
  * Added to_mime_type() helper method
* Controllers.__init__:
  * Added type hints
  * Replaced string versions with APIVersions
* Feedback controller:
  * Replaced with EXPERIMENTAL (probably it should be NONE)

Fixes: https://tracker.ceph.com/issues/52480
Signed-off-by: Ernesto Puerta <epuertat@redhat.com>
 Conflicts:
src/pybind/mgr/dashboard/controllers/__init__.py
   - Remove the current changes and keep the incoming new changes
src/pybind/mgr/dashboard/controllers/crush_rule.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/controllers/docs.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/controllers/feedback.py
   - Deleted the file since feedback module isn't backported to pacific
src/pybind/mgr/dashboard/controllers/host.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/openapi.yaml
   - Generated a new openapi yaml file
src/pybind/mgr/dashboard/tests/__init__.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/tests/test_docs.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/tests/test_host.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/tests/test_tools.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/tests/test_versioning.py
   - Changes related to the versioning like importing the APIVersion
src/pybind/mgr/dashboard/controllers/crush_rule.py
   - Removed the MethodMap decorator which updates the version of the
     enpoint to 2.0 because those changes which caused that version
     updating were not backported to pacific

12 files changed:
src/pybind/mgr/dashboard/__init__.py
src/pybind/mgr/dashboard/controllers/_version.py [new file with mode: 0644]
src/pybind/mgr/dashboard/controllers/crush_rule.py
src/pybind/mgr/dashboard/controllers/docs.py
src/pybind/mgr/dashboard/controllers/feedback.py [deleted file]
src/pybind/mgr/dashboard/controllers/host.py
src/pybind/mgr/dashboard/openapi.yaml
src/pybind/mgr/dashboard/tests/__init__.py
src/pybind/mgr/dashboard/tests/test_docs.py
src/pybind/mgr/dashboard/tests/test_host.py
src/pybind/mgr/dashboard/tests/test_tools.py
src/pybind/mgr/dashboard/tests/test_versioning.py

index b760ae661cd98dbcbcb07d5f95a06f26fb73af5a..feefda948163cb1962046b81c50b5c27adb1e44a 100644 (file)
@@ -6,36 +6,9 @@ ceph dashboard module
 from __future__ import absolute_import
 
 import os
-import re
-from typing import NamedTuple
 
 import cherrypy
 
-DEFAULT_API_VERSION = '1.0'
-
-
-class APIVersion(NamedTuple):
-    major: int = 1
-    minor: int = 0
-
-    @classmethod
-    def from_string(cls, version_string):
-        result = re.match(r'application/vnd\.ceph\.api\.v(\d+)\.(\d+)\+json', version_string)
-        if result:
-            return cls(*(int(s) for s in result.groups()))
-        return None
-
-    def __str__(self):
-        return f'{self.major}.{self.minor}'
-
-    def supports(self, client_version):
-        return self.major == client_version.major and client_version.minor <= self.minor
-
-    @staticmethod
-    def to_tuple(version: str):
-        return APIVersion(int(version.split('.')[0]), int(version.split('.')[1]))
-
-
 if 'COVERAGE_ENABLED' in os.environ:
     import coverage  # pylint: disable=import-error
     __cov = coverage.Coverage(config_file="{}/.coveragerc".format(os.path.dirname(__file__)),
diff --git a/src/pybind/mgr/dashboard/controllers/_version.py b/src/pybind/mgr/dashboard/controllers/_version.py
new file mode 100644 (file)
index 0000000..3e7331c
--- /dev/null
@@ -0,0 +1,75 @@
+import re
+from typing import NamedTuple
+
+
+class APIVersion(NamedTuple):
+    """
+    >>> APIVersion(1,0)
+    APIVersion(major=1, minor=0)
+
+    >>> APIVersion._make([1,0])
+    APIVersion(major=1, minor=0)
+
+    >>> f'{APIVersion(1, 0)!r}'
+    'APIVersion(major=1, minor=0)'
+    """
+    major: int
+    minor: int
+
+    DEFAULT = ...  # type: ignore
+    EXPERIMENTAL = ...  # type: ignore
+    NONE = ...  # type: ignore
+
+    __MIME_TYPE_REGEX = re.compile(  # type: ignore
+        r'^application/vnd\.ceph\.api\.v(\d+\.\d+)\+json$')
+
+    @classmethod
+    def from_string(cls, version_string: str) -> 'APIVersion':
+        """
+        >>> APIVersion.from_string("1.0")
+        APIVersion(major=1, minor=0)
+        """
+        return cls._make(int(s) for s in version_string.split('.'))
+
+    @classmethod
+    def from_mime_type(cls, mime_type: str) -> 'APIVersion':
+        """
+        >>> APIVersion.from_mime_type('application/vnd.ceph.api.v1.0+json')
+        APIVersion(major=1, minor=0)
+
+        """
+        return cls.from_string(cls.__MIME_TYPE_REGEX.match(mime_type).group(1))
+
+    def __str__(self):
+        """
+        >>> f'{APIVersion(1, 0)}'
+        '1.0'
+        """
+        return f'{self.major}.{self.minor}'
+
+    def to_mime_type(self, subtype='json'):
+        """
+        >>> APIVersion(1, 0).to_mime_type(subtype='xml')
+        'application/vnd.ceph.api.v1.0+xml'
+        """
+        return f'application/vnd.ceph.api.v{self!s}+{subtype}'
+
+    def supports(self, client_version: "APIVersion") -> bool:
+        """
+        >>> APIVersion(1, 1).supports(APIVersion(1, 0))
+        True
+
+        >>> APIVersion(1, 0).supports(APIVersion(1, 1))
+        False
+
+        >>> APIVersion(2, 0).supports(APIVersion(1, 1))
+        False
+        """
+        return (self.major == client_version.major
+                and client_version.minor <= self.minor)
+
+
+# Sentinel Values
+APIVersion.DEFAULT = APIVersion(1, 0)  # type: ignore
+APIVersion.EXPERIMENTAL = APIVersion(0, 1)  # type: ignore
+APIVersion.NONE = APIVersion(0, 0)  # type: ignore
index bd00d8feaf408b3ae6e3f57106789ed3f40ced2d..0310ab1c3d985c97f712353f97a3b5086fe97c36 100644 (file)
@@ -8,7 +8,6 @@ from .. import mgr
 from ..security import Scope
 from ..services.ceph_service import CephService
 from . import APIDoc, APIRouter, Endpoint, EndpointDoc, ReadPermission, RESTController, UIRouter
-from ._version import APIVersion
 
 LIST_SCHEMA = {
     "rule_id": (int, 'Rule ID'),
index 22aafeec6c3512eca64f3fe92cebe42bed198971..da040f86f89acbc34a977b20764635503a5e64b4 100644 (file)
@@ -2,11 +2,11 @@
 from __future__ import absolute_import
 
 import logging
-from typing import Any, Dict, List, Union
+from typing import Any, Dict, List, Optional, Union
 
 import cherrypy
 
-from .. import DEFAULT_API_VERSION, mgr
+from .. import mgr
 from ..api.doc import Schema, SchemaInput, SchemaType
 from . import ENDPOINT_MAP, BaseController, Endpoint, Router
 from ._version import APIVersion
@@ -186,7 +186,8 @@ class Docs(BaseController):
         return schema.as_dict()
 
     @classmethod
-    def _gen_responses(cls, method, resp_object=None, version=None):
+    def _gen_responses(cls, method, resp_object=None,
+                       version: Optional[APIVersion] = None):
         resp: Dict[str, Dict[str, Union[str, Any]]] = {
             '400': {
                 "description": "Operation exception. Please check the "
@@ -206,37 +207,38 @@ class Docs(BaseController):
         }
 
         if not version:
-            version = DEFAULT_API_VERSION
+            version = APIVersion.DEFAULT
 
         if method.lower() == 'get':
             resp['200'] = {'description': "OK",
-                           'content': {'application/vnd.ceph.api.v{}+json'.format(version):
+                           'content': {version.to_mime_type():
                                        {'type': 'object'}}}
         if method.lower() == 'post':
             resp['201'] = {'description': "Resource created.",
-                           'content': {'application/vnd.ceph.api.v{}+json'.format(version):
+                           'content': {version.to_mime_type():
                                        {'type': 'object'}}}
         if method.lower() == 'put':
             resp['200'] = {'description': "Resource updated.",
-                           'content': {'application/vnd.ceph.api.v{}+json'.format(version):
+                           'content': {version.to_mime_type():
                                        {'type': 'object'}}}
         if method.lower() == 'delete':
             resp['204'] = {'description': "Resource deleted.",
-                           'content': {'application/vnd.ceph.api.v{}+json'.format(version):
+                           'content': {version.to_mime_type():
                                        {'type': 'object'}}}
         if method.lower() in ['post', 'put', 'delete']:
             resp['202'] = {'description': "Operation is still executing."
                                           " Please check the task queue.",
-                           'content': {'application/vnd.ceph.api.v{}+json'.format(version):
+                           'content': {version.to_mime_type():
                                        {'type': 'object'}}}
 
         if resp_object:
             for status_code, response_body in resp_object.items():
                 if status_code in resp:
-                    resp[status_code].update({
-                        'content': {
-                            'application/vnd.ceph.api.v{}+json'.format(version): {
-                                'schema': cls._gen_schema_for_content(response_body)}}})
+                    resp[status_code].update(
+                        {'content':
+                         {version.to_mime_type():
+                          {'schema': cls._gen_schema_for_content(response_body)}
+                          }})
 
         return resp
 
@@ -288,7 +290,7 @@ class Docs(BaseController):
                 func = endpoint.func
 
                 summary = ''
-                version = ''
+                version = None
                 resp = {}
                 p_info = []
 
diff --git a/src/pybind/mgr/dashboard/controllers/feedback.py b/src/pybind/mgr/dashboard/controllers/feedback.py
deleted file mode 100644 (file)
index e1a9eb3..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-# # -*- coding: utf-8 -*-
-
-from ..exceptions import DashboardException
-from ..model.feedback import Feedback
-from ..rest_client import RequestException
-from ..security import Scope
-from ..services import feedback
-from . import APIDoc, APIRouter, RESTController
-
-
-@APIRouter('/feedback', Scope.CONFIG_OPT)
-@APIDoc("Feedback API", "Report")
-class FeedbackController(RESTController):
-    issueAPIkey = None
-
-    def __init__(self):  # pragma: no cover
-        super().__init__()
-        self.tracker_client = feedback.CephTrackerClient()
-
-    def create(self, project, tracker, subject, description):
-        """
-        Create an issue.
-        :param project: The affected ceph component.
-        :param tracker: The tracker type.
-        :param subject: The title of the issue.
-        :param description: The description of the issue.
-        """
-        try:
-            new_issue = Feedback(Feedback.Project[project].value,
-                                 Feedback.TrackerType[tracker].value, subject, description)
-        except KeyError:
-            raise DashboardException(msg=f'{"Invalid arguments"}', component='feedback')
-        try:
-            return self.tracker_client.create_issue(new_issue)
-        except RequestException as error:
-            if error.status_code == 401:
-                raise DashboardException(msg=f'{"Invalid API key"}',
-                                         http_status_code=error.status_code,
-                                         component='feedback')
-            raise error
-        except Exception:
-            raise DashboardException(msg=f'{"API key not set"}',
-                                     http_status_code=401,
-                                     component='feedback')
-
-    def get(self, issue_number):
-        """
-        Fetch issue details.
-        :param issueAPI: The issue tracker API access key.
-        """
-        try:
-            return self.tracker_client.get_issues(issue_number)
-        except RequestException as error:
-            if error.status_code == 404:
-                raise DashboardException(msg=f'Issue {issue_number} not found',
-                                         http_status_code=error.status_code,
-                                         component='feedback')
-            raise error
index b4d12c0b9312ad5da1a1bd6bde54d04b53c71bb5..53e73b654af2ca82eef4907d07615a5e5bdade21 100644 (file)
@@ -295,7 +295,7 @@ class Host(RESTController):
                      'status': (str, 'Host Status'),
                  },
                  responses={200: None, 204: None})
-    @RESTController.MethodMap(version='0.1')
+    @RESTController.MethodMap(version=APIVersion.EXPERIMENTAL)
     def create(self, hostname: str,
                addr: Optional[str] = None,
                labels: Optional[List[str]] = None,
@@ -408,7 +408,7 @@ class Host(RESTController):
                      'force': (bool, 'Force Enter Maintenance')
                  },
                  responses={200: None, 204: None})
-    @RESTController.MethodMap(version='0.1')
+    @RESTController.MethodMap(version=APIVersion.EXPERIMENTAL)
     def set(self, hostname: str, update_labels: bool = False,
             labels: List[str] = None, maintenance: bool = False,
             force: bool = False):
index c923b3441a6c3cb79c4e772cec7729ede2eeb405..921dadb0471d01011c3647591d0eb1d12aa587d3 100644 (file)
@@ -2656,85 +2656,6 @@ paths:
       summary: Get List Of Features
       tags:
       - FeatureTogglesEndpoint
-  /api/feedback:
-    post:
-      description: "\n        Create an issue.\n        :param project: The affected\
-        \ ceph component.\n        :param tracker: The tracker type.\n        :param\
-        \ subject: The title of the issue.\n        :param description: The description\
-        \ of the issue.\n        "
-      parameters: []
-      requestBody:
-        content:
-          application/json:
-            schema:
-              properties:
-                description:
-                  type: string
-                project:
-                  type: string
-                subject:
-                  type: string
-                tracker:
-                  type: string
-              required:
-              - project
-              - tracker
-              - subject
-              - description
-              type: object
-      responses:
-        '201':
-          content:
-            application/vnd.ceph.api.v1.0+json:
-              type: object
-          description: Resource created.
-        '202':
-          content:
-            application/vnd.ceph.api.v1.0+json:
-              type: object
-          description: Operation is still executing. Please check the task queue.
-        '400':
-          description: Operation exception. Please check the response body for details.
-        '401':
-          description: Unauthenticated access. Please login first.
-        '403':
-          description: Unauthorized access. Please check your permissions.
-        '500':
-          description: Unexpected error. Please check the response body for the stack
-            trace.
-      security:
-      - jwt: []
-      tags:
-      - Report
-  /api/feedback/{issue_number}:
-    get:
-      description: "\n        Fetch issue details.\n        :param issueAPI: The issue\
-        \ tracker API access key.\n        "
-      parameters:
-      - in: path
-        name: issue_number
-        required: true
-        schema:
-          type: integer
-      responses:
-        '200':
-          content:
-            application/vnd.ceph.api.v1.0+json:
-              type: object
-          description: OK
-        '400':
-          description: Operation exception. Please check the response body for details.
-        '401':
-          description: Unauthenticated access. Please login first.
-        '403':
-          description: Unauthorized access. Please check your permissions.
-        '500':
-          description: Unexpected error. Please check the response body for the stack
-            trace.
-      security:
-      - jwt: []
-      tags:
-      - Report
   /api/grafana/dashboards:
     post:
       parameters: []
@@ -10452,8 +10373,6 @@ tags:
   name: RbdSnapshot
 - description: RBD Trash Management API
   name: RbdTrash
-- description: Feedback API
-  name: Report
 - description: RGW Management API
   name: Rgw
 - description: RGW Bucket Management API
index a09fe6a9adb0c45162fdec181b2d24898846d95d..cda76600939772517269ab8d50e3cf44bff4355a 100644 (file)
@@ -14,7 +14,7 @@ from cherrypy.test import helper
 from mgr_module import HandleCommandResult
 from pyfakefs import fake_filesystem
 
-from .. import DEFAULT_API_VERSION, mgr
+from .. import mgr
 from ..controllers import generate_controller_routes, json_error_page
 from ..controllers._version import APIVersion
 from ..module import Module
@@ -154,18 +154,18 @@ class ControllerTestCase(helper.CPWebCase):
         if cls._request_logging:
             cherrypy.config.update({'tools.request_logging.on': False})
 
-    def _request(self, url, method, data=None, headers=None, version=DEFAULT_API_VERSION):
+    def _request(self, url, method, data=None, headers=None, version=APIVersion.DEFAULT):
         if not data:
             b = None
             if version:
-                h = [('Accept', 'application/vnd.ceph.api.v{}+json'.format(version)),
+                h = [('Accept', version.to_mime_type()),
                      ('Content-Length', '0')]
             else:
                 h = None
         else:
             b = json.dumps(data)
             if version is not None:
-                h = [('Accept', 'application/vnd.ceph.api.v{}+json'.format(version)),
+                h = [('Accept', version.to_mime_type()),
                      ('Content-Type', 'application/json'),
                      ('Content-Length', str(len(b)))]
 
@@ -177,19 +177,19 @@ class ControllerTestCase(helper.CPWebCase):
             h = headers
         self.getPage(url, method=method, body=b, headers=h)
 
-    def _get(self, url, headers=None, version=DEFAULT_API_VERSION):
+    def _get(self, url, headers=None, version=APIVersion.DEFAULT):
         self._request(url, 'GET', headers=headers, version=version)
 
-    def _post(self, url, data=None, version=DEFAULT_API_VERSION):
+    def _post(self, url, data=None, version=APIVersion.DEFAULT):
         self._request(url, 'POST', data, version=version)
 
-    def _delete(self, url, data=None, version=DEFAULT_API_VERSION):
+    def _delete(self, url, data=None, version=APIVersion.DEFAULT):
         self._request(url, 'DELETE', data, version=version)
 
-    def _put(self, url, data=None, version=DEFAULT_API_VERSION):
+    def _put(self, url, data=None, version=APIVersion.DEFAULT):
         self._request(url, 'PUT', data, version=version)
 
-    def _task_request(self, method, url, data, timeout, version=DEFAULT_API_VERSION):
+    def _task_request(self, method, url, data, timeout, version=APIVersion.DEFAULT):
         self._request(url, method, data, version=version)
         if self.status != '202 Accepted':
             logger.info("task finished immediately")
@@ -255,13 +255,13 @@ class ControllerTestCase(helper.CPWebCase):
             self.status = 500
         self.body = json.dumps(thread.res_task['exception'])
 
-    def _task_post(self, url, data=None, timeout=60, version=DEFAULT_API_VERSION):
+    def _task_post(self, url, data=None, timeout=60, version=APIVersion.DEFAULT):
         self._task_request('POST', url, data, timeout, version=version)
 
-    def _task_delete(self, url, timeout=60, version=DEFAULT_API_VERSION):
+    def _task_delete(self, url, timeout=60, version=APIVersion.DEFAULT):
         self._task_request('DELETE', url, None, timeout, version=version)
 
-    def _task_put(self, url, data=None, timeout=60, version=DEFAULT_API_VERSION):
+    def _task_put(self, url, data=None, timeout=60, version=APIVersion.DEFAULT):
         self._task_request('PUT', url, data, timeout, version=version)
 
     def json_body(self):
index 1e6abbc0c8cda054c7fa43b090bd45c679b55f19..d0529ab8d82333ecc357ea9477aa6b9283052378 100644 (file)
@@ -30,11 +30,11 @@ class DecoratedController(RESTController):
         },
     )
     @Endpoint(json_response=False)
-    @RESTController.Resource('PUT', version='0.1')
+    @RESTController.Resource('PUT', version=APIVersion(0, 1))
     def decorated_func(self, parameter):
         pass
 
-    @RESTController.MethodMap(version='0.1')
+    @RESTController.MethodMap(version=APIVersion(0, 1))
     def list(self):
         pass
 
@@ -87,7 +87,7 @@ class DocsTest(ControllerTestCase):
 
         expected_response_content = {
             '200': {
-                'application/vnd.ceph.api.v0.1+json': {
+                APIVersion(0, 1).to_mime_type(): {
                     'schema': {'type': 'array',
                                'items': {'type': 'object', 'properties': {
                                    'my_prop': {
@@ -95,7 +95,7 @@ class DocsTest(ControllerTestCase):
                                        'description': '200 property desc.'}}},
                                'required': ['my_prop']}}},
             '202': {
-                'application/vnd.ceph.api.v0.1+json': {
+                APIVersion(0, 1).to_mime_type(): {
                     'schema': {'type': 'object',
                                'properties': {'my_prop': {
                                    'type': 'string',
@@ -111,7 +111,7 @@ class DocsTest(ControllerTestCase):
     def test_gen_method_paths(self):
         outcome = Docs().gen_paths(False)['/api/doctest/']['get']
 
-        self.assertEqual({'application/vnd.ceph.api.v0.1+json': {'type': 'object'}},
+        self.assertEqual({APIVersion(0, 1).to_mime_type(): {'type': 'object'}},
                          outcome['responses']['200']['content'])
 
     def test_gen_paths_all(self):
index 003d955adc95e2b92468d7947f7b2c4262dfc8b1..8b1e03b0ce31721262350b2a75b4c38977996d8f 100644 (file)
@@ -136,7 +136,7 @@ class HostControllerTest(ControllerTestCase):
                 'labels': 'mon',
                 'status': 'maintenance'
             }
-            self._post(self.URL_HOST, payload, version='0.1')
+            self._post(self.URL_HOST, payload, version=APIVersion(0, 1))
             self.assertStatus(201)
             mock_add_host.assert_called()
 
@@ -150,7 +150,7 @@ class HostControllerTest(ControllerTestCase):
             fake_client.hosts.add_label = mock.Mock()
 
             payload = {'update_labels': True, 'labels': ['bbb', 'ccc']}
-            self._put('{}/node0'.format(self.URL_HOST), payload, version='0.1')
+            self._put('{}/node0'.format(self.URL_HOST), payload, version=APIVersion(0, 1))
             self.assertStatus(200)
             self.assertHeader('Content-Type',
                               'application/vnd.ceph.api.v0.1+json')
@@ -158,8 +158,9 @@ class HostControllerTest(ControllerTestCase):
             fake_client.hosts.add_label.assert_called_once_with('node0', 'ccc')
 
             # return 400 if type other than List[str]
-            self._put('{}/node0'.format(self.URL_HOST), {'update_labels': True,
-                                                         'labels': 'ddd'}, version='0.1')
+            self._put('{}/node0'.format(self.URL_HOST),
+                      {'update_labels': True, 'labels': 'ddd'},
+                      version=APIVersion(0, 1))
             self.assertStatus(400)
 
     def test_host_maintenance(self):
@@ -170,25 +171,29 @@ class HostControllerTest(ControllerTestCase):
         ]
         with patch_orch(True, hosts=orch_hosts):
             # enter maintenance mode
-            self._put('{}/node0'.format(self.URL_HOST), {'maintenance': True}, version='0.1')
+            self._put('{}/node0'.format(self.URL_HOST), {'maintenance': True},
+                      version=APIVersion(0, 1))
             self.assertStatus(200)
             self.assertHeader('Content-Type',
                               'application/vnd.ceph.api.v0.1+json')
 
             # force enter maintenance mode
             self._put('{}/node1'.format(self.URL_HOST), {'maintenance': True, 'force': True},
-                      version='0.1')
+                      version=APIVersion(0, 1))
             self.assertStatus(200)
 
             # exit maintenance mode
-            self._put('{}/node0'.format(self.URL_HOST), {'maintenance': True}, version='0.1')
+            self._put('{}/node0'.format(self.URL_HOST), {'maintenance': True},
+                      version=APIVersion(0, 1))
             self.assertStatus(200)
-            self._put('{}/node1'.format(self.URL_HOST), {'maintenance': True}, version='0.1')
+            self._put('{}/node1'.format(self.URL_HOST), {'maintenance': True},
+                      version=APIVersion(0, 1))
             self.assertStatus(200)
 
         # maintenance without orchestrator service
         with patch_orch(False):
-            self._put('{}/node0'.format(self.URL_HOST), {'maintenance': True}, version='0.1')
+            self._put('{}/node0'.format(self.URL_HOST), {'maintenance': True},
+                      version=APIVersion(0, 1))
             self.assertStatus(503)
 
     @mock.patch('dashboard.controllers.host.time')
index 4edb458b955d766df2262047e9b0443da927f0d6..f1e4ae7e157f4e7746816161c031815986659031 100644 (file)
@@ -11,7 +11,6 @@ try:
 except ImportError:
     from unittest.mock import patch
 
-from .. import DEFAULT_API_VERSION
 from ..controllers import APIRouter, BaseController, Proxy, RESTController, Router
 from ..controllers._version import APIVersion
 from ..services.exception import handle_rados_error
@@ -88,8 +87,7 @@ class RESTControllerTest(ControllerTestCase):
         self.assertStatus(204)
         self._get("/foo")
         self.assertStatus('200 OK')
-        self.assertHeader('Content-Type',
-                          'application/vnd.ceph.api.v{}+json'.format(DEFAULT_API_VERSION))
+        self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
         self.assertBody('[]')
 
     def test_fill(self):
@@ -100,19 +98,16 @@ class RESTControllerTest(ControllerTestCase):
                 self._post("/foo", data)
                 self.assertJsonBody(data)
                 self.assertStatus(201)
-                self.assertHeader('Content-Type',
-                                  'application/vnd.ceph.api.v{}+json'.format(DEFAULT_API_VERSION))
+                self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
 
             self._get("/foo")
             self.assertStatus('200 OK')
-            self.assertHeader('Content-Type',
-                              'application/vnd.ceph.api.v{}+json'.format(DEFAULT_API_VERSION))
+            self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
             self.assertJsonBody([data] * 5)
 
             self._put('/foo/0', {'newdata': 'newdata'})
             self.assertStatus('200 OK')
-            self.assertHeader('Content-Type',
-                              'application/vnd.ceph.api.v{}+json'.format(DEFAULT_API_VERSION))
+            self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
             self.assertJsonBody({'newdata': 'newdata', 'key': '0'})
 
     def test_not_implemented(self):
index ae153e3e18d9af2f60edc5d5ac93947070fda369..48e6394c2cf0466849da500697e9d8d3acb84eb8 100644 (file)
@@ -13,22 +13,22 @@ from . import ControllerTestCase  # pylint: disable=no-name-in-module
 class VTest(RESTController):
     RESOURCE_ID = "vid"
 
-    @RESTController.MethodMap(version="0.1")
+    @RESTController.MethodMap(version=APIVersion(0, 1))
     def list(self):
         return {'version': ""}
 
     def get(self):
         return {'version': ""}
 
-    @RESTController.Collection('GET', version="1.0")
+    @RESTController.Collection('GET', version=APIVersion(1, 0))
     def vmethod(self):
         return {'version': '1.0'}
 
-    @RESTController.Collection('GET', version="1.1")
+    @RESTController.Collection('GET', version=APIVersion(1, 1))
     def vmethodv1_1(self):
         return {'version': '1.1'}
 
-    @RESTController.Collection('GET', version="2.0")
+    @RESTController.Collection('GET', version=APIVersion(2, 0))
     def vmethodv2(self):
         return {'version': '2.0'}
 
@@ -40,37 +40,40 @@ class RESTVersioningTest(ControllerTestCase, unittest.TestCase):
 
     def test_list(self):
         for (version, expected_status) in [
-                ("0.1", 200),
-                ("2.0", 415)
+                ((0, 1), 200),
+                ((2, 0), 415)
         ]:
             with self.subTest(version=version):
-                self._get('/test/api/vtest', version=version)
+                self._get('/test/api/vtest', version=APIVersion._make(version))
                 self.assertStatus(expected_status)
 
     def test_v1(self):
         for (version, expected_status) in [
-                ("1.0", 200),
-                ("2.0", 415)
+                ((1, 0), 200),
+                ((2, 0), 415)
         ]:
             with self.subTest(version=version):
-                self._get('/test/api/vtest/vmethod', version=version)
+                self._get('/test/api/vtest/vmethod',
+                          version=APIVersion._make(version))
                 self.assertStatus(expected_status)
 
     def test_v2(self):
         for (version, expected_status) in [
-                ("2.0", 200),
-                ("1.0", 415)
+                ((2, 0), 200),
+                ((1, 0), 415)
         ]:
             with self.subTest(version=version):
-                self._get('/test/api/vtest/vmethodv2', version=version)
+                self._get('/test/api/vtest/vmethodv2',
+                          version=APIVersion._make(version))
                 self.assertStatus(expected_status)
 
     def test_backward_compatibility(self):
         for (version, expected_status) in [
-                ("1.1", 200),
-                ("1.0", 200),
-                ("2.0", 415)
+                ((1, 1), 200),
+                ((1, 0), 200),
+                ((2, 0), 415)
         ]:
             with self.subTest(version=version):
-                self._get('/test/api/vtest/vmethodv1_1', version=version)
+                self._get('/test/api/vtest/vmethodv1_1',
+                          version=APIVersion._make(version))
                 self.assertStatus(expected_status)