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/status"
"google.golang.org/protobuf/types/known/emptypb"
"net/netip"
"time"
"uncloud/internal/cli"
"uncloud/internal/cli/client"
@@ -18,10 +19,11 @@ import (
)
type addOptions struct {
name string
noCaddy bool
sshKey string
cluster string
name string
noCaddy bool
publicIP string
sshKey string
cluster string
}
func NewAddCommand() *cobra.Command {
@@ -52,6 +54,11 @@ func NewAddCommand() *cobra.Command {
&opts.noCaddy, "no-caddy", false,
"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(
&opts.sshKey, "ssh-key", "i", "",
"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 {
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 {
return err
}
+12 -2
View File
@@ -204,9 +204,10 @@ func (cli *CLI) initRemoteMachine(
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(
ctx context.Context, remoteMachine RemoteMachine, clusterName, machineName string,
ctx context.Context, remoteMachine RemoteMachine, clusterName, machineName string, publicIP *netip.Addr,
) (*client.Client, error) {
c, err := cli.ConnectCluster(ctx, clusterName)
if err != nil {
@@ -256,6 +257,15 @@ func (cli *CLI) AddMachine(
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)
if err != nil {
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 {
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 {
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.
if err == nil {
if pubIPErr == nil {
ips = append(ips, publicIP)
}
endpoints := make([]*pb.IPPort, len(ips))
@@ -560,7 +560,7 @@ func (m *Machine) InitCluster(ctx context.Context, req *pb.InitClusterRequest) (
}
if req.GetPublicIp() != nil {
addReq.PublicIp = req.GetPublicIp()
} else if req.GetPublicIpAuto() {
} else if req.GetPublicIpAuto() && pubIPErr == nil {
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)
}
token := NewToken(m.state.Network.PublicKey, endpoints)
token := NewToken(m.state.Network.PublicKey, publicIP, endpoints)
tokenStr, err := token.String()
if err != nil {
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.
type Token struct {
PublicKey secret.Secret
PublicIP netip.Addr
Endpoints []netip.AddrPort
}
// 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{
PublicKey: publicKey,
PublicIP: publicIP,
Endpoints: endpoints,
}
}