def describe(request): """Render a description of the whole MAAS API. :param request: A "related" HTTP request. This is used to derive the URL where the client expects to see the MAAS API. :return: An `HttpResponse` containing a JSON description of the whole MAAS API. Links to the API will use the same scheme and hostname that the client used in `request`. """ description = describe_api() # Add hash so that client can check if things are up to date. description["hash"] = get_api_description_hash() # Make all URIs absolute. Clients - and the command-line client in # particular - expect that all handler URIs are absolute, not just paths. # The handler URIs returned by describe_resource() are relative paths. absolute = partial(build_absolute_uri, request) for resource in description["resources"]: for handler_type in "anon", "auth": handler = resource[handler_type] if handler is not None: handler["uri"] = absolute(handler["path"]) # Return as a JSON document. return HttpResponse( json.dumps(description), content_type="application/json")
def test__caches_hash(self): # Fake the API description. api_description = factory.make_string() api_description_hasher = hash_canonical(api_description) # The description can only be fetched once before crashing. self.patch(doc_module, "describe_api").side_effect = [ api_description, factory.make_exception_type(), ] # The hash is generated and cached. self.assertThat(get_api_description_hash(), Equals(api_description_hasher.hexdigest())) self.assertThat(get_api_description_hash(), Equals(api_description_hasher.hexdigest())) # Calling `describe_api` a second time would have failed. self.assertRaises(Exception, doc_module.describe_api)
def test__calculates_hash_from_api_description(self): # Fake the API description. api_description = factory.make_string() api_description_hasher = hash_canonical(api_description) self.patch(doc_module, "describe_api").return_value = api_description # The hash is generated from the faked API description. self.assertThat(get_api_description_hash(), Equals(api_description_hasher.hexdigest()))
def test_api_hash_is_set_in_headers(self): Config.objects.set_config("maas_name", factory.make_name("name")) self.become_admin() response = self.client.get( reverse("maas_handler"), {"op": "get_config", "name": "maas_name"} ) self.assertThat( response["X-MAAS-API-Hash"], Equals(get_api_description_hash()) )
def __call__(self, request, *args, **kwargs): upcall = super(OperationsResource, self).__call__ response = upcall(request, *args, **kwargs) response["X-MAAS-API-Hash"] = get_api_description_hash() return response
def test_describe_hash_is_the_api_hash(self): response = self.client.get(reverse("describe")) description = json_load_bytes(response.content) self.assertThat(description["hash"], Equals(get_api_description_hash()))
def __call__(self, request, *args, **kwargs): response = super().__call__(request, *args, **kwargs) response["X-MAAS-API-Hash"] = get_api_description_hash() return response