Skip to content

Commit

Permalink
metadata-api: support dnsmasq (#3115)
Browse files Browse the repository at this point in the history
  • Loading branch information
3u13r authored May 24, 2024
1 parent 37e46b9 commit 21c30eb
Show file tree
Hide file tree
Showing 18 changed files with 304 additions and 270 deletions.
3 changes: 2 additions & 1 deletion hack/qemu-metadata-api/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ go_library(
importpath = "github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api",
visibility = ["//visibility:private"],
deps = [
"//hack/qemu-metadata-api/dhcp/dnsmasq",
"//hack/qemu-metadata-api/dhcp/virtwrapper",
"//hack/qemu-metadata-api/server",
"//hack/qemu-metadata-api/virtwrapper",
"//internal/logger",
"@org_libvirt_go_libvirt//:libvirt",
],
Expand Down
8 changes: 8 additions & 0 deletions hack/qemu-metadata-api/dhcp/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "dhcp",
srcs = ["dhcp.go"],
importpath = "github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp",
visibility = ["//visibility:public"],
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

package virtwrapper
package dhcp

// NetworkDHCPLease abstracts a libvirt DHCP lease.
// NetworkDHCPLease abstracts a DHCP lease.
type NetworkDHCPLease struct {
IPaddr string
Hostname string
Expand Down
24 changes: 24 additions & 0 deletions hack/qemu-metadata-api/dhcp/dnsmasq/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//bazel/go:go_test.bzl", "go_test")

go_library(
name = "dnsmasq",
srcs = ["dnsmasq.go"],
importpath = "github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp/dnsmasq",
visibility = ["//visibility:public"],
deps = [
"//hack/qemu-metadata-api/dhcp",
"@com_github_spf13_afero//:afero",
],
)

go_test(
name = "dnsmasq_test",
srcs = ["dnsmasq_test.go"],
embed = [":dnsmasq"],
deps = [
"@com_github_spf13_afero//:afero",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
],
)
56 changes: 56 additions & 0 deletions hack/qemu-metadata-api/dhcp/dnsmasq/dnsmasq.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

package dnsmasq

import (
"bufio"
"strings"

"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp"
"github.com/spf13/afero"
)

// DNSMasq is a DHCP lease getter for dnsmasq.
type DNSMasq struct {
leasesFileName string
fs *afero.Afero
}

// New creates a new DNSMasq.
func New(leasesFileName string) *DNSMasq {
return &DNSMasq{
leasesFileName: leasesFileName,
fs: &afero.Afero{Fs: afero.NewOsFs()},
}
}

// GetDHCPLeases returns the underlying DHCP leases.
func (d *DNSMasq) GetDHCPLeases() ([]dhcp.NetworkDHCPLease, error) {
file, err := d.fs.Open(d.leasesFileName)
if err != nil {
return nil, err
}
defer file.Close()

// read file
var leases []dhcp.NetworkDHCPLease
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// split by whitespace
fields := strings.Fields(line)
leases = append(leases, dhcp.NetworkDHCPLease{
IPaddr: fields[2],
Hostname: fields[3],
})
}
if err := scanner.Err(); err != nil {
return nil, err
}

return leases, nil
}
40 changes: 40 additions & 0 deletions hack/qemu-metadata-api/dhcp/dnsmasq/dnsmasq_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

package dnsmasq

import (
"testing"

"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetDHCPLeases(t *testing.T) {
require := require.New(t)
assert := assert.New(t)

fs := afero.NewMemMapFs()
leasesFileName := "dnsmasq.leases"
leasesFile, err := fs.Create(leasesFileName)
require.NoError(err)
_, err = leasesFile.WriteString("1716219737 52:54:af:a1:98:9f 10.42.2.1 worker0 ff:c2:72:f6:09:00:02:00:00:ab:11:18:fc:48:85:40:3f:bc:41\n")
require.NoError(err)
_, err = leasesFile.WriteString("1716219735 52:54:7f:8f:ba:91 10.42.1.1 controlplane0 ff:c2:72:f6:09:00:02:00:00:ab:11:21:7c:b5:14:ec:43:b7:43\n")
require.NoError(err)
leasesFile.Close()

d := DNSMasq{leasesFileName: leasesFileName, fs: &afero.Afero{Fs: fs}}
leases, err := d.GetDHCPLeases()
require.NoError(err)

assert.Len(leases, 2)
assert.Equal("10.42.2.1", leases[0].IPaddr)
assert.Equal("worker0", leases[0].Hostname)
assert.Equal("10.42.1.1", leases[1].IPaddr)
assert.Equal("controlplane0", leases[1].Hostname)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ go_library(
"virtwrapper_cgo.go",
"virtwrapper_cross.go",
],
importpath = "github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/virtwrapper",
importpath = "github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp/virtwrapper",
visibility = ["//visibility:public"],
deps = ["@org_libvirt_go_libvirt//:libvirt"],
deps = [
"//hack/qemu-metadata-api/dhcp",
"@org_libvirt_go_libvirt//:libvirt",
],
)
7 changes: 7 additions & 0 deletions hack/qemu-metadata-api/dhcp/virtwrapper/virtwrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

package virtwrapper
60 changes: 60 additions & 0 deletions hack/qemu-metadata-api/dhcp/virtwrapper/virtwrapper_cgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//go:build cgo

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

package virtwrapper

import (
"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp"

"libvirt.org/go/libvirt"
)

// Connect wraps a libvirt connection.
type Connect struct {
conn *libvirt.Connect
networkName string
}

// New creates a new libvirt Connct wrapper.
func New(conn *libvirt.Connect, networkName string) *Connect {
return &Connect{
conn: conn,
networkName: networkName,
}
}

// LookupNetworkByName looks up a network by name.
func (c *Connect) lookupNetworkByName(name string) (*libvirt.Network, error) {
net, err := c.conn.LookupNetworkByName(name)
if err != nil {
return nil, err
}
return net, nil
}

// GetDHCPLeases returns the underlying DHCP leases.
func (c *Connect) GetDHCPLeases() ([]dhcp.NetworkDHCPLease, error) {
net, err := c.lookupNetworkByName(c.networkName)
if err != nil {
return nil, err
}
defer net.Free()

leases, err := net.GetDHCPLeases()
if err != nil {
return nil, err
}
ret := make([]dhcp.NetworkDHCPLease, len(leases))
for i, l := range leases {
ret[i] = dhcp.NetworkDHCPLease{
IPaddr: l.IPaddr,
Hostname: l.Hostname,
}
}
return ret, nil
}
24 changes: 24 additions & 0 deletions hack/qemu-metadata-api/dhcp/virtwrapper/virtwrapper_cross.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//go:build !cgo

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/

package virtwrapper

import (
"errors"

"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp"
)

// Connect wraps a libvirt connection.
type Connect struct{}

// GetDHCPLeases returns the underlying DHCP leases.
// This function errors if CGO is disabled.
func (n *Connect) GetDHCPLeases() ([]dhcp.NetworkDHCPLease, error) {
return nil, errors.New("using virtwrapper requires building with CGO")
}
25 changes: 17 additions & 8 deletions hack/qemu-metadata-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,38 @@ import (
"log/slog"
"os"

"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp/dnsmasq"
"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/dhcp/virtwrapper"
"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/server"
"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/virtwrapper"
"github.com/edgelesssys/constellation/v2/internal/logger"
"libvirt.org/go/libvirt"
)

func main() {
bindPort := flag.String("port", "8080", "Port to bind to")
targetNetwork := flag.String("network", "constellation-network", "Name of the network in QEMU to use")
targetNetwork := flag.String("network", "constellation-network", "Name of the network in libvirt")
libvirtURI := flag.String("libvirt-uri", "qemu:///system", "URI of the libvirt connection")
leasesFileName := flag.String("dnsmasq-leases", "", "Path to the dnsmasq leases file")
initSecretHash := flag.String("initsecrethash", "", "brcypt hash of the init secret")
flag.Parse()

log := logger.NewJSONLogger(slog.LevelInfo)

conn, err := libvirt.NewConnect(*libvirtURI)
if err != nil {
log.With(slog.Any("error", err)).Error("Failed to connect to libvirt")
os.Exit(1)
var leaseGetter server.LeaseGetter
if *leasesFileName == "" {
conn, err := libvirt.NewConnect(*libvirtURI)
if err != nil {
log.With(slog.Any("error", err)).Error("Failed to connect to libvirt")
os.Exit(1)
}
defer conn.Close()
leaseGetter = virtwrapper.New(conn, *targetNetwork)
} else {
log.Info("Using dnsmasq leases file")
leaseGetter = dnsmasq.New(*leasesFileName)
}
defer conn.Close()

serv := server.New(log, *targetNetwork, *initSecretHash, &virtwrapper.Connect{Conn: conn})
serv := server.New(log, *targetNetwork, *initSecretHash, leaseGetter)
if err := serv.ListenAndServe(*bindPort); err != nil {
log.With(slog.Any("error", err)).Error("Failed to serve")
os.Exit(1)
Expand Down
11 changes: 3 additions & 8 deletions hack/qemu-metadata-api/server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,25 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//hack/qemu-metadata-api/virtwrapper",
"//hack/qemu-metadata-api/dhcp",
"//internal/cloud/metadata",
"//internal/role",
],
)

go_test(
name = "server_test",
srcs = [
"server_cgo_test.go",
"server_cross_test.go",
"server_test.go",
],
srcs = ["server_test.go"],
embed = [":server"],
# keep
pure = "on",
# keep
race = "off",
deps = [
"//hack/qemu-metadata-api/virtwrapper",
"//hack/qemu-metadata-api/dhcp",
"//internal/cloud/metadata",
"//internal/logger",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
"@org_libvirt_go_libvirt//:libvirt",
],
)
Loading

0 comments on commit 21c30eb

Please sign in to comment.