How to develop the LXD hypervisor – Part #1 (client side lxc)

Background: LXD is a hypervisor that manages machine containers on Linux distributions. You install LXD on your Linux distribution and then you can launch machine containers into your distribution running all sort of (other) Linux distributions.

In this post we see how to help develop the LXD hypervisor. That is, learn how to compile the latest version of the LXD source code, make some enhancement or fix, test that it works, and then upload with the aim to get added to the next version of LXD!

LXD is written in the Go programming language, therefore refresh your Go at A Tour of Go and have a look at Learn Go. Even if you are not proficient in Go, you can figure out how to make small changes.

The aim of this post is to make the process of developing as gentle as possible. The LXD software has a server and a client component. Here we focus on the client component, which is the lxc command. The main benefit is that we can use the newly compiled lxc command to access our existing installation of LXD, thus we do not need to deal now with setting up a separate LXD server. For most work, this should be fine. If you really need a separate LXD server, see the future post on this [TODO: add link here when new post is ready!].

Since we are installing  the latest version of the LXD client, you need to have a pretty recent version of the LXD server. The default LXD server in Ubuntu 16.04 would be too old for a fresh and new LXD client. Therefore, you need to upgrade to the snap version of LXD. If you cannot do that yet, then wait for the future post [TODO: add link here when new post is ready!].

Note that https://github.com/lxc/lxd has complete instructions on how to set up your system to compile LXD. Here we focus on the client side, with the lxc executable.

In the following, we compile the latest version of LXD, and specifically only the lxc executable for the LXD client. We will make sure it works (i.e. set it up to work with the snap package of LXD, if you have it). Then, we will make some small change in the source, recompile and check again that the change has been applied.

Compiling the latest version of LXD

First we set up the Go programming language and then compile.

Setting up the Go programming language

If you already installed Go, you can keep it. In that case, skip to the next section.

Let’s check what version of Go is available in your distribution.

$ apt policy golang
golang:
 Installed: (none)
 Candidate: 2:1.6-1ubuntu4
 Version table:
*** 2:1.6-1ubuntu4 500
    500 http://archive.ubuntu.com/ubuntu xenial/main amd64 Packages

This is from Ubuntu 16.04 LTS, and it is version 1.6. This version of Go is sufficient to compile the client of LXD. Therefore,

$ sudo apt install golang

Let’s verify the version,

$ go version
go version go1.6.2 linux/amd64

All is fine.

Then, we set up the GOPATH variable to the location that Go will do its work. Run the following,

$ mkdir -p ~/go
$ export GOPATH=~/go

Then, append the following line into your ~/.profile configuration file.

GOPATH=~/go

We are ready to compile!

Getting the source of the lxc client of LXD

We get (clone) the source of the lxc client and at the same time compile it, with the following command,

$ go get github.com/lxc/lxd/lxc
$

That’s it! The executable lxc can be found in ~/go/bin/. Let’s run both the stock lxcfrom the snap and the lxcthat we just compiled.

$ which lxc
/snap/bin/lxc
$ lxc version
2.21
$ lxc list
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
$ ~/go/bin/lxc version
2.21
$ ~/go/bin/lxc list
LXD socket not found; is LXD installed and running?
Exit 1
$

Therefore, when we want to invoke the compiled version of lxc, we would use the full path ~/go/bin/lxc.

Our compiled lxc cannot access the snap LXD, because the snap LXD is confined. We need to enable remote access for our compiled lxc to the snap LXD server.

Setting up the compiled lxc to access the snap LXD server

See the post How to use lxc remote with the LXD snap, then come back to continue with compiling the lxc source.

Compiling the source of the lxc client of LXD

The go get command fetches the source code, and if the source is already downloaded, it will pull any updates from the repository. It is preferable for us to use a command that would just build the downloaded source code. This can be done with go build. go build compiles the source code and create the executable in the current directory. Let’s try it.

$ go build github.com/lxc/lxd/lxc
$ ls -l lxc
-rwxrwxr-x 1 user user 10189808 Feb 1 20:23 lxc

How long does it take to build the client?

$ time go build github.com/lxc/lxd/lxc
Elapsed time : 0m1.189s

It took about 1 second to compile all of the LXD client!

Here is how we run the freshly compiled LXD client,

$ ./lxc
Usage: lxc <command> [options]

This is the LXD command line client.
....

Making a change to the lxc source

When we the lxc client without parameters, we get

$ ./lxc
Usage: lxc <command> [options]

This is the LXD command line client.

All of LXD's features can be driven through the various commands below.
For help with any of those, simply call them with --help.

Commands:
 config Change container or server configuration options
 console Interact with the container's console device and log
....................

Let’s change the message the LXD command line client to the LXD command line client we just compiled. We use grep to search the source code for the occurrence of the string so that we can fine the file.

$ grep -r "the LXD command line client" ~/go/src/github.com/lxc/lxd/lxc/
/home/ubuntu/go/src/github.com/lxc/lxd/lxc/help.go: fmt.Println(i18n.G(`This is the LXD command line client.

We edit the file ~/go/src/github.com/lxc/lxd/lxc/help.go, then search for that string and make the change.

Then, let’s build the LXD client lxc.

$ go build github.com/lxc/lxd/lxc
$ ./lxc
Usage: lxc <command> [options]

This is the LXD command line client we just compiled.

All of LXD's features can be driven through the various commands below.
For help with any of those, simply call them with --help.

Commands:
 config Change container or server configuration options
 copy Copy containers within or in between LXD instances
...............

And our change appears in the output of the lxc command.

Troubleshooting

Why do I get package github.com/lxc/lxd: no buildable Go source files?

You tried the following,

$ go get github.com/lxc/lxd
package github.com/lxc/lxd: no buildable Go source files in /home/ubuntu/go/src/github.com/lxc/lxd
$

The LXD repository on github.com is not a Go repository. That is, Go cannot compile it by itself. You would need instead to run go get with the appropriate flags that will just download the files, not compile them.

$ go get -d -v github.com/lxc/lxd/lxd
$ cd $GOPATH/src/github.com/lxc/lxd
$ make

Why do I get package context: unrecognized import path “context” (import path does not begin with hostname)?

You tried to compile LXD (specifically, the lxd server) with Go 1.6 or older. Currently, only the lxc client compiles fine with Go 1.6. Install a newer version of Go and try again.

Why do I get “LXD socket not found; is LXD installed and running?”

Your lxc client cannot connect to a LXD server. If you are following the instructions of this post, then see again the following post.

How to use lxc remote with the LXD snap

Permanent link to this article: https://blog.simos.info/how-to-develop-the-lxd-hypervisor-part-1-client-side-lxc/

1 ping

  1. […] How to develop the LXD hypervisor – Part #1 (client side lxc) […]

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: