// to display images directly on GitHub
ifdef::env-github[]
:encoding: UTF-8
:lang: en
:doctype: book
:toc: left
:imagesdir: ../../images
endif::[]

////

    This file is part of the PacketFence project.

    See PacketFence_Developers_Guide.asciidoc
    for authors, copyright and license information.

////

=== PacketFence Golang libraries

==== Basic setup

This is a guide on how to setup/use the PacketFence Golang libraries.

In order to bootstrap your environment:

[source,bash]
----
cd /usr/local/pf/go
make go-env
----

If you work directly on sources, you can run:

[source,bash]
----
cd go
GO_REPO=${PWD} make go-env
----

This will install Golang version use to build PacketFence Golang binaries and
check if all modules defined in [filename]`go.mod` are available.

You should then source your .bashrc to get the new environment variables:

[source,bash]
----
source ~/.bashrc
----

You can get a complete overview of your Golang environment with [command]`go env` command.

==== Pulling the dependencies

Dependencies use go modules and will be fetched automatically during build time.

You will also need [package]`ipset-devel` and [package]`pkgconfig` libraries
which can be installed using the following command:

.RHEL-based systems
[source,bash]
----
yum install ipset-devel pkgconfig
----

.Debian-based systems
[source,bash]
----
apt install libipset-dev pkg-config
----

==== Update dependencies

After you add or remove Golang dependencies, you should run following command
in [filename]`go` directory to update `go.mod` and `go.sum` files:

[source,bash]
----
go mod tidy
----

==== Building the code

All code should be built into a Caddy middleware which we'll then use in a
[filename]`Caddyfile` to create our recipes. Only reason for not using Caddy would be that
the binaries doesn't interact using HTTP (which Caddy can handle at some
point). For now, we'll focus only on services using HTTP until we're
confortable with Caddy.

A local version of Caddy is in [filename]`caddy/caddy`. This is a vendored version of Caddy which includes the plugins and middlewares for PacketFence.

In order to build the Caddy HTTP service (`pfhttpd`):

[source,bash]
----
make pfhttpd
----

Do the same to build `pfdns`, `pfdhcp`, `pfdetect` and `pfstats`:

[source,bash]
----
make all
make copy
----

==== Creating a service

Once you've built `pfhttpd`, you can use a [filename]`Caddyfile` to load your middleware and bind it on a specific port:

----
localhost:1234 {
  logger {
    requesthistory 100
    level DEBUG
  }
  statsd {
    proto udp
    prefix pfsso
  }
  pfsso
}
----

This file should be put in [filename]`/usr/local/pf/conf/caddy-services/pfexample.conf`

Note how you can control the logger configuration from the [filename]`Caddyfile`. If your middleware (in this example `pfsso`) uses or calls the logger, you *must* declare it in your [filename]`Caddyfile`.

If your middleware uses `statsd`, you don't have to configure `statsd` in your [filename]`Caddyfile` which will result in the packets just not being sent (a dummy `statsd` client will be created).

You can start `pfhttpd` with your [filename]`Caddyfile` using the following command:

[source,bash]
----
/usr/local/pf/sbin/pfhttpd -conf /usr/local/pf/conf/caddy-services/pfexample.conf
----

Once you have ascertained that the service is working correctly, you need to
create an instance of `pf::services::manager` for it. You will also need to
create a unitfile for it in [filename]`conf/systemd` like the following:

----
[Unit]
Description=PacketFence Example Service
Wants=packetfence-base.target packetfence-config.service packetfence-iptables.service
After=packetfence-base.target packetfence-config.service packetfence-iptables.service
Before=packetfence-pfexample.service

[Service]
PIDFile=/usr/local/pf/var/run/pfexample.pid
ExecStart=/usr/local/pf/sbin/pfhttpd -conf /usr/local/pf/conf/caddy-services/pfexample.conf
Restart=on-failure
Slice=packetfence.slice

[Install]
WantedBy=packetfence.target
----

Make sure that the packaging is also updated to copy those files in the [filename]`/usr/lib/systemd/system` directory.

==== Running the tests

Like the <<_running_perl_unit_tests,perl unit tests>>, the Golang tests rely on the presence of the test `pfconfig` process to execute properly.

In order to start the test `pfconfig` process:

[source,bash]
----
cd /usr/local/pf/t && ./pfconfig-test
----

You can proceed to execute all or some of the Golang unit tests:

[source,bash]
----
cd /usr/local/pf/go
go test ./...

cd /usr/local/pf/go/firewallsso/lib
go test
----

In order to run all the tests easily you can also do:

[source,bash]
----
cd /usr/local/pf/go
make test
----
