pylxd icon indicating copy to clipboard operation
pylxd copied to clipboard

`pylxd` should send `Content-Type` header along with some requests

Open simondeziel opened this issue 5 months ago • 2 comments

LXD now requires the Content-Type header to be sent along with some requests, see https://github.com/canonical/lxd/pull/15880

pylxd needs to be updated to provide the header when needed to remain compatible with current LXD (like the latest/edge snap).

The integration tests are currently broken:

+ snap list lxd
Name  Version      Rev    Tracking     Publisher   Notes
lxd   git-12a10e7  34550  latest/edge  canonical✓  in-cohort
+ lxc version
Client version: 6.4
Server version: 6.4
+ tox -e integration
integration: install_deps> python -I -m pip install '.[testing]'
integration: commands[0]> pytest integration
=============================================================================================================================== test session starts ================================================================================================================================
platform linux -- Python 3.12.3, pytest-8.4.1, pluggy-1.6.0
cachedir: .tox/integration/.pytest_cache
rootdir: /root/lxd-ci/pylxd
plugins: cov-6.2.1
collected 57 items                                                                                                                                                                                                                                                                 

integration/test_client.py ..                                                                                                                                                                                                                                                [  3%]
integration/test_cluster_members.py s                                                                                                                                                                                                                                        [  5%]
integration/test_containers.py FFFFFFFFFsssFFFFFF                                                                                                                                                                                                                            [ 36%]
integration/test_images.py FFFFFF                                                                                                                                                                                                                                            [ 47%]
integration/test_networks.py .......                                                                                                                                                                                                                                         [ 59%]
integration/test_profiles.py ......                                                                                                                                                                                                                                          [ 70%]
integration/test_projects.py ......                                                                                                                                                                                                                                          [ 80%]
integration/test_storage.py .......sss.                                                                                                                                                                                                                                      [100%]

===================================================================================================================================== FAILURES =====================================================================================================================================
_____________________________________________________________________________________________________________________________ TestContainers.test_all ______________________________________________________________________________________________________________________________

self = <integration.test_containers.TestContainers testMethod=test_all>

    def test_all(self):
        """A list of all containers is returned."""
>       name = self.create_container()
               ^^^^^^^^^^^^^^^^^^^^^^^

integration/test_containers.py:34: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
integration/testing.py:41: in create_container
    fingerprint, alias = self.create_image()
                         ^^^^^^^^^^^^^^^^^^^
integration/testing.py:91: in create_image
    response = self.lxd.images.post(data=f.read(), headers=headers)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pylxd/client.py:291: in post
    self._assert_response(response, allowed_status_codes=(200, 201, 202))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <pylxd.client._APINode object at 0x741c1cadccb0>, response = <Response [415]>, allowed_status_codes = (200, 201, 202), stream = False, is_api = True

    def _assert_response(
        self, response, allowed_status_codes=(200,), stream=False, is_api=True
    ):
        """Assert properties of the response.
    
        LXD's API clearly defines specific responses. If the API
        response is something unexpected (i.e. an error), then
        we need to raise an exception and have the call points
        handle the errors or just let the issue be raised to the
        user.
        """
        if response.status_code not in allowed_status_codes:
            if response.status_code == 404:
                raise exceptions.NotFound(response)
            elif response.status_code == 409:
                raise exceptions.Conflict(response)
>           raise exceptions.LXDAPIException(response)
E           pylxd.exceptions.LXDAPIException: Unsupported Content-Type for this request

pylxd/client.py:220: LXDAPIException
____________________________________________________________________________________________________________________________ TestContainers.test_create ____________________________________________________________________________________________________________________________

simondeziel avatar Jul 02 '25 17:07 simondeziel

https://github.com/canonical/lxd/pull/15975 made the Content-Type header required only for web browsers.

simondeziel avatar Jul 21 '25 17:07 simondeziel

Pylxd should still send correct content type ideally (as the intention was to tighten up restrictions in future).

tomponline avatar Jul 21 '25 18:07 tomponline