diff --git a/ironic/api/controllers/root.py b/ironic/api/controllers/root.py index 9c3d72944d..9e932b35ef 100644 --- a/ironic/api/controllers/root.py +++ b/ironic/api/controllers/root.py @@ -38,6 +38,7 @@ class RootController(object): @method.expose() def index(self, *args): + V1.add_version_attributes() if args: pecan.abort(404) return root() @@ -49,6 +50,7 @@ class RootController(object): It redirects the request to the default version of the ironic API if the version number is not specified in the url. """ + V1.add_version_attributes() # support paths which are missing the first version element if primary_key and primary_key != version.ID_VERSION1: diff --git a/ironic/api/controllers/v1/__init__.py b/ironic/api/controllers/v1/__init__.py index edf6154998..5ffad1059c 100644 --- a/ironic/api/controllers/v1/__init__.py +++ b/ironic/api/controllers/v1/__init__.py @@ -141,8 +141,7 @@ class Controller(object): # NOTE: The reason why v1() it's being called for every # request is because we need to get the host url from # the request object to make the links. - self._add_version_attributes() - if api.request.method != "GET": + if api.request.method not in ('GET', 'HEAD'): pecan.abort(http_client.METHOD_NOT_ALLOWED) return v1() @@ -169,7 +168,7 @@ class Controller(object): 'max': versions.max_version_string()}, headers=headers) - def _add_version_attributes(self): + def add_version_attributes(self): v = base.Version(api.request.headers, versions.min_version_string(), versions.max_version_string()) @@ -186,7 +185,6 @@ class Controller(object): @pecan.expose() def _lookup(self, primary_key, *remainder): - self._add_version_attributes() controller = self._subcontroller_map.get(primary_key) if not controller: diff --git a/ironic/tests/unit/api/controllers/v1/test_root.py b/ironic/tests/unit/api/controllers/v1/test_root.py index e00fe0a5aa..2c5fc1c1c8 100644 --- a/ironic/tests/unit/api/controllers/v1/test_root.py +++ b/ironic/tests/unit/api/controllers/v1/test_root.py @@ -29,6 +29,28 @@ class TestV1Routing(api_base.BaseApiTest): mock.ANY, mock.ANY) + def test_microversion_headers(self): + # Check root endpoint + response = self.app.head('/') + self.assertEqual(200, response.status_int) + self.assertIn('X-OpenStack-Ironic-API-Minimum-Version', + response.headers) + self.assertIn('X-OpenStack-Ironic-API-Maximum-Version', + response.headers) + + self._check_version.reset_mock() + + # Check v1 endpoint + response = self.app.head('/v1') + self.assertEqual(200, response.status_int) + self.assertIn('X-OpenStack-Ironic-API-Minimum-Version', + response.headers) + self.assertIn('X-OpenStack-Ironic-API-Maximum-Version', + response.headers) + + # -check_version should be called only once + self.assertEqual(1, self._check_version.call_count) + def test_min_version(self): response = self.get_json( '/', diff --git a/releasenotes/notes/add-microversion-headers-to-root-endpoint-199cb910a7aa53f9.yaml b/releasenotes/notes/add-microversion-headers-to-root-endpoint-199cb910a7aa53f9.yaml new file mode 100644 index 0000000000..6e793d1166 --- /dev/null +++ b/releasenotes/notes/add-microversion-headers-to-root-endpoint-199cb910a7aa53f9.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + Adds microversion headers to the root ('/') endpoint.