Reimplement dnsmasq-entrypoint in go
This allowed for deleting all script utilities and environment variable logic.
This commit is contained in:
parent
2200d85992
commit
03618ba72c
16
default.nix
16
default.nix
@ -57,9 +57,11 @@ in rec {
|
||||
|
||||
entrypoint = pkgs.callPackage ./entrypoint {};
|
||||
|
||||
dnsmasq = (pkgs.callPackage ./dnsmasq {
|
||||
dnsmasq = (pkgs.callPackage ./nix/dnsmasq.nix {
|
||||
glibcStatic = pkgs.glibc.static;
|
||||
}).env;
|
||||
});
|
||||
|
||||
nebula = pkgs.callPackage ./nix/nebula.nix {};
|
||||
|
||||
garage = (pkgs.callPackage ./nix/garage.nix {}).env;
|
||||
|
||||
@ -69,18 +71,10 @@ in rec {
|
||||
name = "cryptic-net-AppDir";
|
||||
paths = [
|
||||
|
||||
pkgs.pkgsStatic.bash
|
||||
pkgs.pkgsStatic.coreutils
|
||||
pkgs.pkgsStatic.gnutar
|
||||
pkgs.pkgsStatic.gzip
|
||||
|
||||
# custom packages from ./pkgs.nix
|
||||
pkgs.yq-go
|
||||
pkgs.nebula
|
||||
|
||||
./AppDir
|
||||
version
|
||||
dnsmasq
|
||||
nebula
|
||||
garage
|
||||
entrypoint
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
# TODO implement this in go
|
||||
|
||||
set -e -o pipefail
|
||||
cd "$APPDIR"
|
||||
|
||||
conf_path="$_RUNTIME_DIR_PATH"/dnsmasq.conf
|
||||
|
||||
cat etc/dnsmasq/base.conf > "$conf_path"
|
||||
|
||||
tmp="$(mktemp -d -t cryptic-net-dnsmasq-entrypoint-XXX)"
|
||||
|
||||
( trap "rm -rf '$tmp'" EXIT
|
||||
|
||||
tar xzf "$_BOOTSTRAP_PATH" -C "$tmp" ./hosts
|
||||
|
||||
thisHostName=$(tar xzf "$_BOOTSTRAP_PATH" --to-stdout ./hostname)
|
||||
thisHostIP=$(cat "$tmp"/hosts/"$thisHostName".yml | yq '.nebula.ip')
|
||||
|
||||
domain=$(tar xzf "$_BOOTSTRAP_PATH" --to-stdout ./admin/creation-params.yml | yq '.domain')
|
||||
|
||||
echo "listen-address=$thisHostIP" >> "$conf_path"
|
||||
|
||||
ls -1 "$tmp"/hosts | while read hostYml; do
|
||||
|
||||
hostName=$(echo "$hostYml" | cut -d. -f1)
|
||||
hostIP=$(cat "$tmp"/hosts/"$hostYml" | yq '.nebula.ip')
|
||||
echo "address=/${hostName}.hosts.$domain/$hostIP" >> "$conf_path"
|
||||
|
||||
done
|
||||
)
|
||||
|
||||
cat "$_DAEMON_YML_PATH" | \
|
||||
yq '.dns.resolvers | .[] | "server=" + .' \
|
||||
>> "$conf_path"
|
||||
|
||||
exec bin/dnsmasq -d -C "$conf_path"
|
@ -1,39 +0,0 @@
|
||||
{
|
||||
|
||||
stdenv,
|
||||
buildEnv,
|
||||
glibcStatic,
|
||||
rebase,
|
||||
|
||||
}: rec {
|
||||
|
||||
dnsmasq = stdenv.mkDerivation rec {
|
||||
pname = "dnsmasq";
|
||||
version = "2.85";
|
||||
|
||||
src = builtins.fetchurl {
|
||||
url = "https://www.thekelleys.org.uk/dnsmasq/${pname}-${version}.tar.xz";
|
||||
sha256 = "sha256-rZjTgD32h+W5OAgPPSXGKP5ByHh1LQP7xhmXh/7jEvo=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ glibcStatic ];
|
||||
|
||||
makeFlags = [
|
||||
"LDFLAGS=-static"
|
||||
"DESTDIR="
|
||||
"BINDIR=$(out)/bin"
|
||||
"MANDIR=$(out)/man"
|
||||
"LOCALEDIR=$(out)/share/locale"
|
||||
];
|
||||
};
|
||||
|
||||
env = buildEnv {
|
||||
name = "cryptic-net-dnsmasq";
|
||||
paths = [
|
||||
(rebase "cryptic-net-dnsmasq-bin" ./bin "bin")
|
||||
(rebase "cryptic-net-dnsmasq-etc" ./etc "etc/dnsmasq")
|
||||
dnsmasq
|
||||
];
|
||||
};
|
||||
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
# Configuration file for dnsmasq.
|
||||
#
|
||||
# Format is one option per line, legal options are the same
|
||||
# as the long options legal on the command line. See
|
||||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||
|
||||
# Listen on this specific port instead of the standard DNS port
|
||||
# (53). Setting this to zero completely disables DNS function,
|
||||
# leaving only DHCP and/or TFTP.
|
||||
port=53
|
||||
|
||||
# If you don't want dnsmasq to read /etc/resolv.conf or any other
|
||||
# file, getting its servers from this file instead (see below), then
|
||||
# uncomment this.
|
||||
no-resolv
|
||||
|
||||
# On systems which support it, dnsmasq binds the wildcard address,
|
||||
# even when it is listening on only some interfaces. It then discards
|
||||
# requests that it shouldn't reply to. This has the advantage of
|
||||
# working even when interfaces come and go and change address. If you
|
||||
# want dnsmasq to really bind only the interfaces it is listening on,
|
||||
# uncomment this option. About the only time you may need this is when
|
||||
# running another nameserver on the same machine.
|
||||
bind-interfaces
|
||||
|
||||
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
||||
# following line.
|
||||
no-hosts
|
||||
|
||||
# Unset user and group so that dnsmasq doesn't drop privileges to another user.
|
||||
# If this isn't done then dnsmasq fails to start up, since it fails to access
|
||||
# /etc/passwd correctly, probably due to nix.
|
||||
user=
|
||||
group=
|
||||
|
||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
#
|
||||
# Everything below is generated dynamically based on runtime configuration
|
||||
#
|
||||
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
@ -94,16 +94,14 @@ func runDaemonPmuxOnce(env crypticnet.Env) (crypticnet.Env, error) {
|
||||
return crypticnet.Env{}, fmt.Errorf("generating nebula config: %w", err)
|
||||
}
|
||||
|
||||
dnsmasqPmuxProcConfig, err := dnsmasqPmuxProcConfig(env)
|
||||
if err != nil {
|
||||
return crypticnet.Env{}, fmt.Errorf("generating dnsmasq config: %w", err)
|
||||
}
|
||||
|
||||
pmuxProcConfigs := []pmuxlib.ProcessConfig{
|
||||
nebulaPmuxProcConfig,
|
||||
{
|
||||
Name: "dnsmasq",
|
||||
Cmd: "bash",
|
||||
Args: []string{"dnsmasq-entrypoint"},
|
||||
StartAfterFunc: func(ctx context.Context) error {
|
||||
return waitForNebula(ctx, env)
|
||||
},
|
||||
},
|
||||
dnsmasqPmuxProcConfig,
|
||||
}
|
||||
|
||||
if len(thisDaemon.Storage.Allocations) > 0 {
|
||||
@ -302,15 +300,6 @@ var subCmdDaemon = subCmd{
|
||||
return fmt.Errorf("merging daemon.yml into bootstrap data: %w", err)
|
||||
}
|
||||
|
||||
// TODO once dnsmasq entrypoint is written in go and the config
|
||||
// generation is inlined into this process then this Setenv won't be
|
||||
// necessary.
|
||||
for key, val := range env.ToMap() {
|
||||
if err := os.Setenv(key, val); err != nil {
|
||||
return fmt.Errorf("failed to set %q to %q: %w", key, val, err)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
if env, err = runDaemonPmuxOnce(env); errors.Is(err, context.Canceled) {
|
||||
|
45
entrypoint/src/cmd/entrypoint/dnsmasq_util.go
Normal file
45
entrypoint/src/cmd/entrypoint/dnsmasq_util.go
Normal file
@ -0,0 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
crypticnet "cryptic-net"
|
||||
"cryptic-net/bootstrap"
|
||||
"cryptic-net/dnsmasq"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"code.betamike.com/cryptic-io/pmux/pmuxlib"
|
||||
)
|
||||
|
||||
func dnsmasqPmuxProcConfig(env crypticnet.Env) (pmuxlib.ProcessConfig, error) {
|
||||
|
||||
thisDaemon := env.ThisDaemon()
|
||||
|
||||
confPath := filepath.Join(env.RuntimeDirPath, "dnsmasq.conf")
|
||||
|
||||
hostsSlice := make([]bootstrap.Host, 0, len(env.Bootstrap.Hosts))
|
||||
for _, host := range env.Bootstrap.Hosts {
|
||||
hostsSlice = append(hostsSlice, host)
|
||||
}
|
||||
|
||||
sort.Slice(hostsSlice, func(i, j int) bool {
|
||||
return hostsSlice[i].Nebula.IP < hostsSlice[j].Nebula.IP
|
||||
})
|
||||
|
||||
confData := dnsmasq.ConfData{
|
||||
Resolvers: thisDaemon.DNS.Resolvers,
|
||||
Domain: env.Bootstrap.AdminCreationParams.Domain,
|
||||
IP: env.Bootstrap.ThisHost().Nebula.IP,
|
||||
Hosts: hostsSlice,
|
||||
}
|
||||
|
||||
if err := dnsmasq.WriteConfFile(confPath, confData); err != nil {
|
||||
return pmuxlib.ProcessConfig{}, fmt.Errorf("writing dnsmasq.conf to %q: %w", confPath, err)
|
||||
}
|
||||
|
||||
return pmuxlib.ProcessConfig{
|
||||
Name: "dnsmasq",
|
||||
Cmd: "dnsmasq",
|
||||
Args: []string{"-d", "-C", confPath},
|
||||
}, nil
|
||||
}
|
3
entrypoint/src/dnsmasq/dnsmasq.go
Normal file
3
entrypoint/src/dnsmasq/dnsmasq.go
Normal file
@ -0,0 +1,3 @@
|
||||
// Package dnsmasq contains helper functions and types which are useful for
|
||||
// setting up dnsmasq configs, processes, and deployments.
|
||||
package dnsmasq
|
58
entrypoint/src/dnsmasq/tpl.go
Normal file
58
entrypoint/src/dnsmasq/tpl.go
Normal file
@ -0,0 +1,58 @@
|
||||
package dnsmasq
|
||||
|
||||
import (
|
||||
"cryptic-net/bootstrap"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// ConfData describes all the data needed to populate a dnsmasq.conf file.
|
||||
type ConfData struct {
|
||||
Resolvers []string
|
||||
Domain string
|
||||
IP string
|
||||
Hosts []bootstrap.Host
|
||||
}
|
||||
|
||||
var confTpl = template.Must(template.New("").Parse(`
|
||||
port=53
|
||||
|
||||
bind-interfaces
|
||||
listen-address={{ .IP }}
|
||||
|
||||
no-resolv
|
||||
no-hosts
|
||||
|
||||
user=
|
||||
group=
|
||||
|
||||
{{- range $host := .Hosts }}
|
||||
address=/{{ $host.Name }}.hosts.{{ .Domain }}/{{ $host.Nebula.IP }}
|
||||
{{ end -}}
|
||||
|
||||
{{- range .Resolvers }}
|
||||
server={{ . }}
|
||||
{{ end -}}
|
||||
`))
|
||||
|
||||
// WriteConfFile renders a dnsmasq.conf using the given data to a new
|
||||
// file at the given path.
|
||||
func WriteConfFile(path string, data ConfData) error {
|
||||
|
||||
file, err := os.OpenFile(
|
||||
path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating file: %w", err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
if err := confTpl.Execute(file, data); err != nil {
|
||||
return fmt.Errorf("rendering template to file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -19,14 +19,6 @@ import (
|
||||
"github.com/adrg/xdg"
|
||||
)
|
||||
|
||||
// Names of various environment variables which get set by the entrypoint.
|
||||
const (
|
||||
DaemonYmlPathEnvVar = "_DAEMON_YML_PATH"
|
||||
BootstrapPathEnvVar = "_BOOTSTRAP_PATH"
|
||||
RuntimeDirPathEnvVar = "_RUNTIME_DIR_PATH"
|
||||
DataDirPathEnvVar = "_DATA_DIR_PATH"
|
||||
)
|
||||
|
||||
// Env contains the values of environment variables, as well as other entities
|
||||
// which are useful across all processes.
|
||||
type Env struct {
|
||||
@ -74,40 +66,6 @@ func NewEnv(bootstrapOptional bool) (Env, error) {
|
||||
return env.init(bootstrapOptional)
|
||||
}
|
||||
|
||||
// ReadEnv reads an Env from the process's environment variables, rather than
|
||||
// calculating like NewEnv does.
|
||||
func ReadEnv() (Env, error) {
|
||||
|
||||
var err error
|
||||
|
||||
readEnv := func(key string) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
val := os.Getenv(key)
|
||||
|
||||
if val == "" {
|
||||
err = fmt.Errorf("envvar %q not set", key)
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
env := Env{
|
||||
AppDirPath: getAppDirPath(),
|
||||
DaemonYmlPath: readEnv(DaemonYmlPathEnvVar),
|
||||
RuntimeDirPath: readEnv(RuntimeDirPathEnvVar),
|
||||
DataDirPath: readEnv(DataDirPathEnvVar),
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return Env{}, err
|
||||
}
|
||||
|
||||
return env.init(false)
|
||||
}
|
||||
|
||||
// DataDirBootstrapPath returns the path to the bootstrap file within the user's
|
||||
// data dir. If the file does not exist there it will be found in the AppDirPath
|
||||
// by ReloadBootstrap.
|
||||
@ -197,17 +155,6 @@ func (e Env) init(bootstrapOptional bool) (Env, error) {
|
||||
return e.initBootstrap(bootstrapOptional)
|
||||
}
|
||||
|
||||
// ToMap returns the Env as a map of key/value strings. If this map is set into
|
||||
// a process's environment, then that process can read it back using ReadEnv.
|
||||
func (e Env) ToMap() map[string]string {
|
||||
return map[string]string{
|
||||
DaemonYmlPathEnvVar: e.DaemonYmlPath,
|
||||
BootstrapPathEnvVar: e.BootstrapPath,
|
||||
RuntimeDirPathEnvVar: e.RuntimeDirPath,
|
||||
DataDirPathEnvVar: e.DataDirPath,
|
||||
}
|
||||
}
|
||||
|
||||
// ThisDaemon returns the DaemonYml (loaded from DaemonYmlPath) for the
|
||||
// currently running process.
|
||||
func (e Env) ThisDaemon() DaemonYml {
|
||||
|
@ -67,9 +67,7 @@ func WriteGarageTomlFile(path string, data GarageTomlData) error {
|
||||
|
||||
defer file.Close()
|
||||
|
||||
err = RenderGarageToml(file, data)
|
||||
|
||||
if err != nil {
|
||||
if err := garageTomlTpl.Execute(file, data); err != nil {
|
||||
return fmt.Errorf("rendering template to file: %w", err)
|
||||
}
|
||||
|
||||
|
25
nix/dnsmasq.nix
Normal file
25
nix/dnsmasq.nix
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
|
||||
stdenv,
|
||||
glibcStatic,
|
||||
|
||||
}: stdenv.mkDerivation rec {
|
||||
|
||||
pname = "dnsmasq";
|
||||
version = "2.85";
|
||||
|
||||
src = builtins.fetchurl {
|
||||
url = "https://www.thekelleys.org.uk/dnsmasq/${pname}-${version}.tar.xz";
|
||||
sha256 = "sha256-rZjTgD32h+W5OAgPPSXGKP5ByHh1LQP7xhmXh/7jEvo=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ glibcStatic ];
|
||||
|
||||
makeFlags = [
|
||||
"LDFLAGS=-static"
|
||||
"DESTDIR="
|
||||
"BINDIR=$(out)/bin"
|
||||
"MANDIR=$(out)/man"
|
||||
"LOCALEDIR=$(out)/share/locale"
|
||||
];
|
||||
}
|
13
nix/pkgs.nix
13
nix/pkgs.nix
@ -2,7 +2,8 @@ rec {
|
||||
|
||||
overlays = [
|
||||
|
||||
# Make both buildGoModules use static compilation by default.
|
||||
# Make buildGoModules use static compilation by default, and use go 1.18
|
||||
# everywhere.
|
||||
(final: prev:
|
||||
|
||||
let
|
||||
@ -17,19 +18,11 @@ rec {
|
||||
in {
|
||||
|
||||
go = prev.go_1_18;
|
||||
buildGoModule = args: prev.buildGoModule (buildArgs // args);
|
||||
buildGoModule = args: prev.buildGo118Module (buildArgs // args);
|
||||
buildGo118Module = args: prev.buildGo118Module (buildArgs // args);
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
(final: prev: { rebase = prev.callPackage ./rebase.nix {}; })
|
||||
(final: prev: { yq-go = prev.callPackage ./yq-go.nix {}; })
|
||||
|
||||
(final: prev: { nebula = prev.callPackage ./nebula.nix {
|
||||
buildGoModule = prev.buildGo118Module;
|
||||
}; })
|
||||
|
||||
];
|
||||
|
||||
version = "22-05";
|
||||
|
@ -1,18 +0,0 @@
|
||||
# rebase is a helper which takes all files/dirs under oldroot, and
|
||||
# creates a new derivation with those files/dirs copied under newroot
|
||||
# (where newroot is a relative path to the root of the derivation).
|
||||
|
||||
{
|
||||
|
||||
stdenv,
|
||||
|
||||
}: name: oldroot: newroot: stdenv.mkDerivation {
|
||||
|
||||
inherit name oldroot newroot;
|
||||
|
||||
builder = builtins.toFile "builder.sh" ''
|
||||
source $stdenv/setup
|
||||
mkdir -p "$out"/"$newroot"
|
||||
cp -rL "$oldroot"/* "$out"/"$newroot"
|
||||
'';
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
|
||||
buildGoModule,
|
||||
fetchFromGitHub,
|
||||
|
||||
}: buildGoModule rec {
|
||||
|
||||
pname = "yq-go";
|
||||
version = "4.21.1";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "mikefarah";
|
||||
repo = "yq";
|
||||
rev = "v${version}";
|
||||
sha256 = "sha256-283xe7FVHYSsRl4cZD7WDzIW1gqNAFsNrWYJkthZheU=";
|
||||
};
|
||||
|
||||
vendorSha256 = "sha256-F11FnDYJ59aKrdRXDPpKlhX52yQXdaN1sblSkVI2j9w=";
|
||||
}
|
Loading…
Reference in New Issue
Block a user