Compare commits

...

22 Commits

Author SHA1 Message Date
karasz ff3feb49f2 Merge pull request 'cluster: drop wg1.conf' (#58)
Reviewed-on: #58
2024-07-29 21:57:06 +02:00
amery b0356c7ebb jpictl: don't append -1 to ring1 addresses on jpictl list
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-29 19:09:37 +00:00
amery 08da69f7aa cluster: change wg0.conf to allow ring0/32 and ring1/32 on each peer
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-29 18:13:57 +00:00
amery 6e3bb24b36 cluster: further remove wg1 support
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-29 18:13:57 +00:00
amery 9810f5c6c1 cluster: drop wg1.conf generation
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-29 16:47:35 +00:00
amery 8948b6702a Revert "cluster: fix wg1 generation (AllowedIPs)"
This reverts commit f0c09c2176.
2024-07-29 16:47:35 +00:00
amery 593f88e2a3 Merge pull request #57 (wg1.conf)
cluster: fix wg1 generation (AllowedIPs)

Reviewed-on: #57
2024-07-26 20:34:53 +02:00
Nagy Károly Gábriel f0c09c2176 cluster: fix wg1 generation (AllowedIPs)
Signed-off-by: Nagy Károly Gábriel <k@jpi.io>
2024-07-26 15:28:32 +03:00
amery f9462d3e0b Merge pull request (#55)
introduce `jpictl list`, `tools.LazyBuffer` and updated build system

Reviewed-on: #55
2024-07-25 20:22:17 +02:00
amery c20bd3d41f jpictl: introduce initial jpictl list
to see the different networks and addresses

currently limited to rings zero and one.

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-25 17:36:59 +00:00
amery f0cef6c19f tools: introduce LazyClose()
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-25 17:28:56 +00:00
amery 05538e6925 tools: introduce LazyBuffer abstraction of bytes.Buffer
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-25 17:27:28 +00:00
amery 0c21d74c15 rings: make unsafe address factories public
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-25 17:17:57 +00:00
amery 401603f4be chore: clear lint warnings
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-25 17:16:02 +00:00
amery ac43ee869c build-sys: update build sys to darvaza.org/x's latest
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-25 17:12:57 +00:00
amery 4345a17d9a Merge pull request 'cluster: fix wg0.conf generator' (#54) from pr-amery-wg0.conf into main
Reviewed-on: #54
2024-07-24 19:31:22 +02:00
amery 01ef75a020 cluster: fix wg0.conf generator
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-24 17:30:10 +00:00
amery d0efcbaa74 Merge pull request 'cluster: rework env output to qualify zones using the region' (#53) from pr-amery-env into main
Reviewed-on: #53
2024-07-17 17:58:47 +02:00
amery 7f5d48b2b0 cluster: rework env output to qualify zones using the region
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-07-17 15:54:35 +00:00
karasz 00b2f8b531 Merge pull request 'cluster: migrate to using pkg/rings for Addresses' (#51) from pr-amery-rings into main
Reviewed-on: #51
2024-06-04 10:53:13 +02:00
amery 948eff76d3 cluster: migrate to using pkg/rings for Addresses
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-06-03 20:45:29 +00:00
amery 187149c129 cluster: decouple RingID from WireguardInterfaceID
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-06-03 20:45:29 +00:00
25 changed files with 867 additions and 449 deletions
+14 -16
View File
@@ -6,20 +6,20 @@ GOFMT ?= gofmt
GOFMT_FLAGS = -w -l -s
GOGENERATE_FLAGS = -v
GOPATH ?= $(shell $(GO) env GOPATH)
GOBIN ?= $(GOPATH)/bin
TOOLSDIR := $(CURDIR)/pkg/tools
TMPDIR ?= .tmp
TMPDIR ?= $(CURDIR)/.tmp
OUTDIR ?= $(TMPDIR)
GOLANGCI_LINT_VERSION ?= v1.59.1
REVIVE_VERSION ?= v1.3.7
GOLANGCI_LINT_URL ?= github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
GOLANGCI_LINT ?= $(GO) run $(GOLANGCI_LINT_URL)
REVIVE ?= $(GOBIN)/revive
REVIVE_CONF ?= $(TOOLSDIR)/revive.toml
REVIVE_RUN_ARGS ?= -config $(REVIVE_CONF) -formatter friendly
REVIVE_VERSION ?= v1.3.7
REVIVE_INSTALL_URL ?= github.com/mgechev/revive@$(REVIVE_VERSION)
GO_INSTALL_URLS = \
$(REVIVE_INSTALL_URL) \
REVIVE_URL ?= github.com/mgechev/revive@$(REVIVE_VERSION)
REVIVE ?= $(GO) run $(REVIVE_URL)
V = 0
Q = $(if $(filter 1,$V),,@)
@@ -30,12 +30,13 @@ GO_BUILD_CMD = $(GO_BUILD) -o "$(OUTDIR)"
all: get generate tidy build
install:
$Q $(GO) install -v ./cmd/...
clean: ; $(info $(M) cleaning)
rm -rf $(TMPDIR)
install: ; $(info $(M) cleaning)
$Q $(GO) install -v ./cmd/...
$(TMPDIR)/index: $(TOOLSDIR)/gen_index.sh Makefile FORCE ; $(info $(M) generating index)
$Q mkdir -p $(@D)
$Q $< > $@~
@@ -55,6 +56,3 @@ tidy: fmt
generate: ; $(info $(M) running go:generate)
$Q git grep -l '^//go:generate' | sort -uV | xargs -r -n1 $(GO) generate $(GOGENERATE_FLAGS)
$(REVIVE):
$Q $(GO) install -v $(REVIVE_INSTALL_URL)
+3 -3
View File
@@ -43,7 +43,7 @@ func gatewaySet(zi cluster.ZoneIterator, gw string) error {
zi.ForEachZone(func(z *cluster.Zone) bool {
for _, m := range z.Machines {
if m.Name == gw {
z.SetGateway(m.ID, true)
_ = z.SetGateway(m.ID, true)
return true
}
}
@@ -79,8 +79,8 @@ func gatewayUnset(zi cluster.ZoneIterator, ngw string) error {
zi.ForEachZone(func(z *cluster.Zone) bool {
for _, m := range z.Machines {
if m.Name == ngw && m.IsGateway() {
z.SetGateway(m.ID, false)
m.RemoveWireguardConfig(0)
_ = z.SetGateway(m.ID, false)
_ = m.RemoveWireguardConfig(0)
return true
}
}
+200
View File
@@ -0,0 +1,200 @@
package main
import (
"bytes"
"io"
"net/netip"
"os"
"darvaza.org/core"
"github.com/spf13/cobra"
"git.jpi.io/amery/jpictl/pkg/cluster"
"git.jpi.io/amery/jpictl/pkg/rings"
"git.jpi.io/amery/jpictl/pkg/tools"
)
type inventory struct {
r []*cluster.Region
z [][]*cluster.Zone
}
func (g *inventory) renderRingZero(out *tools.LazyBuffer) error {
ring0 := netip.PrefixFrom(rings.UnsafeRingZeroAddress(0, 0, 0), rings.RingZeroBits)
from, to, _ := rings.PrefixToRange(ring0)
_ = out.Printf("; wg%v\n", 0)
_ = out.Printf("%s\t%s-%s\n", ring0, from, to)
if err := g.renderRingZeroRegions(out); err != nil {
return err
}
return g.renderRingZeroZones(out)
}
func (g *inventory) renderRingZeroRegions(out *tools.LazyBuffer) error {
for _, r := range g.r {
if err := g.renderRingZeroRegion(out, r); err != nil {
return err
}
}
return nil
}
func (*inventory) renderRingZeroRegion(out *tools.LazyBuffer, r *cluster.Region) error {
addr := rings.UnsafeRingZeroAddress(r.ID, 0, 0)
ring0r := netip.PrefixFrom(addr, rings.RingZeroBits+4)
from, to, _ := rings.PrefixToRange(ring0r)
_ = out.Printf("%s\t%s-%s\t# %s\n", ring0r, from, to, r.Name)
return nil
}
func (g *inventory) renderRingZeroZones(out *tools.LazyBuffer) error {
for i, r := range g.r {
for _, z := range g.z[i] {
if err := g.renderRingZeroZone(out, r, z); err != nil {
return err
}
}
}
return nil
}
func (*inventory) renderRingZeroZone(out *tools.LazyBuffer, r *cluster.Region, z *cluster.Zone) error {
addr := rings.UnsafeRingZeroAddress(r.ID, z.ID, 0)
ring0rz := netip.PrefixFrom(addr, rings.RingZeroBits+4+4)
from, to, _ := rings.PrefixToRange(ring0rz)
_ = out.Printf("; wg%v: %s (%s)\n", 0, z.Name, r.Name)
_ = out.Printf("%s\t%s-%s\t%s\n", ring0rz, from, to, z.Name)
z.ForEachMachine(func(m *cluster.Machine) bool {
if m.IsGateway() {
addr, _ := m.RingZeroAddress()
cidr := netip.PrefixFrom(addr, 32)
_ = out.Printf("%s\t\t%s-%v\n", cidr, m.Name, 0)
}
return false
})
return nil
}
func (g *inventory) renderRingOne(out *tools.LazyBuffer) error {
for i, r := range g.r {
for _, z := range g.z[i] {
if err := g.renderRingOneZone(out, r, z); err != nil {
return err
}
}
}
return nil
}
func (*inventory) renderRingOneZone(out *tools.LazyBuffer, r *cluster.Region, z *cluster.Zone) error {
ring1, err := rings.RingOnePrefix(r.ID, z.ID)
if err != nil {
return err
}
from, to, _ := rings.PrefixToRange(ring1)
_ = out.Printf("; wg%v: %s (%s)\n", 1, z.Name, r.Name)
_ = out.Printf("%s\t%s-%s\t%s\n", ring1, from, to, z.Name)
z.ForEachMachine(func(m *cluster.Machine) bool {
addr := m.RingOneAddress()
cidr := netip.PrefixFrom(addr, 32)
_ = out.Printf("%s\t\t%s\n", cidr, m.Name)
return false
})
return nil
}
func (g *inventory) Marshal() ([]byte, error) {
var buf tools.LazyBuffer
if err := g.renderRingZero(&buf); err != nil {
return nil, err
}
if err := g.renderRingOne(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (g *inventory) WriteTo(out io.Writer) (int64, error) {
b, err := g.Marshal()
if err != nil {
return 0, err
}
buf := bytes.NewBuffer(b)
return buf.WriteTo(out)
}
func genInventory(m *cluster.Cluster) (*inventory, error) {
g := new(inventory)
g.populateRegions(m)
g.populateZones()
return g, nil
}
func (g *inventory) populateRegions(m *cluster.Cluster) {
m.ForEachRegion(func(r *cluster.Region) bool {
if r.IsPrimary() {
g.r = append(g.r, r)
}
return false
})
core.SliceSortFn(g.r, func(a, b *cluster.Region) bool {
return a.ID < b.ID
})
}
func (g *inventory) populateZones() {
g.z = make([][]*cluster.Zone, len(g.r))
for i, r := range g.r {
r.ForEachZone(func(z *cluster.Zone) bool {
g.z[i] = append(g.z[i], z)
return false
})
core.SliceSortFn(g.z[i], func(a, b *cluster.Zone) bool {
return a.ID < b.ID
})
}
}
// Command
var listCmd = &cobra.Command{
Use: "list",
Short: "list shows the IP/CIDR inventory",
PreRun: setVerbosity,
RunE: func(_ *cobra.Command, _ []string) error {
m, err := cfg.LoadZones(false)
if err != nil {
return err
}
out, err := genInventory(m)
if err != nil {
return err
}
_, err = out.WriteTo(os.Stdout)
return err
},
}
func init() {
rootCmd.AddCommand(listCmd)
}
+14 -23
View File
@@ -1,52 +1,43 @@
module git.jpi.io/amery/jpictl
go 1.19
go 1.21
require (
asciigoat.org/core v0.3.9 // indirect
asciigoat.org/ini v0.2.5
darvaza.org/core v0.13.1
darvaza.org/cache/x/simplelru v0.1.8 // indirect
darvaza.org/core v0.14.2
darvaza.org/resolver v0.9.2
darvaza.org/sidecar v0.4.0
darvaza.org/slog v0.5.7
darvaza.org/slog/handlers/discard v0.4.11
darvaza.org/slog/handlers/filter v0.4.9 // indirect
darvaza.org/slog/handlers/zerolog v0.4.9 // indirect
)
require (
github.com/gofrs/uuid/v5 v5.2.0
github.com/hack-pad/hackpadfs v0.2.1
github.com/libdns/cloudflare v0.1.1
github.com/libdns/libdns v0.2.2
github.com/mgechev/revive v1.3.7
github.com/spf13/cobra v1.8.0
golang.org/x/crypto v0.23.0
golang.org/x/net v0.25.0
golang.org/x/crypto v0.25.0
golang.org/x/net v0.27.0
gopkg.in/yaml.v3 v3.0.1
)
require (
asciigoat.org/core v0.3.9 // indirect
darvaza.org/cache/x/simplelru v0.1.8 // indirect
darvaza.org/slog/handlers/filter v0.4.9 // indirect
darvaza.org/slog/handlers/zerolog v0.4.9 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/miekg/dns v1.1.59 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.21.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
)
+13 -51
View File
@@ -4,8 +4,8 @@ asciigoat.org/ini v0.2.5 h1:4gRIp9rU+XQt8+HMqZO5R7GavMv9Yl2+N+je6djDIAE=
asciigoat.org/ini v0.2.5/go.mod h1:gmXzJ9XFqf1NLk5nQkj04USQ4tMtdRJHNQX6vp3DzjU=
darvaza.org/cache/x/simplelru v0.1.8 h1:rvFucut4wKYbsYc994yR3P0M08NqlsvZxr5G4QK82tw=
darvaza.org/cache/x/simplelru v0.1.8/go.mod h1:Mv1isOJTcXYK+aK0AvUe+/3KpRTXDsYga6rdTS/upNs=
darvaza.org/core v0.13.1 h1:ZoAfZ3OLnw+t28qMQQxXrDIkETmT2h5gAO6F1XuBpwg=
darvaza.org/core v0.13.1/go.mod h1:47Ydh67KnzjLNu1mzX3r2zpphbxQqEaihMsUq5GflQ4=
darvaza.org/core v0.14.2 h1:6p0iznuGfVGbBp+CnkZTw1b76j6Q/j4ffDztZXrrlK8=
darvaza.org/core v0.14.2/go.mod h1:C+B0GRNLB+/asGfxjQ9XZERdk7xaFxzt5xTIBPiNm2M=
darvaza.org/resolver v0.9.2 h1:sUX6LZ1eN5TzJW7L4m7HM+BvwBeWl8dYYDGVSe+AIhk=
darvaza.org/resolver v0.9.2/go.mod h1:XWqPhrxoOKNzRuSozOwmE1M6QVqQL28jEdxylnIO8Nw=
darvaza.org/sidecar v0.4.0 h1:wHghxzLsiT82WDBBUf34aTqtOvRBg4UbxVIJgKNXRVA=
@@ -18,20 +18,9 @@ darvaza.org/slog/handlers/filter v0.4.9 h1:xD8OBwlJytpiwTSDDZqUuNSOsJuaManXQiOj9
darvaza.org/slog/handlers/filter v0.4.9/go.mod h1:t+sjcf1c46kAdf1TRiQmop91xlkteZrC4WDXoVwHgP8=
darvaza.org/slog/handlers/zerolog v0.4.9 h1:08FjRnwRGtJsLLBnbgxVorb/bkgm5QEM/LXD2cxeCbM=
darvaza.org/slog/handlers/zerolog v0.4.9/go.mod h1:PZYfx6eOxQfD+cXJQp52iwKgcD30QVYHoXxOCojAOdw=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM=
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
@@ -53,27 +42,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE=
github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
@@ -81,39 +53,29 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+43
View File
@@ -0,0 +1,43 @@
package cluster
import (
"net/netip"
"git.jpi.io/amery/jpictl/pkg/rings"
)
// RingOnePrefix returns the ring 1 subnet of this [Zone].
func (z *Zone) RingOnePrefix() netip.Prefix {
subnet, err := rings.RingOnePrefix(z.RegionID(), z.ID)
if err != nil {
panic(err)
}
return subnet
}
// RingOnePrefix returns the ring 1 subnet this [Machine] belongs
// to.
func (m *Machine) RingOnePrefix() netip.Prefix {
return m.zone.RingOnePrefix()
}
// RingZeroAddress returns the ring 0 address of the [Machine]
// if it can act as gateway.
func (m *Machine) RingZeroAddress() (netip.Addr, bool) {
addr, err := rings.RingZeroAddress(m.Region(), m.Zone(), m.ID)
if err != nil {
return netip.Addr{}, false
}
return addr, true
}
// RingOneAddress returns the ring 1 address of the [Machine]
func (m *Machine) RingOneAddress() netip.Addr {
addr, err := rings.RingOneAddress(m.Region(), m.Zone(), m.ID)
if err != nil {
panic(err)
}
return addr
}
+1 -1
View File
@@ -66,7 +66,7 @@ func (m *Cluster) GenCephConfig() (*ceph.Config, error) {
m.ForEachZone(func(z *Zone) bool {
for _, p := range z.GetCephMonitors() {
addr, _ := RingOneAddress(z.ID, p.ID)
addr := p.RingOneAddress()
cfg.Global.Monitors = append(cfg.Global.Monitors, p.Name)
cfg.Global.MonitorsAddr = append(cfg.Global.MonitorsAddr, addr)
+3 -6
View File
@@ -4,6 +4,7 @@ import (
"os"
"darvaza.org/slog"
"git.jpi.io/amery/jpictl/pkg/ceph"
)
@@ -14,8 +15,7 @@ type cephScanTODO struct {
func (todo *cephScanTODO) checkMachine(p *Machine) bool {
// on ceph all addresses are ring1
ring1, _ := RingOneAddress(p.Zone(), p.ID)
addr := ring1.String()
addr := p.RingOneAddress().String()
if _, found := todo.names[p.Name]; found {
// found on the TODO by name
@@ -73,10 +73,7 @@ func newCephScanTODO(cfg *ceph.Config) *cephScanTODO {
func (m *Cluster) scanCephMonitors(opts *ScanOptions) error {
cfg, err := m.GetCephConfig()
switch {
case os.IsNotExist(err):
err = nil
case err != nil:
if err != nil && !os.IsNotExist(err) {
return err
}
+87 -40
View File
@@ -4,9 +4,10 @@ import (
"bytes"
"fmt"
"io"
"sort"
"strings"
"darvaza.org/core"
"git.jpi.io/amery/jpictl/pkg/rings"
)
@@ -36,20 +37,24 @@ func (m *Cluster) Env(export bool) (*Env, error) {
return env, nil
}
// Zones returns the list of Zone IDs
func (m *Env) Zones() []rings.ZoneID {
// Zones returns the list of Zone IDs of a region,
// or from all if none is specified.
func (m *Env) Zones(r *Region) []rings.ZoneID {
var zones []rings.ZoneID
m.ForEachZone(func(z *Zone) bool {
iter := core.IIf[ZoneIterator](r != nil, r, m)
iter.ForEachZone(func(z *Zone) bool {
zones = append(zones, z.ID)
return false
})
core.SliceSortOrdered(zones)
return zones
}
// Regions returns the list of primary regions
func (m *Env) Regions() []string {
// RegionsNames returns a sorted list of primary regions names
func (m *Env) RegionsNames() []string {
var regions []string
m.ForEachRegion(func(r *Region) bool {
@@ -60,7 +65,21 @@ func (m *Env) Regions() []string {
return false
})
sort.Strings(regions)
core.SliceSortOrdered(regions)
return regions
}
// Regions returns a sorted list of primary regions IDs
func (m *Env) Regions() (regions []rings.RegionID) {
m.ForEachRegion(func(r *Region) bool {
if r.IsPrimary() {
regions = append(regions, r.ID)
}
return false
})
core.SliceSortOrdered(regions)
return regions
}
@@ -72,41 +91,75 @@ func (m *Env) WriteTo(w io.Writer) (int64, error) {
m.writeEnvVar(&buf, m.cephFSID, "FSID")
}
m.writeEnvVar(&buf, genEnvStrings(m.Regions()), "REGIONS")
m.writeEnvVar(&buf, genEnvInts(m.Zones()), "ZONES")
m.ForEachZone(func(z *Zone) bool {
m.writeEnvZone(&buf, z)
return false
regions := m.getRegions()
ids := core.SliceMap(regions, func(_ []rings.RegionID, r *Region) (out []rings.RegionID) {
return append(out, r.ID)
})
names := core.SliceMap(regions, func(_ []string, r *Region) (out []string) {
return append(out, r.Name)
})
m.writeEnvVar(&buf, genEnvInts(ids), "REGIONS")
m.writeEnvVar(&buf, genEnvStrings(names), "REGIONS_NAMES")
for _, r := range regions {
m.writeEnvRegion(&buf, r)
}
return buf.WriteTo(w)
}
func (m *Env) writeEnvZone(w io.Writer, z *Zone) {
zoneID := z.ID
func (m *Env) getRegions() (out []*Region) {
m.ForEachRegion(func(r *Region) bool {
if r.IsPrimary() {
out = append(out, r)
}
return false
})
// ZONE{zoneID}
m.writeEnvVar(w, genEnvZoneNodes(z), "ZONE%v", zoneID)
core.SliceSortFn(out, func(a, b *Region) bool {
return a.ID < b.ID
})
// ZONE{zoneID}_NAME
m.writeEnvVar(w, z.Name, "ZONE%v_%s", zoneID, "NAME")
return out
}
func (m *Env) writeEnvRegion(w io.Writer, r *Region) {
regionID := r.ID
// ZONE{zoneID}_GW
// REGION{regionID}_NAME
m.writeEnvVar(w, r.Name, "REGION%v_%s", regionID, "NAME")
// REGION{regionID}_ZONES
m.writeEnvVar(w, genEnvInts(m.Zones(r)), "REGION%v_%s", regionID, "ZONES")
r.ForEachZone(func(z *Zone) bool {
m.writeEnvZone(w, r, z)
return false
})
}
func (m *Env) writeEnvZone(w io.Writer, r *Region, z *Zone) {
zonePrefix := fmt.Sprintf("REGION%v_ZONE%v", r.ID, z.ID)
monPrefix := zonePrefix + "_MON"
// REGION{regionID}_ZONE{zoneID}
m.writeEnvVar(w, genEnvZoneNodes(z), zonePrefix)
// REGION{regionID}_ZONE{zoneID}_NAME
m.writeEnvVar(w, z.Name, zonePrefix+"_NAME")
// REGION{regionID}_ZONE{zoneID}_GW
gateways, _ := z.GatewayIDs()
m.writeEnvVar(w, genEnvInts(gateways), "ZONE%v_%s", zoneID, "GW")
// ZONE{zoneID}_REGION
m.writeEnvVar(w, genEnvZoneRegion(z), "ZONE%v_%s", zoneID, "REGION")
m.writeEnvVar(w, genEnvInts(gateways), zonePrefix+"_GW")
// Ceph
monitors := z.GetCephMonitors()
// MON{zoneID}_NAME
m.writeEnvVar(w, genEnvZoneCephMonNames(monitors), "MON%v_%s", zoneID, "NAME")
// MON{zoneID}_IP
m.writeEnvVar(w, genEnvZoneCephMonIPs(monitors), "MON%v_%s", zoneID, "IP")
// MON{zoneID}_ID
m.writeEnvVar(w, genEnvZoneCephMonIDs(monitors), "MON%v_%s", zoneID, "ID")
// REGION{regionID}_MON{zone_ID}
m.writeEnvVar(w, genEnvZoneCephMonNames(monitors), monPrefix)
// REGION{regionID}_MON{zone_ID}_IP
m.writeEnvVar(w, genEnvZoneCephMonIPs(monitors), monPrefix+"_IP")
// REGION{regionID}_MON{zone_ID}_ID
m.writeEnvVar(w, genEnvZoneCephMonIDs(monitors), monPrefix+"_ID")
}
func (m *Env) writeEnvVar(w io.Writer, value string, name string, args ...any) {
@@ -131,14 +184,15 @@ func (m *Env) writeEnvVar(w io.Writer, value string, name string, args ...any) {
}
}
func genEnvInts[T ~int | ~uint](values []T) string {
func genEnvInts[T core.Signed](values []T) string {
var buf bytes.Buffer
for _, v := range values {
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
}
_, _ = buf.WriteString(fmt.Sprintf("%v", v))
_, _ = buf.WriteString(fmt.Sprintf("%v", int64(v)))
}
return buf.String()
@@ -162,13 +216,6 @@ func genEnvZoneNodes(z *Zone) string {
return ""
}
func genEnvZoneRegion(z *Zone) string {
if z != nil && z.region != nil {
return z.region.Name
}
return ""
}
func genEnvZoneCephMonNames(m Machines) string {
var buf strings.Builder
m.ForEachMachine(func(p *Machine) bool {
@@ -185,7 +232,7 @@ func genEnvZoneCephMonNames(m Machines) string {
func genEnvZoneCephMonIPs(m Machines) string {
var buf strings.Builder
m.ForEachMachine(func(p *Machine) bool {
addr, _ := RingOneAddress(p.Zone(), p.ID)
addr := p.RingOneAddress()
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
+14 -1
View File
@@ -1,6 +1,13 @@
package cluster
import "errors"
import (
"errors"
"io/fs"
"darvaza.org/core"
"git.jpi.io/amery/jpictl/pkg/rings"
)
var (
// ErrInvalidName indicates the name isn't valid
@@ -14,3 +21,9 @@ var (
// the intended purpose
ErrInvalidNode = errors.New("invalid node")
)
// ErrInvalidRing returns an error indicating the [rings.RingID]
// can't be used for the intended purpose
func ErrInvalidRing(ringID rings.RingID) error {
return core.QuietWrap(fs.ErrInvalid, "invalid ring %v", ringID-1)
}
+3 -3
View File
@@ -71,14 +71,14 @@ func (p *Machine) WriteHosts() error {
func (z *Zone) genHosts(out *hostsFile, p *Machine) {
var names []string
ip, _ := RingOneAddress(p.zone.ID, p.ID)
ip := p.RingOneAddress()
names = append(names, p.Name)
if p.CephMonitor {
names = append(names, fmt.Sprintf("%s-%s", p.zone.Name, "ceph"))
names = append(names, fmt.Sprintf("%s-%s", p.zone.Name, "k3s"))
if z.ID == p.zone.ID {
if z.Is(p.Region(), p.Zone()) {
names = append(names, "ceph")
names = append(names, "k3s")
}
@@ -94,7 +94,7 @@ func (z *Zone) genHosts(out *hostsFile, p *Machine) {
if p.IsGateway() {
var s string
ip, _ = RingZeroAddress(p.zone.ID, p.ID)
ip, _ = p.RingZeroAddress()
s = fmt.Sprintf("%s-%v", p.Name, 0)
entry = hostsEntry{
+8 -3
View File
@@ -53,13 +53,13 @@ func (m *Machine) IsActive() bool {
// IsGateway tells if the Machine is a ring0 gateway
func (m *Machine) IsGateway() bool {
_, ok := m.getRingInfo(0)
_, ok := m.getRingInfo(rings.RingZeroID)
return ok
}
// SetGateway enables/disables a Machine ring0 integration
func (m *Machine) SetGateway(enabled bool) error {
ri, found := m.getRingInfo(0)
ri, found := m.getRingInfo(rings.RingZeroID)
switch {
case !found && !enabled:
return nil
@@ -72,7 +72,7 @@ func (m *Machine) SetGateway(enabled bool) error {
}
ri.Enabled = enabled
return m.SyncWireguardConfig(0)
return m.SyncWireguardConfig(rings.RingZeroID)
}
// Zone indicates the [Zone] this machine belongs to
@@ -80,6 +80,11 @@ func (m *Machine) Zone() rings.ZoneID {
return m.zone.ID
}
// Region indicates the [Region] this machine belongs to
func (m *Machine) Region() rings.RegionID {
return m.zone.RegionID()
}
func (m *Machine) getPeerByName(name string) (*Machine, bool) {
return m.zone.zones.GetMachineByName(name)
}
+81 -42
View File
@@ -13,14 +13,21 @@ import (
)
// GetWireguardKeys reads a wgN.key/wgN.pub files
func (m *Machine) GetWireguardKeys(ring int) (wireguard.KeyPair, error) {
func (m *Machine) GetWireguardKeys(ringID rings.RingID) (wireguard.KeyPair, error) {
var (
data []byte
err error
out wireguard.KeyPair
)
data, err = m.ReadFile("wg%v.key", ring)
ring, err := AsWireguardInterfaceID(ringID)
if err != nil {
// invalid ring
return out, err
}
keyFile, pubFile, _ := ring.Files()
data, err = m.ReadFile(keyFile)
if err != nil {
// failed to read
return out, err
@@ -29,11 +36,11 @@ func (m *Machine) GetWireguardKeys(ring int) (wireguard.KeyPair, error) {
out.PrivateKey, err = wireguard.PrivateKeyFromBase64(string(data))
if err != nil {
// bad key
err = core.Wrap(err, "wg%v.key", ring)
err = core.Wrap(err, keyFile)
return out, err
}
data, err = m.ReadFile("wg%v.pub", ring)
data, err = m.ReadFile(pubFile)
switch {
case os.IsNotExist(err):
// no wgN.pub is fine
@@ -45,7 +52,7 @@ func (m *Machine) GetWireguardKeys(ring int) (wireguard.KeyPair, error) {
out.PublicKey, err = wireguard.PublicKeyFromBase64(string(data))
if err != nil {
// bad key
err = core.Wrap(err, "wg%v.pub", ring)
err = core.Wrap(err, pubFile)
return out, err
}
}
@@ -54,8 +61,8 @@ func (m *Machine) GetWireguardKeys(ring int) (wireguard.KeyPair, error) {
return out, err
}
func (m *Machine) tryReadWireguardKeys(ring int) error {
kp, err := m.GetWireguardKeys(ring)
func (m *Machine) tryReadWireguardKeys(ringID rings.RingID) error {
kp, err := m.GetWireguardKeys(ringID)
switch {
case os.IsNotExist(err):
// ignore
@@ -66,20 +73,25 @@ func (m *Machine) tryReadWireguardKeys(ring int) error {
default:
// import keys
ri := &RingInfo{
Ring: ring,
Ring: MustWireguardInterfaceID(ringID),
Keys: kp,
}
return m.applyRingInfo(ring, ri)
return m.applyRingInfo(ringID, ri)
}
}
// RemoveWireguardKeys deletes wgN.key and wgN.pub from
// the machine's config directory
func (m *Machine) RemoveWireguardKeys(ring int) error {
var err error
func (m *Machine) RemoveWireguardKeys(ringID rings.RingID) error {
ring, err := AsWireguardInterfaceID(ringID)
if err != nil {
return err
}
err = m.RemoveFile("wg%v.pub", ring)
keyFile, pubFile, _ := ring.Files()
err = m.RemoveFile(pubFile)
switch {
case os.IsNotExist(err):
// ignore
@@ -87,7 +99,7 @@ func (m *Machine) RemoveWireguardKeys(ring int) error {
return err
}
err = m.RemoveFile("wg%v.key", ring)
err = m.RemoveFile(keyFile)
if os.IsNotExist(err) {
// ignore
err = nil
@@ -97,8 +109,13 @@ func (m *Machine) RemoveWireguardKeys(ring int) error {
}
// GetWireguardConfig reads a wgN.conf file
func (m *Machine) GetWireguardConfig(ring int) (*wireguard.Config, error) {
data, err := m.ReadFile("wg%v.conf", ring)
func (m *Machine) GetWireguardConfig(ringID rings.RingID) (*wireguard.Config, error) {
ring, err := AsWireguardInterfaceID(ringID)
if err != nil {
return nil, err
}
data, err := m.ReadFile(ring.ConfFile())
if err != nil {
return nil, err
}
@@ -107,7 +124,7 @@ func (m *Machine) GetWireguardConfig(ring int) (*wireguard.Config, error) {
return wireguard.NewConfigFromReader(r)
}
func (m *Machine) tryApplyWireguardConfig(ring int) error {
func (m *Machine) tryApplyWireguardConfig(ring rings.RingID) error {
wg, err := m.GetWireguardConfig(ring)
switch {
case os.IsNotExist(err):
@@ -119,15 +136,15 @@ func (m *Machine) tryApplyWireguardConfig(ring int) error {
}
}
func (m *Machine) applyWireguardConfigNode(ring int, wg *wireguard.Config) error {
func (m *Machine) applyWireguardConfigNode(ring rings.RingID, wg *wireguard.Config) error {
addr := wg.GetAddress()
if !core.IsZero(addr) {
zoneID, nodeID, ok := Rings[ring].Decode(addr)
regionID, zoneID, nodeID, ok := Rings[ring].Decode(addr)
if !ok {
return fmt.Errorf("%s: invalid address", addr)
}
if err := m.applyZoneNodeID(zoneID, nodeID); err != nil {
if err := m.applyZoneNodeID(regionID, zoneID, nodeID); err != nil {
return core.Wrap(err, "%s: invalid address", addr)
}
}
@@ -139,7 +156,7 @@ func (m *Machine) applyWireguardConfigNode(ring int, wg *wireguard.Config) error
return nil
}
func (m *Machine) applyWireguardConfig(ring int, wg *wireguard.Config) error {
func (m *Machine) applyWireguardConfig(ring rings.RingID, wg *wireguard.Config) error {
if err := m.applyWireguardConfigNode(ring, wg); err != nil {
return err
}
@@ -153,7 +170,7 @@ func (m *Machine) applyWireguardConfig(ring int, wg *wireguard.Config) error {
WithField("subsystem", "wireguard").
WithField("node", m.Name).
WithField("peer", peer.Endpoint.Host).
WithField("ring", ring).
WithField("ring", MustWireguardInterfaceID(ring)).
Print("ignoring unknown endpoint")
case err != nil:
return core.Wrap(err, "peer")
@@ -163,9 +180,9 @@ func (m *Machine) applyWireguardConfig(ring int, wg *wireguard.Config) error {
return nil
}
func (m *Machine) getRingInfo(ring int) (*RingInfo, bool) {
func (m *Machine) getRingInfo(ring rings.RingID) (*RingInfo, bool) {
for _, ri := range m.Rings {
if ri.Ring == ring {
if ri.RingID() == ring {
return ri, ri.Enabled
}
}
@@ -173,13 +190,13 @@ func (m *Machine) getRingInfo(ring int) (*RingInfo, bool) {
return nil, false
}
func (m *Machine) applyRingInfo(ring int, new *RingInfo) error {
func (m *Machine) applyRingInfo(ring rings.RingID, new *RingInfo) error {
cur, _ := m.getRingInfo(ring)
if cur == nil {
// first, append
m.debug().
WithField("node", m.Name).
WithField("ring", ring).
WithField("ring", MustWireguardInterfaceID(ring)).
Print("found")
m.Rings = append(m.Rings, new)
return nil
@@ -189,9 +206,11 @@ func (m *Machine) applyRingInfo(ring int, new *RingInfo) error {
return cur.Merge(new)
}
func (m *Machine) applyWireguardInterfaceConfig(ring int, data wireguard.InterfaceConfig) error {
func (m *Machine) applyWireguardInterfaceConfig(ring rings.RingID,
data wireguard.InterfaceConfig) error {
//
ri := &RingInfo{
Ring: ring,
Ring: MustWireguardInterfaceID(ring),
Enabled: true,
Keys: wireguard.KeyPair{
PrivateKey: data.PrivateKey,
@@ -201,7 +220,9 @@ func (m *Machine) applyWireguardInterfaceConfig(ring int, data wireguard.Interfa
return m.applyRingInfo(ring, ri)
}
func (m *Machine) applyWireguardPeerConfig(ring int, pc wireguard.PeerConfig) error {
func (m *Machine) applyWireguardPeerConfig(ring rings.RingID,
pc wireguard.PeerConfig) error {
//
peer, found := m.getPeerByName(pc.Endpoint.Name())
switch {
case !found:
@@ -213,7 +234,7 @@ func (m *Machine) applyWireguardPeerConfig(ring int, pc wireguard.PeerConfig) er
default:
// apply RingInfo
ri := &RingInfo{
Ring: ring,
Ring: MustWireguardInterfaceID(ring),
Enabled: true,
Keys: wireguard.KeyPair{
PublicKey: pc.PublicKey,
@@ -224,21 +245,29 @@ func (m *Machine) applyWireguardPeerConfig(ring int, pc wireguard.PeerConfig) er
}
}
func (m *Machine) applyZoneNodeID(zoneID rings.ZoneID, nodeID rings.NodeID) error {
func (m *Machine) applyZoneNodeID(regionID rings.RegionID,
zoneID rings.ZoneID, nodeID rings.NodeID) error {
//
switch {
case zoneID == 0:
case !regionID.Valid():
return fmt.Errorf("invalid %s", "regionID")
case !zoneID.Valid():
return fmt.Errorf("invalid %s", "zoneID")
case nodeID == 0:
case !nodeID.Valid():
return fmt.Errorf("invalid %s", "nodeID")
case m.ID != nodeID:
return fmt.Errorf("invalid %s: %v ≠ %v", "zoneID", m.ID, nodeID)
return fmt.Errorf("invalid %s: %v ≠ %v", "nodeID", m.ID, nodeID)
case m.zone.ID != 0 && m.zone.ID != zoneID:
return fmt.Errorf("invalid %s: %v ≠ %v", "zoneID", m.zone.ID, zoneID)
case m.zone.ID == 0:
m.zone.ID = zoneID
}
case m.Region() != regionID:
return fmt.Errorf("invalid %s: %v ≠ %v", "regionID", m.Region(), regionID)
default:
if m.zone.ID == 0 {
m.zone.ID = zoneID
}
return nil
return nil
}
}
func (m *Machine) setRingDefaults(ri *RingInfo) error {
@@ -260,8 +289,13 @@ func (m *Machine) setRingDefaults(ri *RingInfo) error {
// RemoveWireguardConfig deletes wgN.conf from the machine's
// config directory.
func (m *Machine) RemoveWireguardConfig(ring int) error {
err := m.RemoveFile("wg%v.conf", ring)
func (m *Machine) RemoveWireguardConfig(ringID rings.RingID) error {
ring, err := AsWireguardInterfaceID(ringID)
if err != nil {
return err
}
err = m.RemoveFile(ring.ConfFile())
if os.IsNotExist(err) {
err = nil
}
@@ -269,7 +303,12 @@ func (m *Machine) RemoveWireguardConfig(ring int) error {
return err
}
func (m *Machine) createRingInfo(ring int, enabled bool) (*RingInfo, error) {
func (m *Machine) createRingInfo(ringID rings.RingID, enabled bool) (*RingInfo, error) {
ring, err := AsWireguardInterfaceID(ringID)
if err != nil {
return nil, err
}
keys, err := wireguard.NewKeyPair()
if err != nil {
return nil, err
@@ -281,7 +320,7 @@ func (m *Machine) createRingInfo(ring int, enabled bool) (*RingInfo, error) {
Keys: keys,
}
err = m.applyRingInfo(ring, ri)
err = m.applyRingInfo(ringID, ri)
if err != nil {
return nil, err
}
+6 -5
View File
@@ -9,6 +9,7 @@ import (
"time"
"darvaza.org/core"
"git.jpi.io/amery/jpictl/pkg/rings"
)
@@ -38,8 +39,8 @@ func (m *Machine) init() error {
return core.Wrap(err, m.Name)
}
for i := 0; i < RingsCount; i++ {
if err := m.tryReadWireguardKeys(i); err != nil {
for _, ring := range Rings {
if err := m.tryReadWireguardKeys(ring.ID); err != nil {
return core.Wrap(err, m.Name)
}
}
@@ -72,12 +73,12 @@ func (m *Machine) setID() error {
// scan is called once we know about all zones and machine names
func (m *Machine) scan(_ *ScanOptions) error {
for i := 0; i < RingsCount; i++ {
if err := m.tryApplyWireguardConfig(i); err != nil {
for _, ring := range Rings {
if err := m.tryApplyWireguardConfig(ring.ID); err != nil {
m.error(err).
WithField("subsystem", "wireguard").
WithField("node", m.Name).
WithField("ring", i).
WithField("ring", MustWireguardInterfaceID(ring.ID)).
Print()
return err
}
+95 -142
View File
@@ -4,28 +4,84 @@ import (
"fmt"
"io/fs"
"net/netip"
"strconv"
"git.jpi.io/amery/jpictl/pkg/rings"
"git.jpi.io/amery/jpictl/pkg/wireguard"
)
const (
// RingsCount indicates how many wireguard rings we have
RingsCount = 2
// RingZeroPort is the port wireguard uses for ring0
RingZeroPort = 51800
// RingOnePort is the port wireguard uses for ring1
RingOnePort = 51810
)
// WireguardInterfaceID represents the number in the `wg%v`
// interface name.
type WireguardInterfaceID uint
// AsWireguardInterfaceID returns the [WireguardInterfaceID] for
// a valid [rings.RingID].
func AsWireguardInterfaceID(ring rings.RingID) (WireguardInterfaceID, error) {
switch ring {
case rings.RingZeroID:
return 0, nil
default:
return 0, ErrInvalidRing(ring)
}
}
// MustWireguardInterfaceID returns the [WireguardInterfaceID] for
// a valid [rings.RingID], and panics if it's not.
func MustWireguardInterfaceID(ring rings.RingID) WireguardInterfaceID {
id, err := AsWireguardInterfaceID(ring)
if err != nil {
panic(err)
}
return id
}
// RingID tells the [rings.RingID] of the [WireguardInterfaceID].
func (wi WireguardInterfaceID) RingID() rings.RingID {
return rings.RingID(wi + 1)
}
// PubFile returns "wgN.pub"
func (wi WireguardInterfaceID) PubFile() string {
return fmt.Sprintf("wg%v.pub", wi)
}
// KeyFile returns "wgN.key"
func (wi WireguardInterfaceID) KeyFile() string {
return fmt.Sprintf("wg%v.key", wi)
}
// ConfFile returns "wgN.conf"
func (wi WireguardInterfaceID) ConfFile() string {
return fmt.Sprintf("wg%v.conf", wi)
}
// Files returns all wgN.ext file names.
func (wi WireguardInterfaceID) Files() (keyFile, pubFile, confFile string) {
prefix := "wg" + strconv.Itoa(int(wi))
return prefix + ".key", prefix + ".pub", prefix + ".conf"
}
// RingInfo contains represents the Wireguard endpoint details
// for a Machine on a particular ring
type RingInfo struct {
Ring int
Ring WireguardInterfaceID
Enabled bool
Keys wireguard.KeyPair
}
// RingID returns the [rings.RingID] for this [RingInfo].
func (ri *RingInfo) RingID() rings.RingID {
return rings.RingID(ri.Ring + 1)
}
// Merge attempts to combine two RingInfo structs
func (ri *RingInfo) Merge(alter *RingInfo) error {
switch {
@@ -51,7 +107,7 @@ func (ri *RingInfo) unsafeMerge(alter *RingInfo) error {
ri.Enabled = true
}
// fill the gaps on our keypair
// fill the gaps on our key pair
if ri.Keys.PrivateKey.IsZero() {
ri.Keys.PrivateKey = alter.Keys.PrivateKey
}
@@ -76,100 +132,26 @@ func canMergeKeyPairs(p1, p2 wireguard.KeyPair) bool {
// RingAddressEncoder provides encoder/decoder access for a particular
// Wireguard ring
type RingAddressEncoder struct {
ID int
ID rings.RingID
Port uint16
Encode func(zoneID rings.ZoneID, nodeID rings.NodeID) (netip.Addr, bool)
Decode func(addr netip.Addr) (zoneID rings.ZoneID, nodeID rings.NodeID, ok bool)
Encode func(rings.RegionID, rings.ZoneID, rings.NodeID) (netip.Addr, error)
Decode func(addr netip.Addr) (rings.RegionID, rings.ZoneID, rings.NodeID, bool)
}
var (
// RingZero is a wg0 address encoder/decoder
RingZero = RingAddressEncoder{
ID: 0,
ID: rings.RingZeroID,
Port: RingZeroPort,
Decode: ParseRingZeroAddress,
Encode: RingZeroAddress,
}
// RingOne is a wg1 address encoder/decoder
RingOne = RingAddressEncoder{
ID: 1,
Port: RingOnePort,
Decode: ParseRingOneAddress,
Encode: RingOneAddress,
Decode: rings.DecodeRingZeroAddress,
Encode: rings.RingZeroAddress,
}
// Rings provides indexed access to the ring address encoders
Rings = [RingsCount]RingAddressEncoder{
Rings = []RingAddressEncoder{
RingZero,
RingOne,
}
)
// ValidZoneID checks if the given zoneID is a valid 4 bit zone number.
//
// 0 is reserved, and only allowed when composing CIDRs.
func ValidZoneID(zoneID rings.ZoneID) bool {
return zoneID == 0 || zoneID.Valid()
}
// ValidNodeID checks if the given nodeID is a valid 8 bit number.
// nodeID is unique within a Zone.
// 0 is reserved, and only allowed when composing CIDRs.
func ValidNodeID(nodeID rings.NodeID) bool {
return nodeID == 0 || nodeID.Valid()
}
// ParseRingZeroAddress extracts zone and node ID from a wg0 [netip.Addr]
// wg0 addresses are of the form `10.0.{{zoneID}}.{{nodeID}}`
func ParseRingZeroAddress(addr netip.Addr) (zoneID rings.ZoneID, nodeID rings.NodeID, ok bool) {
if addr.IsValid() {
a4 := addr.As4()
if a4[0] == 10 && a4[1] == 0 {
zoneID = rings.ZoneID(a4[2])
nodeID = rings.NodeID(a4[3])
return zoneID, nodeID, true
}
}
return 0, 0, false
}
// RingZeroAddress returns a wg0 IP address
func RingZeroAddress(zoneID rings.ZoneID, nodeID rings.NodeID) (netip.Addr, bool) {
switch {
case !ValidZoneID(zoneID) || !ValidNodeID(nodeID):
return netip.Addr{}, false
default:
a4 := [4]uint8{10, 0, uint8(zoneID), uint8(nodeID)}
return netip.AddrFrom4(a4), true
}
}
// ParseRingOneAddress extracts zone and node ID from a wg1 [netip.Addr]
// wg1 addresses are of the form `10.{{zoneID << 4}}.{{nodeID}}`
func ParseRingOneAddress(addr netip.Addr) (zoneID rings.ZoneID, nodeID rings.NodeID, ok bool) {
if addr.IsValid() {
a4 := addr.As4()
if a4[0] == 10 && a4[2] == 0 {
zoneID = rings.ZoneID(a4[1] >> 4)
nodeID = rings.NodeID(a4[3])
return zoneID, nodeID, true
}
}
return 0, 0, false
}
// RingOneAddress returns a wg1 IP address
func RingOneAddress(zoneID rings.ZoneID, nodeID rings.NodeID) (netip.Addr, bool) {
switch {
case !ValidZoneID(zoneID) || !ValidNodeID(nodeID):
return netip.Addr{}, false
default:
a4 := [4]uint8{10, uint8(zoneID << 4), 0, uint8(nodeID)}
return netip.AddrFrom4(a4), true
}
}
var (
_ MachineIterator = (*Ring)(nil)
_ ZoneIterator = (*Ring)(nil)
@@ -192,14 +174,15 @@ func (r *Ring) AddPeer(p *Machine) bool {
nodeID := p.ID
zoneID := p.Zone()
addr, _ := r.Encode(zoneID, nodeID)
regionID := p.Region()
addr, _ := r.Encode(regionID, zoneID, nodeID)
rp := &RingPeer{
Node: p,
Address: addr,
PrivateKey: ri.Keys.PrivateKey,
PeerConfig: wireguard.PeerConfig{
Name: fmt.Sprintf("%s-%v", p.Name, r.ID),
Name: fmt.Sprintf("%s-%v", p.Name, ri.Ring),
PublicKey: ri.Keys.PublicKey,
Endpoint: wireguard.EndpointAddress{
Host: p.FullName(),
@@ -208,61 +191,17 @@ func (r *Ring) AddPeer(p *Machine) bool {
},
}
switch {
case r.ID == 0:
r.setRingZeroAllowedIPs(rp)
case p.IsGateway():
r.setRingOneGatewayAllowedIPs(rp)
default:
r.setRingOneNodeAllowedIPs(rp)
}
r.setRingZeroAllowedIPs(rp)
r.Peers = append(r.Peers, rp)
return true
}
func (r *Ring) setRingZeroAllowedIPs(rp *RingPeer) {
zoneID, _, _ := r.Decode(rp.Address)
// everyone on ring0 is a gateway to ring1
addr, _ := RingOneAddress(zoneID, 0)
rp.AllowCIDR(addr, 12)
// peer
rp.AllowCIDR(rp.Address, 32)
}
func (r *Ring) setRingOneGatewayAllowedIPs(rp *RingPeer) {
zoneID, _, _ := r.Decode(rp.Address)
// peer
func (*Ring) setRingZeroAllowedIPs(rp *RingPeer) {
// ring0 peer
rp.AllowCIDR(rp.Address, 32)
// ring1 gateways connect to all other ring1 networks
r.ForEachZone(func(z *Zone) bool {
if z.ID != zoneID {
addr, _ := r.Encode(z.ID, 0)
rp.AllowCIDR(addr, 12)
}
return false
})
// ring1 gateways also connect to all ring0 addresses
r.ForEachZone(func(z *Zone) bool {
z.ForEachMachine(func(p *Machine) bool {
if p.IsGateway() {
addr, _ := RingZeroAddress(z.ID, p.ID)
rp.AllowCIDR(addr, 32)
}
return false
})
return false
})
}
func (*Ring) setRingOneNodeAllowedIPs(rp *RingPeer) {
// only to the peer itself
rp.AllowCIDR(rp.Address, 32)
// everyone on ring0 has a leg on ring1
rp.AllowCIDR(rp.Node.RingOneAddress(), 32)
}
// ForEachMachine calls a function for each Machine in the ring
@@ -318,15 +257,29 @@ type RingPeer struct {
// AllowCIDR allows an IP range via this peer
func (rp *RingPeer) AllowCIDR(addr netip.Addr, bits int) {
cidr := netip.PrefixFrom(addr, bits)
rp.PeerConfig.AllowedIPs = append(rp.PeerConfig.AllowedIPs, cidr)
rp.AllowSubnet(netip.PrefixFrom(addr, bits))
}
// AllowSubnet allows an IP range via this peer
func (rp *RingPeer) AllowSubnet(subnet netip.Prefix) {
rp.PeerConfig.AllowedIPs = append(rp.PeerConfig.AllowedIPs, subnet)
}
// NewRing composes a new Ring for Wireguard setup
func NewRing(z ZoneIterator, m MachineIterator, ring int) (*Ring, error) {
r := &Ring{
RingAddressEncoder: Rings[ring],
ZoneIterator: z,
func NewRing(z ZoneIterator, m MachineIterator, ringID rings.RingID) (*Ring, error) {
var r *Ring
for _, ring := range Rings {
if ringID == ring.ID {
r = &Ring{
RingAddressEncoder: ring,
ZoneIterator: z,
}
break
}
}
if r == nil {
return nil, ErrInvalidRing(ringID)
}
m.ForEachMachine(func(p *Machine) bool {
+3 -3
View File
@@ -35,13 +35,13 @@ func (m *Cluster) SyncMkdirAll() error {
func (m *Cluster) SyncAllWireguard() error {
var err error
for ring := 0; ring < RingsCount; ring++ {
err = m.WriteWireguardKeys(ring)
for _, ring := range Rings {
err = m.WriteWireguardKeys(ring.ID)
if err != nil {
return err
}
err = m.SyncWireguardConfig(ring)
err = m.SyncWireguardConfig(ring.ID)
if err != nil {
return err
}
+40 -50
View File
@@ -3,6 +3,8 @@ package cluster
import (
"io/fs"
"os"
"git.jpi.io/amery/jpictl/pkg/rings"
)
var (
@@ -26,22 +28,22 @@ var (
// A WireguardConfigPruner deletes wgN.conf on all machines under
// its scope with the specified ring disabled
type WireguardConfigPruner interface {
PruneWireguardConfig(ring int) error
PruneWireguardConfig(ring rings.RingID) error
}
// PruneWireguardConfig removes wgN.conf files of machines with
// the corresponding ring disabled on all zones
func (m *Cluster) PruneWireguardConfig(ring int) error {
func (m *Cluster) PruneWireguardConfig(ring rings.RingID) error {
return pruneWireguardConfig(m, ring)
}
// PruneWireguardConfig removes wgN.conf files of machines with
// the corresponding ring disabled.
func (z *Zone) PruneWireguardConfig(ring int) error {
func (z *Zone) PruneWireguardConfig(ring rings.RingID) error {
return pruneWireguardConfig(z, ring)
}
func pruneWireguardConfig(m MachineIterator, ring int) error {
func pruneWireguardConfig(m MachineIterator, ring rings.RingID) error {
var err error
m.ForEachMachine(func(p *Machine) bool {
@@ -59,7 +61,7 @@ func pruneWireguardConfig(m MachineIterator, ring int) error {
// PruneWireguardConfig deletes the wgN.conf file if its
// presence on the ring is disabled
func (m *Machine) PruneWireguardConfig(ring int) error {
func (m *Machine) PruneWireguardConfig(ring rings.RingID) error {
_, ok := m.getRingInfo(ring)
if !ok {
return m.RemoveWireguardConfig(ring)
@@ -71,41 +73,32 @@ func (m *Machine) PruneWireguardConfig(ring int) error {
// A WireguardConfigWriter rewrites all wgN.conf on all machines under
// its scope attached to that ring
type WireguardConfigWriter interface {
WriteWireguardConfig(ring int) error
WriteWireguardConfig(ring rings.RingID) error
}
// WriteWireguardConfig rewrites all wgN.conf on all machines
// attached to that ring
func (m *Cluster) WriteWireguardConfig(ring int) error {
func (m *Cluster) WriteWireguardConfig(ring rings.RingID) error {
switch ring {
case 0:
case rings.RingZeroID:
return writeWireguardConfig(m, m, ring)
case 1:
var err error
m.ForEachZone(func(z *Zone) bool {
err = writeWireguardConfig(m, z, ring)
return err != nil
})
return err
default:
return fs.ErrInvalid
return ErrInvalidRing(ring)
}
}
// WriteWireguardConfig rewrites all wgN.conf on all machines
// on the Zone attached to that ring
func (z *Zone) WriteWireguardConfig(ring int) error {
func (z *Zone) WriteWireguardConfig(ring rings.RingID) error {
switch ring {
case 0:
case rings.RingZeroID:
return writeWireguardConfig(z.zones, z.zones, ring)
case 1:
return writeWireguardConfig(z.zones, z, ring)
default:
return fs.ErrInvalid
return ErrInvalidRing(ring)
}
}
func writeWireguardConfig(z ZoneIterator, m MachineIterator, ring int) error {
func writeWireguardConfig(z ZoneIterator, m MachineIterator, ring rings.RingID) error {
r, err := NewRing(z, m, ring)
if err != nil {
return err
@@ -121,7 +114,7 @@ func writeWireguardConfig(z ZoneIterator, m MachineIterator, ring int) error {
// WriteWireguardConfig rewrites the wgN.conf file of this Machine
// if enabled
func (m *Machine) WriteWireguardConfig(ring int) error {
func (m *Machine) WriteWireguardConfig(ring rings.RingID) error {
r, err := NewRing(m.zone.zones, m.zone, ring)
if err != nil {
return err
@@ -131,12 +124,17 @@ func (m *Machine) WriteWireguardConfig(ring int) error {
}
func (m *Machine) writeWireguardRingConfig(r *Ring) error {
ring, err := AsWireguardInterfaceID(r.ID)
if err != nil {
return err
}
wg, err := r.ExportConfig(m)
if err != nil {
return nil
}
f, err := m.CreateTruncFile("wg%v.conf", r.ID)
f, err := m.CreateTruncFile(ring.ConfFile())
if err != nil {
return err
}
@@ -149,41 +147,32 @@ func (m *Machine) writeWireguardRingConfig(r *Ring) error {
// A WireguardConfigSyncer updates all wgN.conf on all machines under
// its scope reflecting the state of the ring
type WireguardConfigSyncer interface {
SyncWireguardConfig(ring int) error
SyncWireguardConfig(ring rings.RingID) error
}
// SyncWireguardConfig updates all wgN.conf files for the specified
// ring
func (m *Cluster) SyncWireguardConfig(ring int) error {
func (m *Cluster) SyncWireguardConfig(ring rings.RingID) error {
switch ring {
case 0:
case rings.RingZeroID:
return syncWireguardConfig(m, m, ring)
case 1:
var err error
m.ForEachZone(func(z *Zone) bool {
err = syncWireguardConfig(m, z, ring)
return err != nil
})
return err
default:
return fs.ErrInvalid
return ErrInvalidRing(ring)
}
}
// SyncWireguardConfig updates all wgN.conf files for the specified
// ring
func (z *Zone) SyncWireguardConfig(ring int) error {
func (z *Zone) SyncWireguardConfig(ring rings.RingID) error {
switch ring {
case 0:
case rings.RingZeroID:
return syncWireguardConfig(z.zones, z.zones, ring)
case 1:
return syncWireguardConfig(z.zones, z, ring)
default:
return fs.ErrInvalid
return ErrInvalidRing(ring)
}
}
func syncWireguardConfig(z ZoneIterator, m MachineIterator, ring int) error {
func syncWireguardConfig(z ZoneIterator, m MachineIterator, ring rings.RingID) error {
r, err := NewRing(z, m, ring)
if err != nil {
return err
@@ -203,27 +192,27 @@ func syncWireguardConfig(z ZoneIterator, m MachineIterator, ring int) error {
// SyncWireguardConfig updates all wgN.conf files for the specified
// ring
func (m *Machine) SyncWireguardConfig(ring int) error {
func (m *Machine) SyncWireguardConfig(ring rings.RingID) error {
return m.zone.SyncWireguardConfig(ring)
}
// A WireguardKeysWriter writes the Wireguard Keys for all machines
// under its scope for the specified ring
type WireguardKeysWriter interface {
WriteWireguardKeys(ring int) error
WriteWireguardKeys(ring rings.RingID) error
}
// WriteWireguardKeys rewrites all wgN.{key,pub} files
func (m *Cluster) WriteWireguardKeys(ring int) error {
func (m *Cluster) WriteWireguardKeys(ring rings.RingID) error {
return writeWireguardKeys(m, ring)
}
// WriteWireguardKeys rewrites all wgN.{key,pub} files on this zone
func (z *Zone) WriteWireguardKeys(ring int) error {
func (z *Zone) WriteWireguardKeys(ring rings.RingID) error {
return writeWireguardKeys(z, ring)
}
func writeWireguardKeys(m MachineIterator, ring int) error {
func writeWireguardKeys(m MachineIterator, ring rings.RingID) error {
var err error
m.ForEachMachine(func(p *Machine) bool {
@@ -240,12 +229,12 @@ func writeWireguardKeys(m MachineIterator, ring int) error {
}
// WriteWireguardKeys writes the wgN.key/wgN.pub files
func (m *Machine) WriteWireguardKeys(ring int) error {
func (m *Machine) WriteWireguardKeys(ringID rings.RingID) error {
var err error
var key, pub string
var ri *RingInfo
ri, _ = m.getRingInfo(ring)
ri, _ = m.getRingInfo(ringID)
if ri != nil {
key = ri.Keys.PrivateKey.String()
pub = ri.Keys.PublicKey.String()
@@ -258,12 +247,13 @@ func (m *Machine) WriteWireguardKeys(ring int) error {
pub = ri.Keys.PrivateKey.Public().String()
}
err = m.WriteStringFile(key+"\n", "wg%v.key", ring)
keyFile, pubFile, _ := ri.Ring.Files()
err = m.WriteStringFile(key+"\n", keyFile)
if err != nil {
return err
}
err = m.WriteStringFile(pub+"\n", "wg%v.pub", ring)
err = m.WriteStringFile(pub+"\n", pubFile)
if err != nil {
return err
}
+35
View File
@@ -70,3 +70,38 @@ func (z *Zone) GatewayIDs() ([]rings.NodeID, int) {
return out, len(out)
}
// RegionID returns the primary [Region] of a [Zone].
func (z *Zone) RegionID() rings.RegionID {
if z != nil && z.region != nil {
return z.region.ID
}
return 0
}
// Is checks if the given [rings.RegionID] and [rings.ZoneID] match
// the [Zone].
func (z *Zone) Is(regionID rings.RegionID, zoneID rings.ZoneID) bool {
switch {
case z.ID != zoneID:
return false
case z.RegionID() != regionID:
return false
default:
return true
}
}
// Eq checks if two [Zone]s are the same.
func (z *Zone) Eq(z2 *Zone) bool {
switch {
case z == nil, z2 == nil:
return false
case z.ID != z2.ID:
return false
case z.RegionID() != z2.RegionID():
return false
default:
return true
}
}
+19 -10
View File
@@ -14,7 +14,7 @@ func RingZeroPrefix(region RegionID, zone ZoneID) (cidr netip.Prefix, err error)
case !zone.Valid():
err = ErrOutOfRange(zone, "zone")
default:
addr := unsafeRingZeroAddress(region, zone, 0)
addr := UnsafeRingZeroAddress(region, zone, 0)
cidr = netip.PrefixFrom(addr, RingZeroBits)
}
@@ -33,7 +33,7 @@ func RingZeroAddress(region RegionID, zone ZoneID, node NodeID) (addr netip.Addr
case !node.ValidZero():
err = ErrOutOfRange(node, "node")
default:
addr = unsafeRingZeroAddress(region, zone, node)
addr = UnsafeRingZeroAddress(region, zone, node)
}
return addr, err
@@ -52,7 +52,7 @@ func RingOnePrefix(region RegionID, zone ZoneID) (cidr netip.Prefix, err error)
case !zone.Valid():
err = ErrOutOfRange(zone, "zone")
default:
addr := unsafeRingOneAddress(region, zone, 0)
addr := UnsafeRingOneAddress(region, zone, 0)
cidr = netip.PrefixFrom(addr, RingOneBits)
}
return cidr, err
@@ -71,7 +71,7 @@ func RingOneAddress(region RegionID, zone ZoneID, node NodeID) (addr netip.Addr,
case !node.Valid():
err = ErrOutOfRange(node, "node")
default:
addr = unsafeRingOneAddress(region, zone, node)
addr = UnsafeRingOneAddress(region, zone, node)
}
return addr, err
}
@@ -86,7 +86,7 @@ func RingTwoPrefix(region RegionID) (cidr netip.Prefix, err error) {
case !region.Valid():
err = ErrOutOfRange(region, "region")
default:
addr := unsafeRingTwoAddress(region, 0)
addr := UnsafeRingTwoAddress(region, 0)
cidr = netip.PrefixFrom(addr, RingTwoBits)
}
return cidr, err
@@ -101,20 +101,25 @@ func RingThreePrefix(region RegionID) (subnet netip.Prefix, err error) {
case !region.Valid():
err = ErrOutOfRange(region, "region")
default:
addr := unsafeRingThreeAddress(region, 0)
addr := UnsafeRingThreeAddress(region, 0)
subnet = netip.PrefixFrom(addr, RingThreeBits)
}
return subnet, err
}
func unsafeRingZeroAddress(region RegionID, zone ZoneID, node NodeID) netip.Addr {
// UnsafeRingZeroAddress is equivalent ot RingZeroAddress but without validating
// the input.
func UnsafeRingZeroAddress(region RegionID, zone ZoneID, node NodeID) netip.Addr {
r := uint(region)
z := uint(zone)
n := uint(node)
return AddrFrom4(10, 0, r<<4+z, n)
}
func unsafeRingOneAddress(region RegionID, zone ZoneID, node NodeID) netip.Addr {
// UnsafeRingOneAddress is equivalent ot RingOneAddress but without validating
// the input.
func UnsafeRingOneAddress(region RegionID, zone ZoneID, node NodeID) netip.Addr {
r := uint(region)
z := uint(zone)
n := uint(node)
@@ -125,7 +130,9 @@ func unsafeRingOneAddress(region RegionID, zone ZoneID, node NodeID) netip.Addr
return AddrFrom4(10, r, z<<4+n1, n0)
}
func unsafeRingTwoAddress(region RegionID, n uint) netip.Addr {
// UnsafeRingTwoAddress is equivalent ot RingTwoAddress but without validating
// the input.
func UnsafeRingTwoAddress(region RegionID, n uint) netip.Addr {
r := uint(region)
n1 := n >> 8
@@ -134,7 +141,9 @@ func unsafeRingTwoAddress(region RegionID, n uint) netip.Addr {
return AddrFrom4(10, r, n1, n0)
}
func unsafeRingThreeAddress(region RegionID, n uint) netip.Addr {
// UnsafeRingThreeAddress is equivalent ot RingThreeAddress but without validating
// the input.
func UnsafeRingThreeAddress(region RegionID, n uint) netip.Addr {
r := uint(region)
n2 := n >> 16
+72
View File
@@ -0,0 +1,72 @@
package tools
import (
"bytes"
"fmt"
"io"
)
// LazyBuffer is a [bytes.Buffer] that minimizes counting and error checks.
type LazyBuffer bytes.Buffer
// Sys returns the underlying [bytes.Buffer].
func (buf *LazyBuffer) Sys() *bytes.Buffer {
if buf == nil {
return nil
}
return (*bytes.Buffer)(buf)
}
// Len tells the size in bytes of the currently stored data.
func (buf *LazyBuffer) Len() int { return buf.Sys().Len() }
// String returns the stored data as string.
func (buf *LazyBuffer) String() string { return buf.Sys().String() }
// Bytes returns the stored data as a bytes slice.
func (buf *LazyBuffer) Bytes() []byte { return buf.Sys().Bytes() }
// Write implements the standard io.Writer interface.
func (buf *LazyBuffer) Write(b []byte) (int, error) { return buf.Sys().Write(b) }
// WriteTo implements the standard WriteTo() interface.
func (buf *LazyBuffer) WriteTo(out io.Writer) (int64, error) { return buf.Sys().WriteTo(out) }
// Print appends the [fmt.Print] equivalent to the buffer.
func (buf *LazyBuffer) Print(a ...any) error {
_, err := fmt.Fprint(buf.Sys(), a...)
return err
}
// Println appends the [fmt.Println] equivalent to the buffer.
func (buf *LazyBuffer) Println(a ...any) error {
_, err := fmt.Fprintln(buf.Sys(), a...)
return err
}
// Printf appends the [fmt.Printf] equivalent to the buffer.
func (buf *LazyBuffer) Printf(format string, a ...any) error {
_, err := fmt.Fprintf(buf.Sys(), format, a...)
return err
}
// WriteRunes appends the given runes as UTF-8 characters to the buffer.
func (buf *LazyBuffer) WriteRunes(runes ...rune) {
for _, r := range runes {
_, _ = buf.Sys().WriteRune(r)
}
}
// WriteBytes writes the given byte arrays to the buffer.
func (buf *LazyBuffer) WriteBytes(s ...[]byte) {
for _, b := range s {
_, _ = buf.Sys().Write(b)
}
}
// WriteStrings writes the given strings as UTF-8 to the buffer.
func (buf *LazyBuffer) WriteStrings(strings ...string) {
for _, s := range strings {
_, _ = buf.Sys().WriteString(s)
}
}
+1 -2
View File
@@ -5,8 +5,7 @@ set -eu
: ${GO:=go}
MODULES=$(find * -name go.mod -exec dirname '{}' \;)
GROUPS="pkg cmd"
BASE="$PWD"
GROUPS=""
mod() {
local d="${1:-.}"
+102 -40
View File
@@ -7,6 +7,12 @@ INDEX="$1"
PROJECTS="$(cut -d':' -f1 "$INDEX")"
COMMANDS="tidy get build test up"
TAB=$(printf "\t")
escape_dir() {
echo "$1" | sed -e 's|/|\\/|g' -e 's|\.|\\.|g'
}
expand() {
local prefix="$1" suffix="$2"
local x= out=
@@ -41,12 +47,6 @@ packed_oneline() {
packed | tr '\n' ';' | sed -e 's|;$||' -e 's|then;|then |g' -e 's|;[ \t]*|; |g'
}
gen_install_tools() {
cat <<EOT
for url in \$(GO_INSTALL_URLS); do \$(GO) install -v \$\$url; done
EOT
}
gen_revive_exclude() {
local self="$1"
local dirs= d=
@@ -61,36 +61,71 @@ gen_revive_exclude() {
done
}
for cmd in $COMMANDS; do
all="$(prefixed $cmd $PROJECTS)"
depsx=
gen_var_name() {
local x=
for x; do
echo "$x" | tr 'a-z-' 'A-Z_'
done
}
# generate files lists
#
gen_files_lists() {
local name= dir= mod= deps=
local files= files_cmd=
local filter= out_pat=
cat <<EOT
.PHONY: $cmd $all
$cmd: $all
GO_FILES = \$(shell find * \\
-type d -name node_modules -prune -o \\
-type f -name '*.go' -print )
EOT
while IFS=: read name dir mod deps; do
files=GO_FILES_$(gen_var_name "$name")
filter="-e '/^\.$/d;'"
[ "x$dir" = "x." ] || filter="$filter -e '/^$(escape_dir "$dir")$/d;'"
out_pat="$(cut -d: -f2 "$INDEX" | eval "sed $filter -e 's|$|/%|'" | tr '\n' ' ' | sed -e 's| \+$||')"
if [ "x$dir" = "x." ]; then
# root
files_cmd="\$(GO_FILES)"
files_cmd="\$(filter-out $out_pat, $files_cmd)"
else
files_cmd="\$(filter $dir/%, \$(GO_FILES))"
files_cmd="\$(filter-out $out_pat, $files_cmd)"
files_cmd="\$(patsubst $dir/%,%,$files_cmd)"
fi
cat <<-EOT
$files$TAB=$TAB$files_cmd
EOT
done < "$INDEX" | column -t -s "$TAB" -o " "
}
gen_make_targets() {
local cmd="$1" name="$2" dir="$3" mod="$4" deps="$5"
local call= callu= callx=
local depsx= cmdx=
local sequential=
# default calls
case "$cmd" in
tidy)
call="$(cat <<-EOT | packed
\$(GO) mod tidy
# unconditional
callu="\$(GO) mod tidy"
# go vet and revive only if there are .go files
#
$(cat <<-EOL | packed_oneline
set -e
FILES="\$\$(\$(GO) list -f '{{len .GoFiles}}' ./...)"
if [ -n "\$\$FILES" ]; then
\$(GO) vet ./...
\$(REVIVE) \$(REVIVE_RUN_ARGS) ./...
fi
EOL
)
call="$(cat <<-EOT | packed
\$(GO) vet ./...
\$(GOLANGCI_LINT) run
\$(REVIVE) \$(REVIVE_RUN_ARGS) ./...
EOT
)"
depsx="fmt \$(REVIVE)"
depsx="fmt"
;;
up)
call="\$(GO) get -u -v ./...
@@ -111,10 +146,6 @@ EOT
sequential=false ;;
esac
while IFS=: read name dir mod deps; do
deps=$(echo "$deps" | tr ',' ' ')
# cd $dir
if [ "." = "$dir" ]; then
# root
@@ -123,7 +154,6 @@ EOT
cd="cd '$dir'; "
fi
callx="$call"
if [ "$name" = root ]; then
# special case
case "$cmd" in
@@ -140,17 +170,20 @@ EOT
[ -z "$cmdx" ] || cmdx="\$(GO) $cmdx -v ./..."
if [ "up" = "$cmd" ]; then
case "$cmd" in
up)
callx="$cmdx
\$(GO) mod tidy
$(gen_install_tools)"
elif [ "get" = "$cmd" ]; then
callx="$cmdx
$(gen_install_tools)"
elif [ -n "$cmdx" ]; then
classx="$cmdx"
fi
\$(GO) mod tidy"
;;
get)
callx="$cmdx"
;;
*)
callx="$call"
;;
esac
else
callx="$call"
fi
if [ "build" = "$cmd" ]; then
@@ -181,16 +214,45 @@ $(gen_install_tools)"
deps=
fi
files=GO_FILES_$(gen_var_name "$name")
cat <<EOT
$cmd-$name:${deps:+ $(prefixed $cmd $deps)}${depsx:+ | $depsx} ; \$(info \$(M) $cmd: $name)
$(echo "$callx" | sed -e "/^$/d;" -e "s|^|\t\$(Q) $cd|")
$cmd-$name:${deps:+ $(prefixed $cmd $deps)}${depsx:+ | $depsx} ; \$(info \$(M) $cmd: $name)
EOT
if [ -n "$callu" ]; then
# unconditionally
echo "$callu" | sed -e "/^$/d;" -e "s|^|\t\$(Q) $cd|"
fi
if [ -n "$callx" ]; then
# only if there are files
echo "ifneq (\$($files),)"
echo "$callx" | sed -e "/^$/d;" -e "s|^|\t\$(Q) $cd|"
echo "endif"
fi
}
gen_files_lists
for cmd in $COMMANDS; do
all="$(prefixed $cmd $PROJECTS)"
depsx=
cat <<EOT
.PHONY: $cmd $all
$cmd: $all
EOT
while IFS=: read name dir mod deps; do
deps=$(echo "$deps" | tr ',' ' ')
gen_make_targets "$cmd" "$name" "$dir" "$mod" "$deps"
done < "$INDEX"
done
for x in $PROJECTS; do
cat <<EOT
$x: $(suffixed $x get build tidy)
EOT
done
+1 -1
View File
@@ -17,7 +17,7 @@ enableAllRules = true
[rule.cyclomatic]
arguments = [10]
[rule.line-length-limit]
arguments = [100]
arguments = [120]
severity = "warning"
[rule.comment-spacings]
severity = "warning"
+9 -5
View File
@@ -1,7 +1,11 @@
//go:build tools
// Package tools contains helpers
package tools
import (
_ "github.com/mgechev/revive"
)
import "io"
// LazyClose closes an [io.Closer] and discards the error
func LazyClose(p io.Closer) {
if p != nil {
_ = p.Close()
}
}
-2
View File
@@ -8,8 +8,6 @@ import (
"darvaza.org/core"
)
type sectionHandler func(*Config, *basic.Section) error
var sectionMap = map[string]func(*Config, *basic.Section) error{
"Interface": loadInterfaceConfSection,
"Peer": loadPeerConfSection,