Skip to content

Commit 0fa57b2

Browse files
authored
Merge branch 'main' into dependabot/go_modules/go.opentelemetry.io/otel/sdk-1.28.0
2 parents 44929f9 + 4e78b80 commit 0fa57b2

14 files changed

+690
-757
lines changed

clients/clients.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ type LinodeVPCClient interface {
4848

4949
// LinodeNodeBalancerClient defines the methods that interact with Linode's Node Balancer service.
5050
type LinodeNodeBalancerClient interface {
51-
ListNodeBalancers(ctx context.Context, opts *linodego.ListOptions) ([]linodego.NodeBalancer, error)
5251
CreateNodeBalancer(ctx context.Context, opts linodego.NodeBalancerCreateOptions) (*linodego.NodeBalancer, error)
52+
GetNodeBalancer(ctx context.Context, nodebalancerID int) (*linodego.NodeBalancer, error)
53+
GetNodeBalancerConfig(ctx context.Context, nodebalancerID int, configID int) (*linodego.NodeBalancerConfig, error)
5354
CreateNodeBalancerConfig(ctx context.Context, nodebalancerID int, opts linodego.NodeBalancerConfigCreateOptions) (*linodego.NodeBalancerConfig, error)
5455
DeleteNodeBalancerNode(ctx context.Context, nodebalancerID int, configID int, nodeID int) error
5556
DeleteNodeBalancer(ctx context.Context, nodebalancerID int) error

cloud/services/domains.go

Lines changed: 71 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,41 @@ package services
22

33
import (
44
"context"
5-
"crypto/sha256"
6-
"encoding/hex"
75
"encoding/json"
8-
"errors"
96
"fmt"
10-
"time"
7+
"net/netip"
8+
"sync"
119

1210
"github.com/linode/linodego"
11+
"sigs.k8s.io/cluster-api/api/v1beta1"
1312
kutil "sigs.k8s.io/cluster-api/util"
1413

1514
"github.com/linode/cluster-api-provider-linode/cloud/scope"
1615
rutil "github.com/linode/cluster-api-provider-linode/util/reconciler"
1716
)
1817

19-
var ipTypeToRecordTypeMapper = map[string]linodego.DomainRecordType{"IPv4": "A", "IPv6": "AAAA"}
18+
type DNSEntries struct {
19+
options []DNSOptions
20+
mux sync.RWMutex
21+
}
2022

21-
// AddIPToDNS creates the A and TXT record for the machine
22-
func AddIPToDNS(ctx context.Context, mscope *scope.MachineScope) error {
23-
dnsTTLSec := rutil.DefaultDNSTTLSec
24-
if mscope.LinodeCluster.Spec.Network.DNSTTLSec != 0 {
25-
dnsTTLSec = mscope.LinodeCluster.Spec.Network.DNSTTLSec
26-
}
23+
type DNSOptions struct {
24+
Hostname string
25+
Target string
26+
DNSRecordType linodego.DomainRecordType
27+
DNSTTLSec int
28+
}
2729

30+
// EnsureDNSEntries ensures the domainrecord is created, updated, or deleted based on operation passed
31+
func EnsureDNSEntries(ctx context.Context, mscope *scope.MachineScope, operation string) error {
2832
// Check if instance is a control plane node
2933
if !kutil.IsControlPlaneMachine(mscope.Machine) {
3034
return nil
3135
}
3236

3337
// Get the public IP that was assigned
34-
publicIPs, err := getMachinePublicIPs(ctx, mscope)
38+
var dnss DNSEntries
39+
dnsEntries, err := dnss.getDNSEntriesToEnsure(mscope)
3540
if err != nil {
3641
return err
3742
}
@@ -41,90 +46,53 @@ func AddIPToDNS(ctx context.Context, mscope *scope.MachineScope) error {
4146
if err != nil {
4247
return err
4348
}
44-
domainHostname := mscope.LinodeCluster.ObjectMeta.Name + "-" + mscope.LinodeCluster.Spec.Network.DNSUniqueIdentifier
4549

46-
// Create/Update the A record for this IP and name combo
47-
for ipType, publicIP := range publicIPs {
48-
if err := CreateUpdateDomainRecord(ctx, mscope, domainHostname, publicIP, dnsTTLSec, domainID, ipTypeToRecordTypeMapper[ipType]); err != nil {
50+
for _, dnsEntry := range dnsEntries {
51+
if operation == "delete" {
52+
if err := DeleteDomainRecord(ctx, mscope, domainID, dnsEntry); err != nil {
53+
return err
54+
}
55+
continue
56+
}
57+
if err := CreateUpdateDomainRecord(ctx, mscope, domainID, dnsEntry); err != nil {
4958
return err
5059
}
5160
}
5261

53-
// Create/Update the TXT record for this IP and name combo
54-
txtRecordValueString := createSHA256HashOfString(mscope.LinodeMachine.Name)
55-
if err := CreateUpdateDomainRecord(ctx, mscope, domainHostname, "owner:"+txtRecordValueString, dnsTTLSec, domainID, "TXT"); err != nil {
56-
return err
57-
}
58-
5962
return nil
6063
}
6164

62-
// DeleteIPFromDNS deletes the A and TXT record for the machine
63-
func DeleteIPFromDNS(ctx context.Context, mscope *scope.MachineScope) error {
65+
// getDNSEntriesToEnsure return DNS entries to create/delete
66+
func (d *DNSEntries) getDNSEntriesToEnsure(mscope *scope.MachineScope) ([]DNSOptions, error) {
67+
d.mux.Lock()
68+
defer d.mux.Unlock()
6469
dnsTTLSec := rutil.DefaultDNSTTLSec
6570
if mscope.LinodeCluster.Spec.Network.DNSTTLSec != 0 {
6671
dnsTTLSec = mscope.LinodeCluster.Spec.Network.DNSTTLSec
6772
}
6873

69-
// Check if instance is a control plane node
70-
if !kutil.IsControlPlaneMachine(mscope.Machine) {
71-
return nil
72-
}
73-
74-
// Get the public IP that was assigned
75-
publicIPs, err := getMachinePublicIPs(ctx, mscope)
76-
if err != nil {
77-
return err
78-
}
79-
80-
// Get domainID from domain name
81-
domainID, err := GetDomainID(ctx, mscope)
82-
if err != nil {
83-
return err
74+
if mscope.LinodeMachine.Status.Addresses == nil {
75+
return nil, fmt.Errorf("no addresses available on the LinodeMachine resource")
8476
}
8577
domainHostname := mscope.LinodeCluster.ObjectMeta.Name + "-" + mscope.LinodeCluster.Spec.Network.DNSUniqueIdentifier
8678

87-
// Delete A record
88-
for ipType, publicIP := range publicIPs {
89-
if err := DeleteDomainRecord(ctx, mscope, domainHostname, publicIP, dnsTTLSec, domainID, ipTypeToRecordTypeMapper[ipType]); err != nil {
90-
return err
79+
for _, IPs := range mscope.LinodeMachine.Status.Addresses {
80+
recordType := linodego.RecordTypeA
81+
if IPs.Type != v1beta1.MachineExternalIP {
82+
continue
9183
}
84+
addr, err := netip.ParseAddr(IPs.Address)
85+
if err != nil {
86+
return nil, fmt.Errorf("not a valid IP %w", err)
87+
}
88+
if !addr.Is4() {
89+
recordType = linodego.RecordTypeAAAA
90+
}
91+
d.options = append(d.options, DNSOptions{domainHostname, IPs.Address, recordType, dnsTTLSec})
9292
}
93+
d.options = append(d.options, DNSOptions{domainHostname, mscope.LinodeMachine.Name, linodego.RecordTypeTXT, dnsTTLSec})
9394

94-
// Delete TXT record
95-
txtRecordValueString := createSHA256HashOfString(mscope.LinodeMachine.Name)
96-
if err := DeleteDomainRecord(ctx, mscope, domainHostname, "owner:"+txtRecordValueString, dnsTTLSec, domainID, "TXT"); err != nil {
97-
return err
98-
}
99-
100-
// Wait for TTL to expire
101-
time.Sleep(time.Duration(dnsTTLSec) * time.Second)
102-
103-
return nil
104-
}
105-
106-
// getMachinePublicIPs gets the machines public IP
107-
func getMachinePublicIPs(ctx context.Context, mscope *scope.MachineScope) (map[string]string, error) {
108-
// Verify instance id is not nil
109-
if mscope.LinodeMachine.Spec.InstanceID == nil {
110-
return nil, errors.New("instance ID is nil. cant get machine's public ip")
111-
}
112-
113-
// Get the public IP that was assigned
114-
addresses, err := mscope.LinodeClient.GetInstanceIPAddresses(ctx, *mscope.LinodeMachine.Spec.InstanceID)
115-
if err != nil {
116-
return nil, err
117-
}
118-
119-
if len(addresses.IPv4.Public) == 0 || addresses.IPv6 == nil {
120-
return nil, errors.New("no public address")
121-
}
122-
123-
if addresses.IPv6.SLAAC == nil {
124-
return nil, errors.New("no SLAAC address")
125-
}
126-
127-
return map[string]string{"IPv4": addresses.IPv4.Public[0].Address, "IPv6": addresses.IPv6.SLAAC.Address}, nil
95+
return d.options, nil
12896
}
12997

13098
// GetDomainID gets the domains linode id
@@ -145,9 +113,9 @@ func GetDomainID(ctx context.Context, mscope *scope.MachineScope) (int, error) {
145113
return domains[0].ID, nil
146114
}
147115

148-
func CreateUpdateDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostname, target string, ttl, domainID int, recordType linodego.DomainRecordType) error {
116+
func CreateUpdateDomainRecord(ctx context.Context, mscope *scope.MachineScope, domainID int, dnsEntry DNSOptions) error {
149117
// Check if domain record exists for this IP and name combo
150-
filter, err := json.Marshal(map[string]interface{}{"name": hostname, "target": target, "type": recordType})
118+
filter, err := json.Marshal(map[string]interface{}{"name": dnsEntry.Hostname, "target": dnsEntry.Target, "type": dnsEntry.DNSRecordType})
151119
if err != nil {
152120
return err
153121
}
@@ -159,31 +127,31 @@ func CreateUpdateDomainRecord(ctx context.Context, mscope *scope.MachineScope, h
159127

160128
// If record doesnt exist, create it
161129
if len(domainRecords) == 0 {
162-
if err := CreateDomainRecord(ctx, mscope, hostname, target, ttl, domainID, recordType); err != nil {
130+
if err := CreateDomainRecord(ctx, mscope, domainID, dnsEntry); err != nil {
163131
return err
164132
}
165133
return nil
166134
}
167135

168136
// If record exists, update it
169-
if len(domainRecords) != 0 && recordType != "TXT" {
170-
isOwner, err := IsDomainRecordOwner(ctx, mscope, hostname, target, domainID)
137+
if len(domainRecords) != 0 && dnsEntry.DNSRecordType != linodego.RecordTypeTXT {
138+
isOwner, err := IsDomainRecordOwner(ctx, mscope, dnsEntry.Hostname, domainID)
171139
if err != nil {
172140
return err
173141
}
174142
if !isOwner {
175143
return fmt.Errorf("the domain record is not owned by this entity. wont update")
176144
}
177145
}
178-
if err := UpdateDomainRecord(ctx, mscope, hostname, target, ttl, domainID, domainRecords[0].ID, recordType); err != nil {
146+
if err := UpdateDomainRecord(ctx, mscope, domainID, domainRecords[0].ID, dnsEntry); err != nil {
179147
return err
180148
}
181149
return nil
182150
}
183151

184-
func DeleteDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostname, target string, ttl, domainID int, recordType linodego.DomainRecordType) error {
152+
func DeleteDomainRecord(ctx context.Context, mscope *scope.MachineScope, domainID int, dnsEntry DNSOptions) error {
185153
// Check if domain record exists for this IP and name combo
186-
filter, err := json.Marshal(map[string]interface{}{"name": hostname, "target": target, "type": recordType})
154+
filter, err := json.Marshal(map[string]interface{}{"name": dnsEntry.Hostname, "target": dnsEntry.Target, "type": dnsEntry.DNSRecordType})
187155
if err != nil {
188156
return err
189157
}
@@ -198,12 +166,11 @@ func DeleteDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostnam
198166
return nil
199167
}
200168

201-
// If record is A type, verify ownership
202-
if recordType != "TXT" {
203-
txtRecordValueString := createSHA256HashOfString(mscope.LinodeMachine.Name)
204-
isOwner, ownerErr := IsDomainRecordOwner(ctx, mscope, hostname, "owner:"+txtRecordValueString, domainID)
205-
if ownerErr != nil {
206-
return ownerErr
169+
// If record is A/AAAA type, verify ownership
170+
if dnsEntry.DNSRecordType != linodego.RecordTypeTXT {
171+
isOwner, err := IsDomainRecordOwner(ctx, mscope, dnsEntry.Hostname, domainID)
172+
if err != nil {
173+
return err
207174
}
208175
if !isOwner {
209176
return fmt.Errorf("the domain record is not owned by this entity. wont delete")
@@ -217,12 +184,12 @@ func DeleteDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostnam
217184
return nil
218185
}
219186

220-
func CreateDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostname, target string, ttl, domainID int, recordType linodego.DomainRecordType) error {
187+
func CreateDomainRecord(ctx context.Context, mscope *scope.MachineScope, domainID int, dnsEntries DNSOptions) error {
221188
recordReq := linodego.DomainRecordCreateOptions{
222-
Type: recordType,
223-
Name: hostname,
224-
Target: target,
225-
TTLSec: ttl,
189+
Type: dnsEntries.DNSRecordType,
190+
Name: dnsEntries.Hostname,
191+
Target: dnsEntries.Target,
192+
TTLSec: dnsEntries.DNSTTLSec,
226193
}
227194

228195
if _, err := mscope.LinodeDomainsClient.CreateDomainRecord(ctx, domainID, recordReq); err != nil {
@@ -231,12 +198,12 @@ func CreateDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostnam
231198
return nil
232199
}
233200

234-
func UpdateDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostname, target string, ttl, domainID, domainRecordID int, recordType linodego.DomainRecordType) error {
201+
func UpdateDomainRecord(ctx context.Context, mscope *scope.MachineScope, domainID, domainRecordID int, dnsEntries DNSOptions) error {
235202
recordReq := linodego.DomainRecordUpdateOptions{
236-
Type: recordType,
237-
Name: hostname,
238-
Target: target,
239-
TTLSec: ttl,
203+
Type: dnsEntries.DNSRecordType,
204+
Name: dnsEntries.Hostname,
205+
Target: dnsEntries.Target,
206+
TTLSec: dnsEntries.DNSTTLSec,
240207
}
241208

242209
if _, err := mscope.LinodeDomainsClient.UpdateDomainRecord(ctx, domainID, domainRecordID, recordReq); err != nil {
@@ -245,9 +212,9 @@ func UpdateDomainRecord(ctx context.Context, mscope *scope.MachineScope, hostnam
245212
return nil
246213
}
247214

248-
func IsDomainRecordOwner(ctx context.Context, mscope *scope.MachineScope, hostname, target string, domainID int) (bool, error) {
215+
func IsDomainRecordOwner(ctx context.Context, mscope *scope.MachineScope, hostname string, domainID int) (bool, error) {
249216
// Check if domain record exists
250-
filter, err := json.Marshal(map[string]interface{}{"name": hostname, "target": target, "type": "TXT"})
217+
filter, err := json.Marshal(map[string]interface{}{"name": hostname, "target": mscope.LinodeMachine.Name, "type": linodego.RecordTypeTXT})
251218
if err != nil {
252219
return false, err
253220
}
@@ -259,14 +226,8 @@ func IsDomainRecordOwner(ctx context.Context, mscope *scope.MachineScope, hostna
259226

260227
// If record exists, update it
261228
if len(domainRecords) == 0 {
262-
return false, fmt.Errorf("no txt record %s found with value %s for machine %s", hostname, target, mscope.LinodeMachine.Name)
229+
return false, fmt.Errorf("no txt record %s found with value %s for machine %s", hostname, mscope.LinodeMachine.Name, mscope.LinodeMachine.Name)
263230
}
264231

265232
return true, nil
266233
}
267-
268-
func createSHA256HashOfString(stringToConvert string) string {
269-
machineNameHash := sha256.New()
270-
machineNameHash.Write([]byte(stringToConvert))
271-
return hex.EncodeToString(machineNameHash.Sum(nil))
272-
}

0 commit comments

Comments
 (0)