Adding varlink to DNF
This page shows, how to easily add a varlink interface to existing software.
Prerequisites
Checkout the dnf git repo with branch varlink
:
$ git clone -b varlink https://github.com/haraldh/dnf.git
$ cd dnf
$ cmake . -DPYTHON_DESIRED:str=3 -DWITH_MAN=0 -DPYTHON_EXECUTABLE=/usr/bin/python3
$ make
For Fedora we also need
$ sudo dnf install --enablerepo rawhide python3-varlink libvarlink-util
Interface definition
First, the interface definition has to be specified. With compatibility in mind, we define a general purpose package manager interface: com.redhat.packages.varlink.
Implementation
The implementation is done in main.py
First a varlink.Service
object is created:
service = varlink.Service(
vendor='Red Hat',
product='Packages',
version='1',
interface_dir=os.path.dirname(__file__),
namespaced=True
)
The namespaced=True
indicates, that the methods are called with arguments of type SimpleNamespace
and not dict
, so that we can access the subelements with parm.foo
instead of parm["foo"]
.
The DnfVarlinkService
class is tagged with the @service.interface('com.redhat.packages')
annotator, to indicate, that it is the interface provider for the varlink service com.redhat.packages
. The varlink.Service
will load the interface definition file com.redhat.packages.varlink
from the directory specified with interface_dir
.
For our showcase, we implement only the List
method. First we create the search_pattern
according to the packages
parameter. After querying the packages with base._do_package_lists()
, the returned lists have to be processed to fit the Package
type specified in the varlink com.redhat.packages
interface.
The varlink.ThreadingServer
class, which is a subclass of socketserver.BaseServer is used to serve from the URL, which is passed in argv[1]
(for dnf args[0]
). varlink.ThreadingServer
, varlink.ForkingServer
and varlink.Server
parse the varlink URI address, check for socket activation (LISTEN_FD) and bind a socket for us.
main()
is called from the dnf-varlink cli utility following dnf-automatic
and dnf-cli
in the bin directory.
Running
Now we can talk to dnf with varlink. We use the “exec:” mechanism, which will start the dnf-varlink-3
client executable directly in the user context with all the user’s permissions.
$ varlink call exec:./bin/dnf-varlink-3/com.redhat.packages.List '{"packages": [{"name":"libvarlink", "version": {"architecture": "x86_64" }}, {"name": "python3-varlink"}]}'
Last metadata expiration check: 0:04:35 ago on Mi 21 Feb 2018 10:02:42 CET.
{
"packages": [
{
"available": false,
"installed": true,
"name": "libvarlink",
"version": {
"architecture": "x86_64",
"release": "2.fc28",
"version": "1"
}
},
{
"available": true,
"installed": true,
"name": "python3-varlink",
"version": {
"architecture": "noarch",
"release": "1.git.137.51a669b.fc28",
"version": "12"
}
},
{
"available": true,
"installed": false,
"name": "libvarlink",
"version": {
"architecture": "x86_64",
"release": "1.git.224.bd4cd60.fc28",
"version": "2"
}
}
]
}
The dnf-varlink-3
executable can also be started in server mode
$ ./bin/dnf-varlink-3 --varlink=unix:@com.redhat.packages
And a client can talk to it via the unix socket
$ varlink call unix:@com.redhat.packages/com.redhat.packages.List '{"packages": [{"name":"libvarlink", "version": {"architecture": "x86_64" }}, {"name": "python3-varlink"}]}'
{
"packages": [
{
"available": false,
"installed": true,
"name": "libvarlink",
"version": {
"architecture": "x86_64",
"release": "2.fc28",
"version": "1"
}
},
{
"available": true,
"installed": true,
"name": "python3-varlink",
"version": {
"architecture": "noarch",
"release": "1.git.137.51a669b.fc28",
"version": "12"
}
},
{
"available": true,
"installed": false,
"name": "libvarlink",
"version": {
"architecture": "x86_64",
"release": "1.git.224.bd4cd60.fc28",
"version": "2"
}
}
]
}
Other transport mechanisms can be specified via the varlink address. varlink.SimpleServer
supports exec:
, unix:
and tcp:
.