Bug 55057 - wrong status code 201 (CREATED) instead of 202 (ACCEPTED) for UDM REST API move operation
wrong status code 201 (CREATED) instead of 202 (ACCEPTED) for UDM REST API mo...
Status: VERIFIED FIXED
Product: UCS
Classification: Unclassified
Component: UDM - REST API
UCS 5.0
Other Linux
: P5 normal (vote)
: UCS 5.2
Assigned To: Florian Best
Juan Carlos
https://help.univention.com/t/using-r...
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2022-08-01 17:00 CEST by Florian Best
Modified: 2024-03-08 10:35 CET (History)
6 users (show)

See Also:
What kind of report is it?: ---
What type of bug is this?: ---
Who will be affected by this bug?: ---
How will those affected feel about the bug?: ---
User Pain:
Enterprise Customer affected?:
School Customer affected?:
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number:
Bug group (optional): API change, External feedback
Max CVSS v3 score:
best: Patch_Available+


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Florian Best univentionstaff 2022-08-01 17:00:44 CEST
The UDM REST API returns  status code 201 (CREATED) instead of 202 (ACCEPTED) for a move operation.

Patch:

diff --git management/univention-directory-manager-rest/src/univention/admin/rest/module.py management/univention-directory-manager-rest/src/univention/admin/rest/module.py
index 302aff81b4..f11a716735 100755
--- management/univention-directory-manager-rest/src/univention/admin/rest/module.py
+++ management/univention-directory-manager-rest/src/univention/admin/rest/module.py
@@ -3004,7 +3004,7 @@ class Object(FormBase, Resource):
                        shared_memory.queue[self.request.user_dn] = shared_memory.dict()
                shared_memory.queue[self.request.user_dn][status_id] = status
 
-               self.set_status(201)
+               self.set_status(202)
                self.set_header('Location', self.abspath('progress', status['id']))
                self.add_caching(public=False, must_revalidate=True)
                self.content_negotiation(dict(status))

diff --git management/univention-directory-manager-rest/src/univention/admin/rest/client/__init__.py management/univention-directory-manager-rest/src/univention/admin/rest/client/__init__.py
index e027249981..1e27950f42 100755
--- management/univention-directory-manager-rest/src/univention/admin/rest/client/__init__.py
+++ management/univention-directory-manager-rest/src/univention/admin/rest/client/__init__.py
@@ -668,8 +668,8 @@ class Object(Client):
        def _follow_redirection(self, response, reload=True):
                # type: (Response, bool) -> Response
                location = None
-               # python-requests doesn't follow redirects for 201
-               if response.response.status_code == 201 and 'Location' in response.response.headers:
+               # python-requests doesn't follow redirects for 20X
+               if response.response.status_code in (201, 202) and 'Location' in response.response.headers:
                        location = response.response.headers['Location']
                        response = self.client.make_request('GET', location, allow_redirects=False)
Comment 1 Daniel Tröder univentionstaff 2022-08-02 08:24:09 CEST
What fixed, please verify that the UDM REST API client (https://github.com/univention/python-udm-rest-api-client/) still works.
If not, please create a new bug for it, and depend on it (wait with the release) - this is an API change.
Comment 2 Florian Best univentionstaff 2022-10-19 14:51:23 CEST
(In reply to Daniel Tröder from comment #1)
> What fixed, please verify that the UDM REST API client
> (https://github.com/univention/python-udm-rest-api-client/) still works.
> If not, please create a new bug for it, and depend on it (wait with the
> release) - this is an API change.

The client is compatible since python-udm-rest-api-client 1.0.11 (2022-10-19):
https://github.com/univention/python-udm-rest-api-client/pull/107
Comment 3 Jürn Brodersen univentionstaff 2022-11-28 16:40:38 CET
I think we need this for the kelvin api. It looks like the udm-rest-client is trying to make a progress call due to the 201 status. But that progress call than fails.

Log for the progress call /var/log/apache2/access.log:
```
172.17.0.1 - - [28/Nov/2022:14:10:54 +0100] "PUT /univention/udm//users/user/uid=t1,cn=lehrer,cn=users,ou=DEMOSCHOOL,dc=school,dc=test HTTP/1.1" 201 1100 "-" "udm-rest-client/1.0.13"
172.17.0.1 - - [28/Nov/2022:14:10:54 +0100] "GET /univention/udm/progress/6e195e06-60b1-45a1-81a5-a5198aa2f257 HTTP/1.1" 404 1707 "-" "Python/3.8 aiohttp/3.8.3"
172.17.0.2 - - [28/Nov/2022:14:10:53 +0100] "PUT /ucsschool/kelvin/v1/users/t1 HTTP/1.1" 500 332 "-" "python-httpx/0.23.1"
```

Kelvin log:
```
Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/usr/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/fastapi/applications.py", line 270, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/lib/python3.8/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/base.py", line 106, in __call__
    response = await self.dispatch_func(request, call_next)
  File "/usr/lib/python3.8/site-packages/fastapi_utils/timing.py", line 47, in timing_middleware
    response = await call_next(request)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/base.py", line 80, in call_next
    raise app_exc
  File "/usr/lib/python3.8/site-packages/starlette/middleware/base.py", line 69, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/usr/lib/python3.8/site-packages/asgi_correlation_id/middleware.py", line 81, in __call__
    await self.app(scope, receive, handle_outgoing_request)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/lib/python3.8/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/usr/lib/python3.8/site-packages/fastapi/routing.py", line 235, in app
    raw_response = await run_endpoint_function(
  File "/usr/lib/python3.8/site-packages/fastapi/routing.py", line 161, in run_endpoint_function
    return await dependant.call(**values)
  File "/kelvin/kelvin-api/ucsschool/kelvin/routers/user.py", line 1286, in complete_update
    user_current = await change_school(udm, logger, user_current, new_school, new_schools.copy())
  File "/kelvin/kelvin-api/ucsschool/kelvin/routers/user.py", line 879, in change_school
    await user.change_school(new_school, udm)
  File "/kelvin/ucs-school-import/modules/ucsschool/importer/models/import_user.py", line 326, in change_school
    res = await super(ImportUser, self).change_school(school, lo)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 809, in change_school
    return await self.move(lo, force=True)
  File "/kelvin/ucs-school-import/modules/ucsschool/importer/models/import_user.py", line 1178, in move
    return await super(ImportUser, self).move(lo, udm_obj, force)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 761, in move
    success = await self.move_without_hooks(lo, udm_obj, force)
  File "/kelvin/ucs-school-import/modules/ucsschool/importer/models/import_user.py", line 1185, in move_without_hooks
    return await super(ImportUser, self).move_without_hooks(lo, udm_obj, force)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 781, in move_without_hooks
    await self.do_move(udm_obj, lo)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 794, in do_move
    await udm_obj.save()
  File "/usr/lib/python3.8/site-packages/udm_rest_client/base_http.py", line 704, in save
    api_obj = await self._move(self.position, language=language)
  File "/usr/lib/python3.8/site-packages/udm_rest_client/base_http.py", line 891, in _move
    udm_api_response = await self._follow_move_redirects(
  File "/usr/lib/python3.8/site-packages/udm_rest_client/base_http.py", line 948, in _follow_move_redirects
    raise ApiException(
openapi_client_udm.exceptions.ApiException: (UDM REST API returned status 404, headers: <CIMultiDictProxy('Date': 'Mon, 28 Nov 2022 13:10:54 GMT', 'Server': 'Univention/1.0', 'X-Permitted-Cross-Domain-Policies': 'master-only', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "frame-ancestors 'none';", 'Content-Language': 'en-US', 'Content-Type': 'text/html; charset=UTF-8', 'Access-Control-Expose-Headers': '*, Authorization, X-Request-Id', 'X-Request-Id': '007f3ff4-0e15-4fff-8a57-af67f387249e', 'Link': '<https://backup1.school.test/univention/udm/progress/6e195e06-60b1-45a1-81a5-a5198aa2f257>; rel="self"; title="HTTP-Error 404: "', 'Link': '<https://backup1.school.test/univention/udm/css/style.css>; rel="stylesheet"', 'Cache-Control': 'private, must-revalidate, no-cache, no-store', 'Vary': 'Accept,Accept-Language,Accept-Encoding,Authorization', 'Content-Length': '862', 'Via': '1.1 backup1.school.test')> for move of UdmObject('users/user', 'uid=t1,cn=lehrer,cn=users,ou=DEMOSCHOOL,dc=school,dc=test') to position 'cn=lehrer,cn=users,ou=school1,dc=school,dc=test'.)
```
Comment 6 Jürn Brodersen univentionstaff 2022-11-29 15:32:32 CET
(In reply to Florian Best from comment #5)
> MR: https://git.knut.univention.de/univention/ucs/-/merge_requests/579

I tried the changes in the MR and now get a different error, sorry. Do you think  this a new bug or part of this one?

Python UDM REST Client: 1.0.13
I also tried "update_openapi_client", but no change.


```
Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/usr/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/fastapi/applications.py", line 270, in __call__
    await super().__call__(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/usr/lib/python3.8/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/base.py", line 106, in __call__
    response = await self.dispatch_func(request, call_next)
  File "/usr/lib/python3.8/site-packages/fastapi_utils/timing.py", line 47, in timing_middleware
    response = await call_next(request)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/base.py", line 80, in call_next
    raise app_exc
  File "/usr/lib/python3.8/site-packages/starlette/middleware/base.py", line 69, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/usr/lib/python3.8/site-packages/asgi_correlation_id/middleware.py", line 81, in __call__
    await self.app(scope, receive, handle_outgoing_request)
  File "/usr/lib/python3.8/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/lib/python3.8/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/usr/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/lib/python3.8/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/usr/lib/python3.8/site-packages/fastapi/routing.py", line 235, in app
    raw_response = await run_endpoint_function(
  File "/usr/lib/python3.8/site-packages/fastapi/routing.py", line 161, in run_endpoint_function
    return await dependant.call(**values)
  File "/kelvin/kelvin-api/ucsschool/kelvin/routers/user.py", line 1286, in complete_update
    user_current = await change_school(udm, logger, user_current, new_school, new_schools.copy())
  File "/kelvin/kelvin-api/ucsschool/kelvin/routers/user.py", line 879, in change_school
    await user.change_school(new_school, udm)
  File "/kelvin/ucs-school-import/modules/ucsschool/importer/models/import_user.py", line 326, in change_school
    res = await super(ImportUser, self).change_school(school, lo)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 809, in change_school
    return await self.move(lo, force=True)
  File "/kelvin/ucs-school-import/modules/ucsschool/importer/models/import_user.py", line 1178, in move
    return await super(ImportUser, self).move(lo, udm_obj, force)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 761, in move
    success = await self.move_without_hooks(lo, udm_obj, force)
  File "/kelvin/ucs-school-import/modules/ucsschool/importer/models/import_user.py", line 1185, in move_without_hooks
    return await super(ImportUser, self).move_without_hooks(lo, udm_obj, force)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 781, in move_without_hooks
    await self.do_move(udm_obj, lo)
  File "/kelvin/ucs-school-lib/modules/ucsschool/lib/models/base.py", line 794, in do_move
    await udm_obj.save()
  File "/usr/lib/python3.8/site-packages/udm_rest_client/base_http.py", line 704, in save
    api_obj = await self._move(self.position, language=language)
  File "/usr/lib/python3.8/site-packages/udm_rest_client/base_http.py", line 871, in _move
    new_api_obj, status, header = await self._udm_module.session.call_openapi(
  File "/usr/lib/python3.8/site-packages/udm_rest_client/base_http.py", line 457, in call_openapi
    _dn = None if status == 204 else api_model_obj.dn
AttributeError: 'dict' object has no attribute 'dn'
```
Comment 7 Florian Best univentionstaff 2022-11-30 18:32:53 CET
(In reply to Jürn Brodersen from comment #6)
> I tried the changes in the MR and now get a different error, sorry. Do you
> think  this a new bug or part of this one?
I think it's a different bug related to problems in the shared memory.
 
> ```
> Traceback (most recent call last):>     _dn = None if status == 204 else api_model_obj.dn
> AttributeError: 'dict' object has no attribute 'dn'
> ```
This has been fixed in:
https://git.knut.univention.de/univention/components/python-udm-rest-api-client/-/merge_requests/11
Comment 8 Florian Best univentionstaff 2023-01-18 14:22:10 CET
(In reply to Florian Best from comment #7)
> (In reply to Jürn Brodersen from comment #6)
> > I tried the changes in the MR and now get a different error, sorry. Do you
> > think  this a new bug or part of this one?
> I think it's a different bug related to problems in the shared memory.
The problem was that the service was accessed with a different `Accept-Language` header when following the move-redirects.
The move-progress is not shared across language-bound-processes.
Comment 9 Juan Carlos univentionstaff 2024-01-15 11:20:13 CET
QA:

Code: OK
Changelog: OK
Tests: OK
Correct status code: OK
Comment 10 Florian Best univentionstaff 2024-03-08 10:35:42 CET
univention-directory-manager-rest (11.0.5)
154e1cc083af | fix(udm-rest)!: change status code to 202 for move operations