feat(dns): configure and store public IP when adding new machine

This commit is contained in:
Pavel Sviderski
2025-02-26 11:16:13 +10:00
parent 35804458b0
commit 1046396edc
5 changed files with 46 additions and 13 deletions
+26 -5
View File
@@ -10,6 +10,7 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/emptypb"
"net/netip"
"time" "time"
"uncloud/internal/cli" "uncloud/internal/cli"
"uncloud/internal/cli/client" "uncloud/internal/cli/client"
@@ -18,10 +19,11 @@ import (
) )
type addOptions struct { type addOptions struct {
name string name string
noCaddy bool noCaddy bool
sshKey string publicIP string
cluster string sshKey string
cluster string
} }
func NewAddCommand() *cobra.Command { func NewAddCommand() *cobra.Command {
@@ -52,6 +54,11 @@ func NewAddCommand() *cobra.Command {
&opts.noCaddy, "no-caddy", false, &opts.noCaddy, "no-caddy", false,
"Don't deploy Caddy reverse proxy service to the machine.", "Don't deploy Caddy reverse proxy service to the machine.",
) )
cmd.Flags().StringVar(
&opts.publicIP, "public-ip", "auto",
"Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, "+
"blank '' or 'none' to disable ingress on this machine, or specify an IP address.",
)
cmd.Flags().StringVarP( cmd.Flags().StringVarP(
&opts.sshKey, "ssh-key", "i", "", &opts.sshKey, "ssh-key", "i", "",
"path to SSH private key for SSH remote login. (default ~/.ssh/id_*)", "path to SSH private key for SSH remote login. (default ~/.ssh/id_*)",
@@ -64,7 +71,21 @@ func NewAddCommand() *cobra.Command {
} }
func add(ctx context.Context, uncli *cli.CLI, remoteMachine cli.RemoteMachine, opts addOptions) error { func add(ctx context.Context, uncli *cli.CLI, remoteMachine cli.RemoteMachine, opts addOptions) error {
machineClient, err := uncli.AddMachine(ctx, remoteMachine, opts.cluster, opts.name) var publicIP *netip.Addr
switch opts.publicIP {
case "auto":
publicIP = &netip.Addr{}
case "", "none":
publicIP = nil
default:
ip, err := netip.ParseAddr(opts.publicIP)
if err != nil {
return fmt.Errorf("parse public IP: %w", err)
}
publicIP = &ip
}
machineClient, err := uncli.AddMachine(ctx, remoteMachine, opts.cluster, opts.name, publicIP)
if err != nil { if err != nil {
return err return err
} }
+12 -2
View File
@@ -204,9 +204,10 @@ func (cli *CLI) initRemoteMachine(
return machineClient, nil return machineClient, nil
} }
// TODO: // AddMachine provisions a remote machine and adds it to the cluster. It returns a client to interact with the machine
// which should be closed after use by the caller.
func (cli *CLI) AddMachine( func (cli *CLI) AddMachine(
ctx context.Context, remoteMachine RemoteMachine, clusterName, machineName string, ctx context.Context, remoteMachine RemoteMachine, clusterName, machineName string, publicIP *netip.Addr,
) (*client.Client, error) { ) (*client.Client, error) {
c, err := cli.ConnectCluster(ctx, clusterName) c, err := cli.ConnectCluster(ctx, clusterName)
if err != nil { if err != nil {
@@ -256,6 +257,15 @@ func (cli *CLI) AddMachine(
PublicKey: token.PublicKey, PublicKey: token.PublicKey,
}, },
} }
if publicIP != nil {
if publicIP.IsValid() {
addReq.PublicIp = pb.NewIP(*publicIP)
} else if token.PublicIP.IsValid() {
// Invalid or in other words zero IP means to use an automatically detected public IP from the token.
addReq.PublicIp = pb.NewIP(token.PublicIP)
}
}
addResp, err := c.AddMachine(ctx, addReq) addResp, err := c.AddMachine(ctx, addReq)
if err != nil { if err != nil {
return nil, fmt.Errorf("add machine to cluster: %w", err) return nil, fmt.Errorf("add machine to cluster: %w", err)
+1 -1
View File
@@ -37,5 +37,5 @@ func MachineToken(dataDir string) (machine.Token, error) {
for i, ip := range ips { for i, ip := range ips {
endpoints[i] = netip.AddrPortFrom(ip, network.WireGuardPort) endpoints[i] = netip.AddrPortFrom(ip, network.WireGuardPort)
} }
return machine.NewToken(state.Network.PublicKey, endpoints), nil return machine.NewToken(state.Network.PublicKey, publicIP, endpoints), nil
} }
+4 -4
View File
@@ -538,9 +538,9 @@ func (m *Machine) InitCluster(ctx context.Context, req *pb.InitClusterRequest) (
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "list routable IPs: %v", err) return nil, status.Errorf(codes.Internal, "list routable IPs: %v", err)
} }
publicIP, err := network.GetPublicIP() publicIP, pubIPErr := network.GetPublicIP()
// Ignore the error if failed to get the public IP using API services. // Ignore the error if failed to get the public IP using API services.
if err == nil { if pubIPErr == nil {
ips = append(ips, publicIP) ips = append(ips, publicIP)
} }
endpoints := make([]*pb.IPPort, len(ips)) endpoints := make([]*pb.IPPort, len(ips))
@@ -560,7 +560,7 @@ func (m *Machine) InitCluster(ctx context.Context, req *pb.InitClusterRequest) (
} }
if req.GetPublicIp() != nil { if req.GetPublicIp() != nil {
addReq.PublicIp = req.GetPublicIp() addReq.PublicIp = req.GetPublicIp()
} else if req.GetPublicIpAuto() { } else if req.GetPublicIpAuto() && pubIPErr == nil {
addReq.PublicIp = pb.NewIP(publicIP) addReq.PublicIp = pb.NewIP(publicIP)
} }
@@ -690,7 +690,7 @@ func (m *Machine) Token(_ context.Context, _ *emptypb.Empty) (*pb.TokenResponse,
endpoints[i] = netip.AddrPortFrom(ip, network.WireGuardPort) endpoints[i] = netip.AddrPortFrom(ip, network.WireGuardPort)
} }
token := NewToken(m.state.Network.PublicKey, endpoints) token := NewToken(m.state.Network.PublicKey, publicIP, endpoints)
tokenStr, err := token.String() tokenStr, err := token.String()
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, err.Error()) return nil, status.Error(codes.Internal, err.Error())
+3 -1
View File
@@ -16,13 +16,15 @@ const (
// Token represents the machine's token for joining a cluster. // Token represents the machine's token for joining a cluster.
type Token struct { type Token struct {
PublicKey secret.Secret PublicKey secret.Secret
PublicIP netip.Addr
Endpoints []netip.AddrPort Endpoints []netip.AddrPort
} }
// NewToken creates a new machine token with the given public key and endpoints. // NewToken creates a new machine token with the given public key and endpoints.
func NewToken(publicKey secret.Secret, endpoints []netip.AddrPort) Token { func NewToken(publicKey secret.Secret, publicIP netip.Addr, endpoints []netip.AddrPort) Token {
return Token{ return Token{
PublicKey: publicKey, PublicKey: publicKey,
PublicIP: publicIP,
Endpoints: endpoints, Endpoints: endpoints,
} }
} }