env-manager: dynamically generate cidr for new env (#85)
* env-manager: allocate env cidrs dynamically
* fix: net.IP to netip.Addr conversion
* bootstrapper: generate empty env-cidrs.yaml
* fix: net.IP to netip.Addr conversion for IP pool
* infra: expose provided startIP subnet via tailscale proxy
* headscale: pass private network ip subnet to expose to api service
* dns: make ingress IP configurable
---------
Co-authored-by: Giorgi Lekveishvili <lekva@gl-mbp-m1-max.local>
diff --git a/core/installer/tasks/infra.go b/core/installer/tasks/infra.go
index 39d9f50..cd7ad14 100644
--- a/core/installer/tasks/infra.go
+++ b/core/installer/tasks/infra.go
@@ -2,6 +2,7 @@
import (
"fmt"
+ "net"
"net/netip"
"github.com/miekg/dns"
@@ -9,7 +10,7 @@
"github.com/giolekva/pcloud/core/installer"
)
-func SetupInfra(env Env, st *state) []Task {
+func SetupInfra(env Env, startIP net.IP, st *state) []Task {
t := newLeafTask("Create client", func() error {
repo, err := st.ssClient.GetRepo("config")
if err != nil {
@@ -31,10 +32,10 @@
&t,
newConcurrentParentTask(
"Core services",
- SetupNetwork(env, st),
+ SetupNetwork(env, startIP, st),
SetupCertificateIssuers(env, st),
SetupAuth(env, st),
- SetupHeadscale(env, st),
+ SetupHeadscale(env, startIP, st),
SetupWelcome(env, st),
SetupAppStore(env, st),
),
@@ -101,13 +102,31 @@
return &t
}
-func SetupNetwork(env Env, st *state) Task {
+func SetupNetwork(env Env, startIP net.IP, st *state) Task {
t := newLeafTask("Setup network", func() error {
- ingressPrivateIP, err := netip.ParseAddr("10.1.0.1")
+ startAddr, err := netip.ParseAddr(startIP.String())
if err != nil {
return err
}
+ if !startAddr.Is4() {
+ return fmt.Errorf("Expected IPv4, got %s instead", startAddr)
+ }
+ addr := startAddr.AsSlice()
+ if addr[3] != 0 {
+ return fmt.Errorf("Expected last byte to be zero, got %d instead", addr[3])
+ }
+ addr[3] = 10
+ fromIP, ok := netip.AddrFromSlice(addr)
+ if !ok {
+ return fmt.Errorf("Must not reach")
+ }
+ addr[3] = 254
+ toIP, ok := netip.AddrFromSlice(addr)
+ if !ok {
+ return fmt.Errorf("Must not reach")
+ }
{
+ ingressPrivateIP := startAddr
headscaleIP := ingressPrivateIP.Next()
app, err := st.appsRepo.Find("metallb-ipaddresspool")
if err != nil {
@@ -133,8 +152,8 @@
}
if err := st.appManager.Install(app, st.nsGen, st.emptySuffixGen, map[string]any{
"name": env.Name,
- "from": "10.1.0.100", // TODO(gio): auto-generate
- "to": "10.1.0.254",
+ "from": fromIP.String(),
+ "to": toIP.String(),
"autoAssign": false,
"namespace": "metallb-system",
}); err != nil {
@@ -150,7 +169,7 @@
"privateNetwork": map[string]any{
"hostname": "private-network-proxy",
"username": "private-network-proxy",
- "ipSubnet": "10.1.0.0/24",
+ "ipSubnet": fmt.Sprintf("%s/24", startIP.String()),
},
}); err != nil {
return err
@@ -210,7 +229,7 @@
)
}
-func SetupHeadscale(env Env, st *state) Task {
+func SetupHeadscale(env Env, startIP net.IP, st *state) Task {
t := newLeafTask("Setup", func() error {
app, err := st.appsRepo.Find("headscale")
if err != nil {
@@ -218,6 +237,7 @@
}
if err := st.appManager.Install(app, st.nsGen, st.emptySuffixGen, map[string]any{
"subdomain": "headscale",
+ "ipSubnet": fmt.Sprintf("%s/24", startIP),
}); err != nil {
return err
}