Python library that can be used for snapctl functionality within a snap?

I have a piece of python code that runs within a snap, and I would like to be able to set some snap configure options based on some data it processes. I’d rather not a python lib if possible.

I was originally looking at the python example here: How to communicate with /run/snapd.socket using Python?

…but I don’t want to have to use the snapd-control interface. I just want to be able to operate in the context of the snap, in the same way the snapctl does.

Any way using native python ? Or is calling snapctl my only option ?

Thanks !

Cheers,
Just

The snapctl command connects to a different socket /run/snapd-snap.socket.

Note that the only endpoint that can be accessed using this alternative socket is /v2/snapctl. The interface is basically to post a list of arguments, and receives stdout, stderr, and exit code in response. So you’re not getting anything more structured than calling the snapctl executable.

1 Like

Thanks @jamesh

This might be a dumb question, but is it possible to use the pygobject lib to communicate via that socket ?

Cheers,
Just

You can call the set_socket_path(socket_path) method on the client object to point it at the other socket.

The methods corresponding to /v2/snapctl are run_snapctl_{sync,async,finish}. For the context ID argument, you should pass the value of the SNAP_COOKIE environment variable. Any other method calls will likely return errors.

Thanks again @jamesh for the pointer :slight_smile:

That does seem to be the correct way of doing it, but sadly with the snap I have created to test this I get a segfault:

python3[12425]: segfault at a6f6f60 ip 00007f3b1f60b6a7 sp 00007fff4c943328 error 4 in libc-2.31.so[7f3b1f4a5000+178000]

Not sure exactly where the issue is there, but unless you have any further suggestions, I may just have to look at implementing something myself using requests_unixsocket or some such.

I did a quick PoC just using python socket, and that seemed to work fine:

#!/usr/bin/env python3


import os, json, socket

s = socket.socket(socket.AF_UNIX)
s.settimeout(1)
s.connect('/run/snapd-snap.socket')

snap_cookie = os.environ.get('SNAP_COOKIE')


headers = """\
POST /v2/snapctl HTTP/1.1\r
Host: localhost\r
Content-Type: {content_type}\r
Content-Length: {content_length}\r
Connection: close\r
\r\n"""


_body = {
    "context-id": snap_cookie,
    "args": [ "get", "username" ]
}

body = json.dumps(_body)


body_bytes = body.encode('ascii')
header_bytes = headers.format(
    content_type="application/json",
    content_length=len(body_bytes)
).encode('iso-8859-1')

payload = header_bytes + body_bytes


recv_bytes = s.send(payload)

response = s.recv(recv_bytes)
print(response)
# ./socket-test 
b'HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nDate: Thu, 08 Oct 2020 12:07:17 GMT\r\nContent-Length: 87\r\nConnection: close\r\n\r\n{"type":"sync","status-code":200,"status":"OK","result":{"stderr":"","stdout":"moo\\n'