Compare commits

..

15 Commits

Author SHA1 Message Date
amery 6c875ae832 cluster: introduce NodeID and ZoneID types
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-31 14:54:07 +01:00
karasz e1186975a6 Merge pull request 'rings: Prefix and Address factories' (#48) from pr-amery-rings into main
Reviewed-on: #48
2024-05-29 17:44:11 +02:00
amery 72a2468a10 rings: RingTwoPrefix()
Ring 2 is the service network shared by all kubernetes clusters.

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-28 14:36:41 +00:00
amery 6142d0f7f0 rings: RingThreePrefix()
Ring 3 corresponds to the pods of the kubernetes cluster of a region

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-28 14:09:06 +00:00
amery 0f177acf57 rings: RingZeroPrefix()/RingZeroAddress()
Ring zero corresponds to the backbone that connects all zones.

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-28 14:05:33 +00:00
amery 394a84c3ab rings: RingOnePrefix()/RingOneAddress()
Ring one designates the (virtual) local network of a zone
within a region.

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-28 14:02:02 +00:00
amery 52e1195139 rings: introduce generic ErrOutOfRange() factory
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-27 22:14:11 +00:00
amery 378bab2f96 rings: introduce RegionID, ZoneID and NodeID
and a Valid() method to check if their value is within the
valid range.

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-27 22:14:11 +00:00
amery f45a8f21f3 Merge pull request 'rings: PrefixToRange(), AddrToU32(), AddrFromU32()' (#46)
Reviewed-on: #46
2024-05-28 00:13:37 +02:00
amery 686e6f2f73 Merge in pull request #47 (chores)
build-sys: update dependencies and fix revive's installation
2024-05-25 23:39:20 +02:00
amery 199ef88a65 build-sys: update dependencies
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-25 21:36:50 +00:00
amery addf138d36 build-sys: fix revive installation
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-25 21:36:06 +00:00
amery 3e90c7a30b rings: introduce PrefixToRange()
returning the beginning and end of a subnet

Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-25 21:17:16 +00:00
amery 50436a320c rings: introduce AddrToU32() and AddrFromU32() helpers
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-25 21:17:16 +00:00
amery ac5827898b rings: introduce subpackage to deal with Ring addresses
Signed-off-by: Alejandro Mery <amery@jpi.io>
2024-05-25 21:15:36 +00:00
19 changed files with 641 additions and 104 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ TMPDIR ?= .tmp
REVIVE ?= $(GOBIN)/revive
REVIVE_CONF ?= $(TOOLSDIR)/revive.toml
REVIVE_RUN_ARGS ?= -config $(REVIVE_CONF) -formatter friendly
REVIVE_INSTALL_URL ?= github.com/mgechev/revive
REVIVE_INSTALL_URL ?= github.com/mgechev/revive@master
GO_INSTALL_URLS = \
$(REVIVE_INSTALL_URL) \
+1 -1
View File
@@ -52,7 +52,7 @@ func populateDNSManager(mgr *dns.Manager, m *cluster.Cluster) error {
m.ForEachZone(func(z *cluster.Zone) bool {
z.ForEachMachine(func(p *cluster.Machine) bool {
err = mgr.AddHost(ctx, z.Name, p.ID, p.IsActive(), p.PublicAddresses...)
err = mgr.AddHost(ctx, z.Name, int(p.ID), p.IsActive(), p.PublicAddresses...)
return err != nil
})
+1 -2
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"github.com/spf13/cobra"
@@ -128,7 +127,7 @@ func gatewayListAll(zi cluster.ZoneIterator) error {
return false
}
for _, i := range ids {
sIDs = append(sIDs, strconv.Itoa(i))
sIDs = append(sIDs, i.String())
}
b.WriteString(strings.Join(sIDs, ", "))
b.WriteString("\n")
+15 -15
View File
@@ -4,19 +4,19 @@ go 1.19
require (
asciigoat.org/ini v0.2.5
darvaza.org/core v0.12.0
darvaza.org/core v0.13.1
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
github.com/gofrs/uuid/v5 v5.0.0
github.com/gofrs/uuid/v5 v5.2.0
github.com/hack-pad/hackpadfs v0.2.1
github.com/libdns/cloudflare v0.1.0
github.com/libdns/libdns 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.20.0
golang.org/x/net v0.21.0
golang.org/x/crypto v0.23.0
golang.org/x/net v0.25.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -25,9 +25,9 @@ require (
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.3.2 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/fatih/color v1.16.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
@@ -35,18 +35,18 @@ require (
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.58 // 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.32.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.15.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // 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
)
+30 -31
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.12.0 h1:LLtYh9RZJSd0sgPTDocofCc4H5jbutSUQgPbKt+8gcI=
darvaza.org/core v0.12.0/go.mod h1:47Ydh67KnzjLNu1mzX3r2zpphbxQqEaihMsUq5GflQ4=
darvaza.org/core v0.13.1 h1:ZoAfZ3OLnw+t28qMQQxXrDIkETmT2h5gAO6F1XuBpwg=
darvaza.org/core v0.13.1/go.mod h1:47Ydh67KnzjLNu1mzX3r2zpphbxQqEaihMsUq5GflQ4=
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,8 +18,8 @@ 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.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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=
@@ -28,13 +28,13 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
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.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
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.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
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=
github.com/hack-pad/hackpadfs v0.2.1 h1:FelFhIhv26gyjujoA/yeFO+6YGlqzmc9la/6iKMIxMw=
github.com/hack-pad/hackpadfs v0.2.1/go.mod h1:khQBuCEwGXWakkmq8ZiFUvUZz84ZkJ2KNwKvChs4OrU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -43,11 +43,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/libdns/cloudflare v0.1.0 h1:93WkJaGaiXCe353LHEP36kAWCUw0YjFqwhkBkU2/iic=
github.com/libdns/cloudflare v0.1.0/go.mod h1:a44IP6J1YH6nvcNl1PverfJviADgXUnsozR3a7vBKN8=
github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054=
github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU=
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@@ -61,8 +60,8 @@ github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8c
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.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
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=
@@ -79,8 +78,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
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=
@@ -95,24 +94,24 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
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.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg=
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
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/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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/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.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
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=
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=
+2 -2
View File
@@ -45,7 +45,7 @@ func (m *Cluster) initZones(opts *ScanOptions) error {
func (m *Cluster) initZone(z *Zone, _ *ScanOptions) error {
var hasMissing bool
var lastMachineID int
var lastMachineID NodeID
z.zones = m
z.logger = m
@@ -58,7 +58,7 @@ func (m *Cluster) initZone(z *Zone, _ *ScanOptions) error {
case p.ID == 0:
hasMissing = true
case p.ID > lastMachineID:
lastMachineID = z.ID
lastMachineID = p.ID
}
return false
+1 -1
View File
@@ -114,7 +114,7 @@ func (m *Cluster) scanMachines(opts *ScanOptions) error {
func (m *Cluster) scanZoneIDs(_ *ScanOptions) error {
var hasMissing bool
var lastZoneID int
var lastZoneID ZoneID
m.ForEachZone(func(z *Zone) bool {
switch {
+23 -32
View File
@@ -35,8 +35,8 @@ func (m *Cluster) Env(export bool) (*Env, error) {
}
// Zones returns the list of Zone IDs
func (m *Env) Zones() []int {
var zones []int
func (m *Env) Zones() []ZoneID {
var zones []ZoneID
m.ForEachZone(func(z *Zone) bool {
zones = append(zones, z.ID)
@@ -70,8 +70,8 @@ func (m *Env) WriteTo(w io.Writer) (int64, error) {
m.writeEnvVar(&buf, m.cephFSID, "FSID")
}
m.writeEnvVarStrings(&buf, m.Regions(), "REGIONS")
m.writeEnvVarInts(&buf, m.Zones(), "ZONES")
m.writeEnvVar(&buf, genEnvStrings(m.Regions()), "REGIONS")
m.writeEnvVar(&buf, genEnvInts(m.Zones()), "ZONES")
m.ForEachZone(func(z *Zone) bool {
m.writeEnvZone(&buf, z)
@@ -92,7 +92,7 @@ func (m *Env) writeEnvZone(w io.Writer, z *Zone) {
// ZONE{zoneID}_GW
gateways, _ := z.GatewayIDs()
m.writeEnvVarInts(w, gateways, "ZONE%v_%s", zoneID, "GW")
m.writeEnvVar(w, genEnvInts(gateways), "ZONE%v_%s", zoneID, "GW")
// ZONE{zoneID}_REGION
m.writeEnvVar(w, genEnvZoneRegion(z), "ZONE%v_%s", zoneID, "REGION")
@@ -107,32 +107,6 @@ func (m *Env) writeEnvZone(w io.Writer, z *Zone) {
m.writeEnvVar(w, genEnvZoneCephMonIDs(monitors), "MON%v_%s", zoneID, "ID")
}
func (m *Env) writeEnvVarInts(w io.Writer, value []int, name string, args ...any) {
var buf bytes.Buffer
for _, v := range value {
if buf.Len() > 0 {
_, _ = fmt.Fprint(&buf, " ")
}
_, _ = fmt.Fprintf(&buf, "%v", v)
}
m.writeEnvVar(w, buf.String(), name, args...)
}
func (m *Env) writeEnvVarStrings(w io.Writer, value []string, name string, args ...any) {
var buf bytes.Buffer
for _, v := range value {
if buf.Len() > 0 {
_, _ = fmt.Fprint(&buf, " ")
}
_, _ = fmt.Fprintf(&buf, "%s", v)
}
m.writeEnvVar(w, buf.String(), name, args...)
}
func (m *Env) writeEnvVar(w io.Writer, value string, name string, args ...any) {
var prefix string
@@ -155,6 +129,23 @@ func (m *Env) writeEnvVar(w io.Writer, value string, name string, args ...any) {
}
}
func genEnvInts[T ~int | ~uint](values []T) string {
var buf bytes.Buffer
for _, v := range values {
if buf.Len() > 0 {
_, _ = buf.WriteRune(' ')
}
_, _ = buf.WriteString(fmt.Sprintf("%v", v))
}
return buf.String()
}
func genEnvStrings(values []string) string {
return strings.Join(values, " ")
}
func genEnvZoneNodes(z *Zone) string {
if n := z.Len(); n > 0 {
s := make([]string, 0, n)
@@ -164,7 +155,7 @@ func genEnvZoneNodes(z *Zone) string {
return false
})
return strings.Join(s, " ")
return genEnvStrings(s)
}
return ""
}
+2 -2
View File
@@ -12,7 +12,7 @@ type Machine struct {
zone *Zone
logger `json:"-" yaml:"-"`
ID int
ID NodeID
Name string `json:"-" yaml:"-"`
Inactive bool `json:"inactive,omitempty" yaml:"inactive,omitempty"`
@@ -74,7 +74,7 @@ func (m *Machine) SetGateway(enabled bool) error {
}
// Zone indicates the [Zone] this machine belongs to
func (m *Machine) Zone() int {
func (m *Machine) Zone() ZoneID {
return m.zone.ID
}
+1 -1
View File
@@ -223,7 +223,7 @@ func (m *Machine) applyWireguardPeerConfig(ring int, pc wireguard.PeerConfig) er
}
}
func (m *Machine) applyZoneNodeID(zoneID, nodeID int) error {
func (m *Machine) applyZoneNodeID(zoneID ZoneID, nodeID NodeID) error {
switch {
case zoneID == 0:
return fmt.Errorf("invalid %s", "zoneID")
+1 -1
View File
@@ -65,7 +65,7 @@ func (m *Machine) setID() error {
return err
}
m.ID = int(id)
m.ID = NodeID(id)
return nil
}
+11 -11
View File
@@ -81,8 +81,8 @@ func canMergeKeyPairs(p1, p2 wireguard.KeyPair) bool {
type RingAddressEncoder struct {
ID int
Port uint16
Encode func(zoneID, nodeID int) (netip.Addr, bool)
Decode func(addr netip.Addr) (zoneID, nodeID int, ok bool)
Encode func(zoneID ZoneID, nodeID NodeID) (netip.Addr, bool)
Decode func(addr netip.Addr) (zoneID ZoneID, nodeID NodeID, ok bool)
}
var (
@@ -110,7 +110,7 @@ var (
// 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 int) bool {
func ValidZoneID(zoneID ZoneID) bool {
switch {
case zoneID < 0 || zoneID > MaxZoneID:
return false
@@ -122,7 +122,7 @@ func ValidZoneID(zoneID int) bool {
// 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 int) bool {
func ValidNodeID(nodeID NodeID) bool {
switch {
case nodeID < 0 || nodeID > MaxNodeID:
return false
@@ -133,19 +133,19 @@ func ValidNodeID(nodeID int) bool {
// 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 int, nodeID int, ok bool) {
func ParseRingZeroAddress(addr netip.Addr) (zoneID ZoneID, nodeID NodeID, ok bool) {
if addr.IsValid() {
a4 := addr.As4()
if a4[0] == 10 && a4[1] == 0 {
return int(a4[2]), int(a4[3]), true
return ZoneID(a4[2]), NodeID(a4[3]), true
}
}
return 0, 0, false
}
// RingZeroAddress returns a wg0 IP address
func RingZeroAddress(zoneID, nodeID int) (netip.Addr, bool) {
func RingZeroAddress(zoneID ZoneID, nodeID NodeID) (netip.Addr, bool) {
switch {
case !ValidZoneID(zoneID) || !ValidNodeID(nodeID):
return netip.Addr{}, false
@@ -157,13 +157,13 @@ func RingZeroAddress(zoneID, nodeID int) (netip.Addr, bool) {
// 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 int, nodeID int, ok bool) {
func ParseRingOneAddress(addr netip.Addr) (zoneID ZoneID, nodeID NodeID, ok bool) {
if addr.IsValid() {
a4 := addr.As4()
if a4[0] == 10 && a4[2] == 0 {
zoneID = int(a4[1] >> 4)
nodeID = int(a4[3])
zoneID = ZoneID(a4[1] >> 4)
nodeID = NodeID(a4[3])
return zoneID, nodeID, true
}
}
@@ -171,7 +171,7 @@ func ParseRingOneAddress(addr netip.Addr) (zoneID int, nodeID int, ok bool) {
}
// RingOneAddress returns a wg1 IP address
func RingOneAddress(zoneID, nodeID int) (netip.Addr, bool) {
func RingOneAddress(zoneID ZoneID, nodeID NodeID) (netip.Addr, bool) {
switch {
case !ValidZoneID(zoneID) || !ValidNodeID(nodeID):
return netip.Addr{}, false
+25
View File
@@ -0,0 +1,25 @@
package cluster
import "strconv"
type (
// ZoneID is the identifier of a [Zone]
ZoneID int
// NodeID is the identifier of a [Machine]
NodeID int
)
func (z ZoneID) String() string {
return idString(int(z))
}
func (n NodeID) String() string {
return idString(int(n))
}
func idString(v int) string {
if v > 0 {
return strconv.Itoa(v)
}
return ""
}
+4 -4
View File
@@ -19,7 +19,7 @@ type Zone struct {
zones *Cluster
logger `json:"-" yaml:"-"`
ID int
ID ZoneID
Name string
Regions []string `json:",omitempty" yaml:",omitempty"`
@@ -31,7 +31,7 @@ func (z *Zone) String() string {
}
// SetGateway configures a machine to be the zone's ring0 gateway
func (z *Zone) SetGateway(gatewayID int, enabled bool) error {
func (z *Zone) SetGateway(gatewayID NodeID, enabled bool) error {
var err error
var found bool
@@ -56,8 +56,8 @@ func (z *Zone) SetGateway(gatewayID int, enabled bool) error {
}
// GatewayIDs returns the list of IDs of machines that act as ring0 gateways
func (z *Zone) GatewayIDs() ([]int, int) {
var out []int
func (z *Zone) GatewayIDs() ([]NodeID, int) {
var out []NodeID
z.ForEachMachine(func(p *Machine) bool {
if p.IsGateway() {
out = append(out, p.ID)
+77
View File
@@ -0,0 +1,77 @@
package rings
import "net/netip"
// AddrFromU32 converts a 32bit value into an IPv4
// address.
func AddrFromU32(v uint32) netip.Addr {
return AddrFrom4(
uint(v>>24),
uint(v>>16),
uint(v>>8),
uint(v),
)
}
// AddrFrom4 assembles an IPv4 address for 4 numbers.
// each number is truncated to 8-bits.
func AddrFrom4(a, b, c, d uint) netip.Addr {
return netip.AddrFrom4([4]byte{
byte(a & 0xff),
byte(b & 0xff),
byte(c & 0xff),
byte(d & 0xff),
})
}
// AddrToU32 converts a valid IPv4 address into it's
// 32bit numeric representation.
func AddrToU32(addr netip.Addr) (v uint32, ok bool) {
if addr.IsValid() {
if addr.Is4() || addr.Is4In6() {
a4 := addr.As4()
v = uint32(a4[0])<<24 +
uint32(a4[1])<<16 +
uint32(a4[2])<<8 +
uint32(a4[3])
return v, true
}
}
return 0, false
}
// PrefixToRange returns the beginning and end of a
// [netip.Prefix] (aka CIDR or subnet).
func PrefixToRange(subnet netip.Prefix) (from, to netip.Addr, ok bool) {
var u uint32
addr := subnet.Addr()
if u, ok = AddrToU32(addr); ok {
bits := subnet.Bits()
switch {
case bits > 32, bits < 0:
// bad
case bits == 32:
// single
from, to, ok = addr, addr, true
default:
// subnet
shift := 32 - bits
m1 := uint32((1 << shift) - 1)
m0 := uint32(0xffffffff) & ^m1
u0 := u & m0
u1 := u0 + m1
ok = true
from = AddrFromU32(u0)
to = AddrFromU32(u1)
}
}
return from, to, ok
}
+178
View File
@@ -0,0 +1,178 @@
package rings
import (
"fmt"
"net/netip"
"testing"
)
func TestAddrFrom4(t *testing.T) {
cases := []struct {
v [4]uint
s string
}{
{[4]uint{0, 0, 0, 0}, "0.0.0.0"},
{[4]uint{127, 0, 0, 1}, "127.0.0.1"},
{[4]uint{4096 + 127, 0, 0, 1}, "127.0.0.1"},
{[4]uint{257, 258, 259, 260}, "1.2.3.4"},
{[4]uint{255, 255, 255, 255}, "255.255.255.255"},
}
for i, tc := range cases {
fn := fmt.Sprintf("%v.%v.%v.%v", tc.v[0], tc.v[1], tc.v[2], tc.v[3])
addr := AddrFrom4(tc.v[0], tc.v[1], tc.v[2], tc.v[3])
s := addr.String()
if s == tc.s {
t.Logf("[%v/%v]: %s → %s", i, len(cases), fn, s)
} else {
t.Errorf("ERROR: [%v/%v]: %s → %s (expected %s)", i, len(cases), fn, s, tc.s)
}
}
}
func TestAddrU32Invalid(t *testing.T) {
cases := []netip.Addr{
{},
netip.IPv6Unspecified(),
netip.IPv6Loopback(),
}
for i, tc := range cases {
v, ok := AddrToU32(tc)
switch {
case !ok && v == 0:
t.Logf("[%v/%v]: %s → %v %v", i, len(cases), tc, 0, false)
default:
t.Errorf("ERROR: [%v/%v]: %s → %v %v (expected %v %v)", i, len(cases),
tc, v, ok, 0, false)
}
}
}
func TestAddrU32Valid(t *testing.T) {
cases := []netip.Addr{
netip.IPv4Unspecified(),
AddrFrom4(0, 0, 0, 0),
AddrFrom4(1, 2, 3, 4),
AddrFrom4(10, 20, 30, 40),
AddrFrom4(127, 0, 0, 1),
AddrFrom4(255, 255, 255, 255),
MustParseAddr("::ffff:1.2.3.4"),
}
for i, tc := range cases {
u32, ok := AddrToU32(tc)
if !ok {
t.Errorf("ERROR: [%v/%v]: %s → %v %v", i, len(cases), tc, u32, ok)
continue
}
addr := AddrFromU32(u32)
if tc.Is4In6() {
ok = addr.Compare(tc.Unmap()) == 0
} else {
ok = addr.Compare(tc) == 0
}
if ok {
t.Logf("[%v/%v]: %s → %v → %s", i, len(cases), tc, u32, addr)
} else {
t.Errorf("ERROR: [%v/%v]: %s → %v → %s", i, len(cases), tc, u32, addr)
}
}
}
func MustParseAddr(s string) netip.Addr {
addr, err := netip.ParseAddr(s)
if err != nil {
panic(err)
}
return addr
}
func MustParsePrefix(s string) netip.Prefix {
subnet, err := netip.ParsePrefix(s)
if err != nil {
panic(err)
}
return subnet
}
func TestPrefixToRangeValid(t *testing.T) {
cases := []struct {
subnet netip.Prefix
from netip.Addr
to netip.Addr
}{
{
MustParsePrefix("127.0.0.1/32"),
MustParseAddr("127.0.0.1"),
MustParseAddr("127.0.0.1"),
},
{
MustParsePrefix("127.0.0.1/24"),
MustParseAddr("127.0.0.0"),
MustParseAddr("127.0.0.255"),
},
{
MustParsePrefix("127.0.1.2/16"),
MustParseAddr("127.0.0.0"),
MustParseAddr("127.0.255.255"),
},
{
MustParsePrefix("127.1.2.3/8"),
MustParseAddr("127.0.0.0"),
MustParseAddr("127.255.255.255"),
},
{
MustParsePrefix("10.20.30.40/12"),
MustParseAddr("10.16.0.0"),
MustParseAddr("10.31.255.255"),
},
{
MustParsePrefix("10.20.30.40/20"),
MustParseAddr("10.20.16.0"),
MustParseAddr("10.20.31.255"),
},
{
MustParsePrefix("10.0.0.0/12"),
MustParseAddr("10.0.0.0"),
MustParseAddr("10.15.255.255"),
},
{
MustParsePrefix("10.16.0.0/12"),
MustParseAddr("10.16.0.0"),
MustParseAddr("10.31.255.255"),
},
{
MustParsePrefix("10.32.0.0/12"),
MustParseAddr("10.32.0.0"),
MustParseAddr("10.47.255.255"),
},
{
MustParsePrefix("10.48.0.0/12"),
MustParseAddr("10.48.0.0"),
MustParseAddr("10.63.255.255"),
},
}
for i, tc := range cases {
from, to, ok := PrefixToRange(tc.subnet)
if ok && from.IsValid() && to.IsValid() &&
from.Compare(tc.from) == 0 &&
to.Compare(tc.to) == 0 {
//
t.Logf("[%v/%v]: %s → %s - %s",
i, len(cases),
tc.subnet,
from, to)
} else {
t.Errorf("ERROR: [%v/%v]: %q → %s - %s %v (expected %s - %s %v)",
i, len(cases),
tc.subnet,
from, to, ok,
tc.from, tc.to, true)
}
}
}
+145
View File
@@ -0,0 +1,145 @@
package rings
import "net/netip"
// RingZeroPrefix represents the backbone that connects gateways
// of the different Ring 1 networks.
//
// The ring 0 network corresponds to what would be ring 2 for region_id 0.
// 10.0.0.0-10.0.255.255
func RingZeroPrefix(region RegionID, zone ZoneID) (cidr netip.Prefix, err error) {
switch {
case !region.Valid():
err = ErrOutOfRange(region, "region")
case !zone.Valid():
err = ErrOutOfRange(zone, "zone")
default:
addr := unsafeRingZeroAddress(region, zone, 0)
cidr = netip.PrefixFrom(addr, RingZeroBits)
}
return cidr, err
}
// RingZeroAddress returns a Ring 0 address for a particular node.
//
// A ring 0 address looks like 10.0.(region_id << 4 + zone_id).(node_id)/20
func RingZeroAddress(region RegionID, zone ZoneID, node NodeID) (addr netip.Addr, err error) {
switch {
case !region.Valid():
err = ErrOutOfRange(region, "region")
case !zone.Valid():
err = ErrOutOfRange(zone, "zone")
case !node.ValidZero():
err = ErrOutOfRange(node, "node")
default:
addr = unsafeRingZeroAddress(region, zone, node)
}
return addr, err
}
// RingOnePrefix represents a (virtual) local network of a zone.
//
// Ring 1 is `10.(region_id).(zone_id << 4).(node_id)/20` network
// grouped under what would be Ring 2 for region_id 0.
// There are 12 bits worth of nodes but nodes under 255 are special
// as they also get a slot on Ring 0.
func RingOnePrefix(region RegionID, zone ZoneID) (cidr netip.Prefix, err error) {
switch {
case !region.Valid():
err = ErrOutOfRange(region, "region")
case !zone.Valid():
err = ErrOutOfRange(zone, "zone")
default:
addr := unsafeRingOneAddress(region, zone, 0)
cidr = netip.PrefixFrom(addr, RingOneBits)
}
return cidr, err
}
// RingOneAddress returns a Ring 1 address for a particular node.
//
// A ring 1 address is `10.(region_id).(zone_id << 4).(node_id)/20`
// but the node_id can take up to 12 bits.
func RingOneAddress(region RegionID, zone ZoneID, node NodeID) (addr netip.Addr, err error) {
switch {
case !region.Valid():
err = ErrOutOfRange(region, "region")
case !zone.Valid():
err = ErrOutOfRange(zone, "zone")
case !node.Valid():
err = ErrOutOfRange(node, "node")
default:
addr = unsafeRingOneAddress(region, zone, node)
}
return addr, err
}
// RingTwoPrefix represents the services of a cluster
//
// Ring 2 subnets are of the form `10.(region_id).0.0/20`,
// using the address space that would belong to the ring 3
// region_id 0.
func RingTwoPrefix(region RegionID) (cidr netip.Prefix, err error) {
switch {
case !region.Valid():
err = ErrOutOfRange(region, "region")
default:
addr := unsafeRingTwoAddress(region, 0)
cidr = netip.PrefixFrom(addr, RingTwoBits)
}
return cidr, err
}
// RingThreePrefix returns the subnet corresponding to
// the pods of a cluster.
//
// Ring 3 is a `10.(region_id << 4).0.0/12` network
func RingThreePrefix(region RegionID) (subnet netip.Prefix, err error) {
switch {
case !region.Valid():
err = ErrOutOfRange(region, "region")
default:
addr := unsafeRingThreeAddress(region, 0)
subnet = netip.PrefixFrom(addr, RingThreeBits)
}
return subnet, err
}
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 {
r := uint(region)
z := uint(zone)
n := uint(node)
n1 := n >> 8
n0 := n >> 0
return AddrFrom4(10, r, z<<4+n1, n0)
}
func unsafeRingTwoAddress(region RegionID, n uint) netip.Addr {
r := uint(region)
n1 := n >> 8
n0 := n >> 0
return AddrFrom4(10, r, n1, n0)
}
func unsafeRingThreeAddress(region RegionID, n uint) netip.Addr {
r := uint(region)
n2 := n >> 16
n1 := n >> 8
n0 := n >> 0
return AddrFrom4(10, r<<4+n2, n1, n0)
}
+63
View File
@@ -0,0 +1,63 @@
package rings
import (
"fmt"
"net/netip"
"testing"
)
func TestRingZeroAddress(t *testing.T) {
RZNTest(t, "RingZeroAddress", RingZeroAddress, []RZNTestCase{
{1, 1, 50, MustParseAddr("10.0.17.50")},
{1, 2, 50, MustParseAddr("10.0.18.50")},
{2, 3, 1, MustParseAddr("10.0.35.1")},
{2, 3, 300, netip.Addr{}},
})
}
func TestRingOneAddress(t *testing.T) {
RZNTest(t, "RingOneAddress", RingOneAddress, []RZNTestCase{
{1, 1, 50, MustParseAddr("10.1.16.50")},
{1, 2, 50, MustParseAddr("10.1.32.50")},
{2, 3, 300, MustParseAddr("10.2.49.44")},
{1, 20, 50, netip.Addr{}},
})
}
type RZNTestCase struct {
region RegionID
zone ZoneID
node NodeID
addr netip.Addr
}
func RZNTest(t *testing.T,
fnName string, fn func(RegionID, ZoneID, NodeID) (netip.Addr, error),
cases []RZNTestCase) {
//
for i, tc := range cases {
s := fmt.Sprintf("%s(%v, %v, %v)", fnName,
tc.region,
tc.zone,
tc.node,
)
addr, err := fn(tc.region, tc.zone, tc.node)
switch {
case !tc.addr.IsValid():
// expect error
if err != nil {
t.Logf("[%v/%v]: %s → %s", i, len(cases), s, err)
} else {
t.Errorf("ERROR: [%v/%v]: %s → %s (expected %s)", i, len(cases), s, addr, "error")
}
case err != nil:
t.Errorf("ERROR: [%v/%v]: %s → %s (expected %s)", i, len(cases), s, err, tc.addr)
case addr.Compare(tc.addr) != 0:
t.Errorf("ERROR: [%v/%v]: %s → %s (expected %s)", i, len(cases), s, addr, tc.addr)
default:
t.Logf("[%v/%v]: %s → %s", i, len(cases), s, addr)
}
}
}
+60
View File
@@ -0,0 +1,60 @@
// Package rings provides logic to work with the four rings
// of a cluster
package rings
import (
"syscall"
"darvaza.org/core"
)
const (
// RegionMax indicates the highest number that can be used for a [RegionID].
RegionMax = (1 << 4) - 1
// ZoneMax indicates the highest number that can be used for a [ZoneID].
ZoneMax = (1 << 4) - 1
// NodeMax indicates the highest number that can be used for a [NodeID].
NodeMax = (1 << 12) - 1
// NodeZeroMax indicates the highest number that can be used for a [NodeID]
// when its a gateway connected to Ring 0 (backbone).
NodeZeroMax = (1 << 8) - 1
// RingZeroBits indicates the size of the prefix on the ring 0 (backbone) network.
RingZeroBits = 16
// RingOneBits indicates the size of the prefix on the ring 1 (lan) network.
RingOneBits = 20
// RingTwoBits indicates the size of the prefix on the ring 2 (services) network
// of all kubernetes clusters.
RingTwoBits = 20
// RingThreeBits indicates the size of the prefix on the ring 3 (pods) network
// of the kubernetes cluster of a region.
RingThreeBits = 12
)
// RegionID is the identifier of a region, valid between 1 and [RegionMax].
type RegionID int
// Valid tells a [RegionID] is within the valid range.
func (n RegionID) Valid() bool { return n > 0 && n <= RegionMax }
// ZoneID is the identifier of a zone within a region, valid between 1 and [ZoneMax].
type ZoneID int
// Valid tells a [ZoneID] is within the valid range.
func (n ZoneID) Valid() bool { return n > 0 && n <= ZoneMax }
// NodeID is the identifier of a machine within a zone of a region, valid between
// 1 and [NodeMax], but between 1 and [NodeZeroMax] if it will be a zone gateway.
type NodeID int
// Valid tells a [NodeID] is within the valid range.
func (n NodeID) Valid() bool { return n > 0 && n <= NodeMax }
// ValidZero tells a [NodeID] is within the valid range for a gateway.
func (n NodeID) ValidZero() bool { return n > 0 && n <= NodeZeroMax }
// ErrOutOfRange is an error indicating the value of a field
// is out of range.
func ErrOutOfRange[T ~int | ~uint32](value T, field string) error {
return core.Wrap(syscall.EINVAL, "%s out of range (%v)", field, value)
}