MaaS instance can download images or start DHCP server, not both

Hello! My team runs a TLS-enabled MaaS instance that has an intriguing problem: it can download Ubuntu images, or it can start the DHCP server, but apparently not both at the same time. I’ve been able to reproduce this behavior with a fresh (and what seems to me to be a) minimal configuration with a single region+rack controllre, with the variable being the MaaS URL provided during initial configuration.

We are using a Let’s Encrypt-provided certificate to enable native TLS in our MaaS environment.

To configure the reproduction environment:

  • Install Ubuntu Server
  • Install the MaaS 3.7.2 snap
  • Install PostgreSQL using apt
  • Initialize the MaaS PostgreSQL database
  • Configure the node as a region+rack controller using the specified MaaS URL (more on that detail later)
  • Configure MaaS-native TLS using maas config-tls
  • Create the admin user
  • Through the web UI, finish configuring the region

When the MaaS URL specifies a non-TLS-enabled endpoint (i.e., http://regionandrack.mydomain.com:5240/MAAS), the controller downloads Ubuntu images with impressive speed. However, once I enable DHCP on a subnet, the DHCP server never starts:

$ sudo maas status
Service          Startup   Current   Since
agent            disabled  active    today at 18:16 UTC
apiserver        enabled   active    today at 18:15 UTC
bind9            disabled  active    today at 18:15 UTC
dhcpd            disabled  inactive  -
dhcpd6           disabled  inactive  -
http             disabled  active    today at 18:15 UTC
ntp              disabled  active    today at 18:15 UTC
proxy            disabled  inactive  today at 18:18 UTC
rackd            enabled   active    today at 18:15 UTC
regiond          enabled   active    today at 18:15 UTC
syslog           disabled  active    today at 18:16 UTC
temporal         disabled  active    today at 18:15 UTC
temporal-worker  disabled  active    today at 18:15 UTC

Also, the DHCP configuration files are zero-length:

$ ls -alh /var/snap/maas/common/maas/dhcp*
-rw-r----- 1 root root 0 Apr  9 18:19 /var/snap/maas/common/maas/dhcpd6.conf
-rw-r----- 1 root root 0 Apr  9 18:19 /var/snap/maas/common/maas/dhcpd6-interfaces
-rw-r----- 1 root root 0 Apr  9 18:19 /var/snap/maas/common/maas/dhcpd.conf
-rw-r----- 1 root root 0 Apr  9 18:19 /var/snap/maas/common/maas/dhcpd-interfaces
srw-rw-rw- 1 root root 0 Apr  9 18:16 /var/snap/maas/common/maas/dhcpd.sock

When the MaaS URL specifies a TLS-enabled endpoint (i.e., https://regionandrack.mydomain.com/MAAS), the controller has no problem populating the DHCP configuration files (with a note that this environment does not have any DHCPv6-enabled interfaces):

$ ls -alh /var/snap/maas/common/maas/dhcp*
-rw-r----- 1 root root 1.1K Apr  9 20:47 /var/snap/maas/common/maas/dhcpd6.conf
-rw-r----- 1 root root    0 Apr  9 20:47 /var/snap/maas/common/maas/dhcpd6-interfaces
-rw-r----- 1 root root 5.2K Apr  9 20:47 /var/snap/maas/common/maas/dhcpd.conf
-rw-r----- 1 root root    6 Apr  9 20:47 /var/snap/maas/common/maas/dhcpd-interfaces
srw-rw-rw- 1 root root    0 Apr  9 20:47 /var/snap/maas/common/maas/dhcpd.sock

And the DHCP server starts with ease:

$ sudo maas status
Service          Startup   Current   Since
agent            disabled  active    today at 20:49 UTC
apiserver        enabled   active    today at 20:49 UTC
bind9            disabled  active    today at 20:49 UTC
dhcpd            disabled  active    today at 20:49 UTC
dhcpd6           disabled  inactive  -
http             disabled  active    today at 20:49 UTC
ntp              disabled  active    today at 20:49 UTC
proxy            disabled  active    today at 20:50 UTC
rackd            enabled   active    today at 20:49 UTC
regiond          enabled   active    today at 20:49 UTC
syslog           disabled  active    today at 20:49 UTC
temporal         disabled  active    today at 20:49 UTC
temporal-worker  disabled  active    today at 20:49 UTC

However, the controller indicates that Ubuntu images selected during the UI-based region configuration process are queued for download - but they never download:

Also, the maas-temporal-worker persistently complains about an SSL failure, tweaked to hopefully render into a format that’s more easily read by us humans:

$ journalctl -u snap.maas.pebble.service -t maas-temporal-worker --grep "Completing activity as fai
led" | tail -n 1 | sed 's/^[^{]*//g' | jq . | sed 's/^"//;s/"$//;s/\\n/\n/g;s/\\"/"/g'
{                                                                     
  "message": "Completing activity as failed ({'activity_id': '1', 'activity_type': 'get-bootresourcefile-endpoints', 'attempt': 7, 'namespac
e': 'default', 'task_queue': 'region', 'workflow_id': 'sync-boot-resources:streams', 'workflow_run_id': '9c427897-2568-4e6e-8da6-74f43b97ec0
2', 'workflow_type': 'sync-bootresources'})",                       
  "exc_info": "Traceback (most recent call last):
  File "/snap/maas/x1/usr/lib/python3/dist-packages/anyio/streams/tls.py", line 140, in _call_sslobject_method                              
    result = func(*args)                                                                                                                    
             ^^^^^^^^^^^                                              
  File "/usr/lib/python3.12/ssl.py", line 917, in do_handshake        
    self._sslobj.do_handshake()                                                                                                             
ssl.SSLWantReadError: The operation did not complete (read) (_ssl.c:1000)
                                                                      
During handling of the above exception, another exception occurred:                                                                         
                                                                      
Traceback (most recent call last):                                                                                                          
  File "/snap/maas/x1/usr/lib/python3/dist-packages/anyio/_core/_tasks.py", line 115, in fail_after                                         
    yield cancel_scope                                                
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_backends/anyio.py", line 69, in start_tls                   
    ssl_stream = await anyio.streams.tls.TLSStream.wrap(                                                                                    
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                    
  File "/snap/maas/x1/usr/lib/python3/dist-packages/anyio/streams/tls.py", line 132, in wrap
    await wrapper._call_sslobject_method(ssl_object.do_handshake)                                                                           
  File "/snap/maas/x1/usr/lib/python3/dist-packages/anyio/streams/tls.py", line 147, in _call_sslobject_method      
    data = await self.transport_stream.receive()                                                                                            
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                            
  File "/snap/maas/x1/usr/lib/python3/dist-packages/anyio/_backends/_asyncio.py", line 1245, in receive
    await self._wait_until_readable(loop)
asyncio.exceptions.CancelledError: Cancelled by cancel scope 726c8c2d2db0

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_exceptions.py", line 10, in map_exceptions
    yield
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_backends/anyio.py", line 78, in start_tls
    raise exc
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_backends/anyio.py", line 68, in start_tls
    with anyio.fail_after(timeout): 
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/x1/usr/lib/python3/dist-packages/anyio/_core/_tasks.py", line 118, in fail_after
    raise TimeoutError
TimeoutError

The above exception was the direct cause of the following exception:

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_transports/default.py", line 67, in map_httpcore_exceptions
    yield
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_transports/default.py", line 371, in handle_async_request
    resp = await self._pool.handle_async_request(req)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_async/connection_pool.py", line 268, in handle_async_request
    raise exc
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_async/connection_pool.py", line 251, in handle_async_request
    response = await connection.handle_async_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_async/connection.py", line 99, in handle_async_request
    raise exc
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_async/connection.py", line 76, in handle_async_request
    stream = await self._connect(request)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_async/connection.py", line 156, in _connect
    stream = await stream.start_tls(**kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_backends/anyio.py", line 66, in start_tls
    with map_exceptions(exc_map):
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpcore/_exceptions.py", line 14, in map_exceptions
    raise to_exc(exc) from exc
httpcore.ConnectTimeout

The above exception was the direct cause of the following exception:

Traceback (most recent call last):                                                                                        20:54:23 [18/1884]
  File "/snap/maas/x1/usr/lib/python3/dist-packages/temporalio/worker/_activity.py", line 453, in _run_activity
    result = await impl.execute_activity(input)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/temporalio/worker/_activity.py", line 711, in execute_activity
    return await input.fn(*input.args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/lib/python3.12/site-packages/maastemporalworker/workflow/utils.py", line 32, in wrapper
    res = await func(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/lib/python3.12/site-packages/maastemporalworker/workflow/bootresource.py", line 189, in get_bootresourcefile_endpoints
    regions = await self.apiclient.request_async("GET", url)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/lib/python3.12/site-packages/maastemporalworker/workflow/api_client.py", line 62, in request_async
    response = await self.unix_client.request(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_client.py", line 1559, in request
    return await self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_client.py", line 1646, in send
    response = await self._send_handling_auth(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_client.py", line 1674, in _send_handling_auth
    response = await self._send_handling_redirects(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_client.py", line 1711, in _send_handling_redirects
    response = await self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_client.py", line 1748, in _send_single_request
    response = await transport.handle_async_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_transports/default.py", line 370, in handle_async_request
    with map_httpcore_exceptions(): 
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/x1/usr/lib/python3/dist-packages/httpx/_transports/default.py", line 84, in map_httpcore_exceptions
    raise mapped_exc(message) from exc
httpx.ConnectTimeout",
  "taskName": "Task-87",
  "temporal_activity": {
    "activity_id": "1",
    "activity_type": "get-bootresourcefile-endpoints",
    "attempt": 7,
    "namespace": "default",
    "task_queue": "region",
    "workflow_id": "sync-boot-resources:streams",
    "workflow_run_id": "9c427897-2568-4e6e-8da6-74f43b97ec02",
    "workflow_type": "sync-bootresources
  },
  "logger": "temporalio.activity:493",
  "level": "WARNING",
  "thread": "MainThread:125810733500224",
  "timestamp": "2026-04-09T20:53:24.140445Z
}

So it would seem that if we configure TLS, we truly can have either image downloads or a configured and running dhcpd but not both…

I’m very open to the possibility that I’m missing something rather obvious. I’m happy to share any additional non-sensitive configuration details or logs if they would be of any help.

Thank you in advance for your assistance!

The MAAS url in the regiond.conf must be http

Excellent - thank you very much, @r00ta! Your answer resolves one of the issues… Do you have any suggestions on how best to determine why the DHCP configuration files are empty and the dhcpd server does not start when I specify a non-TLS endpoint? I see nothing in the logs that indicates an error processing DHCP configuration, so I’m rather at a loss.

Thank you again for your help!

any exception in in maas-temporal-worker and maas-agent?

No exceptions in maas-agent or mass-temporal-worker, but I did see this exception which I hadn’t previously noticed:

{
  "message": "401, message='Unauthorized', url=URL('https://jfs-maas-sandbox.eng.exagrid.com:443/MAAS/api/2.0/agents/aqk3s3/services/dhcp/config/')",
  "exc_info": "Traceback (most recent call last):
  File "/snap/maas/41649/usr/lib/python3/dist-packages/anyio/streams/memory.py", line 97, in receive
    return self.receive_nowait()
           ^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/anyio/streams/memory.py", line 92, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 159, in call_next
    message = await recv_stream.receive()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/anyio/streams/memory.py", line 112, in receive
    raise EndOfStream
anyio.EndOfStream

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/exceptions.py", line 61, in dispatch
    return await call_next(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/db.py", line 61, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/v3/middlewares/services.py", line 44, in dispatch
    return await call_next(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/db.py", line 113, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/prometheus.py", line 50, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/provisioningserver/prometheus/utils.py", line 134, in record_latency
    result = await coro
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 746, in __call__
    await route.handle(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 75, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 70, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/routing.py", line 273, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/routing.py", line 190, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/v3/api/internal/handlers/agent.py", line 29, in get_agent_service_config
    tokens = await services.agents.get_service_configuration(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasservicelayer/services/agents.py", line 59, in get_service_configuration
    return await apiclient.request(method="GET", path=path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasservicelayer/apiclient/client.py", line 48, in request
    response.raise_for_status()
  File "/snap/maas/41649/usr/lib/python3/dist-packages/aiohttp/client_reqrep.py", line 1059, in raise_for_status
    raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 401, message='Unauthorized', url=URL('https://jfs-maas-sandbox.eng.exagrid.com:443/MAAS/api/2.0/agents/aqk3s3/services/dhcp/config/')",
  "taskName": "starlette.middleware.base.BaseHTTPMiddleware.__call__.<locals>.call_next.<locals>.coro",
  "context_id": "4dd89772-4b34-4bc0-9a38-5043535a436c",
  "timestamp": "2026-04-10T14:31:42.140409Z",
  "exception": "Traceback (most recent call last):
  File "/snap/maas/41649/usr/lib/python3/dist-packages/anyio/streams/memory.py", line 97, in receive
    return self.receive_nowait()
           ^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/anyio/streams/memory.py", line 92, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 159, in call_next
    message = await recv_stream.receive()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/anyio/streams/memory.py", line 112, in receive
    raise EndOfStream
anyio.EndOfStream

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/exceptions.py", line 61, in dispatch
    return await call_next(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/db.py", line 61, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/v3/middlewares/services.py", line 44, in dispatch
    return await call_next(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/db.py", line 113, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 189, in __call__
    with collapse_excgroups():
  File "/usr/lib/python3.12/contextlib.py", line 158, in __exit__
    self.gen.throw(value)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_utils.py", line 88, in collapse_excgroups
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 191, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/common/middlewares/prometheus.py", line 50, in dispatch
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/provisioningserver/prometheus/utils.py", line 134, in record_latency
    result = await coro
             ^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 165, in call_next
    raise app_exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/base.py", line 151, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 746, in __call__
    await route.handle(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 75, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/snap/maas/41649/usr/lib/python3/dist-packages/starlette/routing.py", line 70, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/routing.py", line 273, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/usr/lib/python3/dist-packages/fastapi/routing.py", line 190, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasapiserver/v3/api/internal/handlers/agent.py", line 29, in get_agent_service_config
    tokens = await services.agents.get_service_configuration(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasservicelayer/services/agents.py", line 59, in get_service_configuration
    return await apiclient.request(method="GET", path=path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/snap/maas/41649/lib/python3.12/site-packages/maasservicelayer/apiclient/client.py", line 48, in request
    response.raise_for_status()
  File "/snap/maas/41649/usr/lib/python3/dist-packages/aiohttp/client_reqrep.py", line 1059, in raise_for_status
    raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 401, message='Unauthorized', url=URL('https://jfs-maas-sandbox.eng.exagrid.com:443/MAAS/api/2.0/agents/aqk3s3/services/dhcp/config/')",
  "logger": "maasapiserver.common.middlewares.exceptions:93",
  "level": "ERROR",
  "thread": "MainThread:133289808852800"
}

I’ll confess I’m having trouble understanding this one. Do I need to configure some kind of token for DHCP configuration to succeed once TLS is configured? I didn’t see anything in the documentation describing any such step, but I may have overlooked something.

One more potentially interesting data point: I reset my sandbox environment and configured it without any TLS, and I found that DHCP configuration occurs without an error. I then reset the sandbox environment again and configured it without MaaS native TLS but with Apache providing TLS termination on port 443 and acting as a proxy to MaaS on port 5240. With this configuration and with the MaaS URL pointing to unencrypted port 5240 as per your direction, both image download and DHCP configuration function without error.

This data point and the previously noted exception seem to suggest that DHCP configuration attempts - and fails - to use the native TLS endpoint when native TLS is configured, but is able to use unencrypted port 5240 without an issue. If this theory is correct, should DHCP configuration be made to correctly function with the native TLS endpoint, or should it instead use the unencrypted MaaS URL?

Thank you again for your help and your time!