nanovms/ops

unimplemented socket options for Python amqp

BunningsWarehouseOfficial opened this issue ยท 5 comments

After creating a pip venv and running pip install amqp, I run the following command: ops pkg load eyberg/python:3.10.6 -c amqpConfig.json

amqpConfig.json:

{
    "MapDirs": {
        ".venv/*": "/.local"
    },
    "Args": [
        "amqp_test.py"
    ]
}

amqp_test.py:

import amqp
connection = amqp.Connection(host='192.168.90.88', userid='username', password='password')
connection.connect()
channel = connection.channel()
channel.queue_declare(queue='test')
channel.basic_publish(amqp.basic_message.Message('Hello World!'), exchange='', routing_key='test')
print(" [x] Sent 'Hello World!'")
connection.close()

I get the following error:

kris@Kris-Ubuntu:~/Documents/ops/python3.10.6$ ops pkg load eyberg/python:3.10.6 -c amqpConfig.json
running local instance
booting /home/kris/.ops/images/python3.10 ...
en1: assigned 10.0.2.15
netsock_getsockopt error: getsockopt unimplemented optname: fd 3, level 6, optname 7
Traceback (most recent call last):
  File "//amqp_test.py", line 108, in <module>
    connection.connect()
  File "/.local/lib/python3.10/site-packages/amqp/connection.py", line 324, in connect
    self.transport.connect()
  File "/.local/lib/python3.10/site-packages/amqp/transport.py", line 130, in connect
    self._init_socket(
  File "/.local/lib/python3.10/site-packages/amqp/transport.py", line 197, in _init_socket
    self._set_socket_options(socket_settings)
  File "/.local/lib/python3.10/site-packages/amqp/transport.py", line 241, in _set_socket_options
    tcp_opts = self._get_tcp_socket_defaults(self.sock)
  File "/.local/lib/python3.10/site-packages/amqp/transport.py", line 234, in _get_tcp_socket_defaults
    tcp_opts[enum] = sock.getsockopt(SOL_TCP, getattr(socket, opt))
OSError: [Errno 42] No message of desired type

The amqp package tries to get the following SOL_TCP socket options:

  • socket.TCP_MAXSEG = 2
  • socket.TCP_CORK = 3
  • socket.TCP_SYNCNT = 7
  • socket.TCP_LINGER2 = 8
  • socket.TCP_DEFER_ACCEPT = 9
  • socket.TCP_WINDOW_CLAMP = 10
  • socket.TCP_QUICKACK = 12

After doing some digging (with the help of #1121) through system_structs.h and netsyscall.c, and playing around with the errors I receive, it appears to me that the following socket {level, optname} pairs aren't implemented by Nanos (at least as far as getsockopt is concerned I guess)?

  • SOL_SOCKET, TCP_WINDOW_CLAMP
  • SOL_TCP, TCP_CORK
  • SOL_TCP, TCP_SYNCNT
  • SOL_TCP, TCP_LINGER2
  • SOL_TCP, TCP_DEFER_ACCEPT
  • SOL_TCP, TCP_WINDOW_CLAMP
  • SOL_TCP, TCP_QUICKACK
    The only SOL_TCP option which amqp tried to access that didn't fail was TCP_MAXSEG, which is in netsyscall.c

Also, this may not be relevant, but if I change this line in amqp to be tcp_opts[enum] = sock.getsockopt(1, getattr(socket, opt)), where 1 represents the value for SOL_SOCKET instead of SOL_TCP, and comment out 'TCP_WINDOW_CLAMP', on this line, then the above test code (and my full application which I was debugging) works perfectly, which I found to be strange given that it's such a hack.

kris@Kris-Ubuntu:~/Documents/ops/python3.10.6$ ops profile
Ops version: 0.1.39
Nanos version: 0.1.48
Qemu version: 6.2.0
OS: linux
Arch: amd64
Virtualized: true

Forgive my ignorance, as I'm new to OPS/Nanos and know very little about sockets, but is this known/expected/intentional/expected?

eyberg commented

yeh, we haven't added all the various socket options - we tend to add things like this as people request them - we can certainly take a look at adding a handful of these though

Could we go about requesting implementation of the socket opt names above?
Would be handy to be able to use Nanos for a service running AMQP.

eyberg commented

I don't know when we'll get to it but we can take a look

@BunningsWarehouseOfficial I added to the Nanos kernel support for the above socket options in nanovms/nanos#1973. I tested the AMQP Python client with these changes, and it works fine, as both a producer and a consumer.
If you want, you can try it out by adding the --nanos-version 3348993 option to your Ops command line, e.g. ops pkg load eyberg/python:3.10.6 -c amqpConfig.json --nanos-version 3348993.

Sweet, thank you! We've tested it with our setup and it works like a charm.