mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
fix: create AAAA DNS record for IPv6 machines" (#257)
* chore: update gitignore * fix: create AAAA DNS record for IPv6 machines" * test: randomize execution order to prevent order-based bugs in tests
This commit is contained in:
+54
-13
@@ -75,24 +75,17 @@ func (cli *Client) CreateIngressRecords(ctx context.Context, serviceID string) (
|
||||
close(reachableMachines)
|
||||
}()
|
||||
|
||||
var ingressIPs []string
|
||||
var machines []*pb.MachineInfo
|
||||
for m := range reachableMachines {
|
||||
ip, _ := m.PublicIp.ToAddr()
|
||||
ingressIPs = append(ingressIPs, ip.String())
|
||||
machines = append(machines, m)
|
||||
}
|
||||
if len(ingressIPs) == 0 {
|
||||
if len(machines) == 0 {
|
||||
return nil, ErrNoReachableMachines
|
||||
}
|
||||
|
||||
req := &pb.CreateDomainRecordsRequest{
|
||||
Records: []*pb.DNSRecord{
|
||||
{
|
||||
Name: "*",
|
||||
Type: pb.DNSRecord_A,
|
||||
Values: ingressIPs,
|
||||
},
|
||||
// TODO: Add AAAA record with routable IPv6 addresses of machines running Caddy containers.
|
||||
},
|
||||
req, err := getCreateDomainRecordsRequest(machines)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create CreateDomainRecordsRequest: %w", err)
|
||||
}
|
||||
resp, err := cli.CreateDomainRecords(ctx, req)
|
||||
if err != nil {
|
||||
@@ -102,6 +95,54 @@ func (cli *Client) CreateIngressRecords(ctx context.Context, serviceID string) (
|
||||
return resp.Records, nil
|
||||
}
|
||||
|
||||
func getCreateDomainRecordsRequest(machines []*pb.MachineInfo) (*pb.CreateDomainRecordsRequest, error) {
|
||||
if len(machines) == 0 {
|
||||
return nil, fmt.Errorf("at least one machine must be provided")
|
||||
}
|
||||
|
||||
var ipv4IngressIPs []string
|
||||
var ipv6IngressIPs []string
|
||||
var errs error
|
||||
for _, m := range machines {
|
||||
ip, _ := m.PublicIp.ToAddr()
|
||||
if ip.Is4() {
|
||||
ipv4IngressIPs = append(ipv4IngressIPs, ip.String())
|
||||
} else if ip.Is6() {
|
||||
ipv6IngressIPs = append(ipv6IngressIPs, ip.String())
|
||||
} else {
|
||||
// This is just a save guard, in case some special case is ever missed.
|
||||
errs = errors.Join(errs, fmt.Errorf("machine with name %s (and ID: %s) has the public IP address '%s' which is neither IPv4 nor IPv6", m.Name, m.Id, ip.String()))
|
||||
}
|
||||
}
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
records := make([]*pb.DNSRecord, 0, 2)
|
||||
if len(ipv4IngressIPs) > 0 {
|
||||
records = append(records,
|
||||
&pb.DNSRecord{
|
||||
Name: "*",
|
||||
Type: pb.DNSRecord_A,
|
||||
Values: ipv4IngressIPs,
|
||||
},
|
||||
)
|
||||
}
|
||||
if len(ipv6IngressIPs) > 0 {
|
||||
records = append(records,
|
||||
&pb.DNSRecord{
|
||||
Name: "*",
|
||||
Type: pb.DNSRecord_AAAA,
|
||||
Values: ipv6IngressIPs,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return &pb.CreateDomainRecordsRequest{
|
||||
Records: records,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// verifyCaddyReachable verifies that the Caddy service is reachable on the machine by its public IP.
|
||||
func verifyCaddyReachable(ctx context.Context, m *pb.MachineInfo) error {
|
||||
publicIP, _ := m.PublicIp.ToAddr()
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetVerifyURL(t *testing.T) {
|
||||
@@ -28,3 +31,74 @@ func TestGetVerifyURL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCreateDomainRecordsRequest(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
given []*pb.MachineInfo
|
||||
wantReq *pb.CreateDomainRecordsRequest
|
||||
wantErr error
|
||||
}{
|
||||
"single IPv4 machine": {
|
||||
given: []*pb.MachineInfo{
|
||||
{Id: "m1", Name: "machine-1", PublicIp: pb.NewIP(netip.MustParseAddr("1.2.3.4"))},
|
||||
},
|
||||
wantReq: &pb.CreateDomainRecordsRequest{
|
||||
Records: []*pb.DNSRecord{
|
||||
{Name: "*", Type: pb.DNSRecord_A, Values: []string{"1.2.3.4"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
"single IPv6 machine": {
|
||||
given: []*pb.MachineInfo{
|
||||
{Id: "m1", Name: "machine-1", PublicIp: pb.NewIP(netip.MustParseAddr("2001:db8::1"))},
|
||||
},
|
||||
wantReq: &pb.CreateDomainRecordsRequest{
|
||||
Records: []*pb.DNSRecord{
|
||||
{Name: "*", Type: pb.DNSRecord_AAAA, Values: []string{"2001:db8::1"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
"multiple IPv4 machines": {
|
||||
given: []*pb.MachineInfo{
|
||||
{Id: "m1", Name: "machine-1", PublicIp: pb.NewIP(netip.MustParseAddr("1.2.3.4"))},
|
||||
{Id: "m2", Name: "machine-2", PublicIp: pb.NewIP(netip.MustParseAddr("5.6.7.8"))},
|
||||
},
|
||||
wantReq: &pb.CreateDomainRecordsRequest{
|
||||
Records: []*pb.DNSRecord{
|
||||
{Name: "*", Type: pb.DNSRecord_A, Values: []string{"1.2.3.4", "5.6.7.8"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
"mixed IPv4 and IPv6 machines": {
|
||||
given: []*pb.MachineInfo{
|
||||
{Id: "m1", Name: "machine-1", PublicIp: pb.NewIP(netip.MustParseAddr("1.2.3.4"))},
|
||||
{Id: "m2", Name: "machine-2", PublicIp: pb.NewIP(netip.MustParseAddr("2001:db8::1"))},
|
||||
{Id: "m3", Name: "machine-3", PublicIp: pb.NewIP(netip.MustParseAddr("10.0.0.1"))},
|
||||
{Id: "m4", Name: "machine-4", PublicIp: pb.NewIP(netip.MustParseAddr("2001:db8::2"))},
|
||||
},
|
||||
wantReq: &pb.CreateDomainRecordsRequest{
|
||||
Records: []*pb.DNSRecord{
|
||||
{Name: "*", Type: pb.DNSRecord_A, Values: []string{"1.2.3.4", "10.0.0.1"}},
|
||||
{Name: "*", Type: pb.DNSRecord_AAAA, Values: []string{"2001:db8::1", "2001:db8::2"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
"empty machine list": {
|
||||
given: nil,
|
||||
wantErr: fmt.Errorf("at least one machine must be provided"),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
gotReq, gotErr := getCreateDomainRecordsRequest(tt.given)
|
||||
if tt.wantErr == nil {
|
||||
require.NoError(t, gotErr)
|
||||
assert.Equal(t, tt.wantReq, gotReq)
|
||||
} else {
|
||||
assert.Nil(t, gotReq)
|
||||
assert.Equal(t, tt.wantErr.Error(), gotErr.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user