wrapper.go raw
1 package internal
2
3 import (
4 "fmt"
5 "strings"
6
7 "github.com/softlayer/softlayer-go/datatypes"
8 "github.com/softlayer/softlayer-go/services"
9 "github.com/softlayer/softlayer-go/session"
10 "github.com/softlayer/softlayer-go/sl"
11 )
12
13 type Wrapper struct {
14 session *session.Session
15 }
16
17 func NewWrapper(sess *session.Session) *Wrapper {
18 return &Wrapper{session: sess}
19 }
20
21 func (w Wrapper) AddTXTRecord(fqdn, domain, value string, ttl int) error {
22 service := services.GetDnsDomainService(w.session)
23
24 domainID, err := getDomainID(service, domain)
25 if err != nil {
26 return fmt.Errorf("failed to get domain ID: %w", err)
27 }
28
29 service.Options.Id = domainID
30
31 if _, err := service.CreateTxtRecord(sl.String(fqdn), sl.String(value), sl.Int(ttl)); err != nil {
32 return fmt.Errorf("failed to create TXT record: %w", err)
33 }
34
35 return nil
36 }
37
38 func (w Wrapper) CleanupTXTRecord(fqdn, domain string) error {
39 service := services.GetDnsDomainService(w.session)
40
41 domainID, err := getDomainID(service, domain)
42 if err != nil {
43 return fmt.Errorf("failed to get domain ID: %w", err)
44 }
45
46 service.Options.Id = domainID
47
48 records, err := findTxtRecords(service, fqdn)
49 if err != nil {
50 return fmt.Errorf("failed to find TXT records: %w", err)
51 }
52
53 return deleteResourceRecords(service, records)
54 }
55
56 func getDomainID(service services.Dns_Domain, domain string) (*int, error) {
57 res, err := service.GetByDomainName(sl.String(domain))
58 if err != nil {
59 return nil, err
60 }
61
62 for _, r := range res {
63 if r.Id == nil || toString(r.Name) != domain {
64 continue
65 }
66
67 return r.Id, nil
68 }
69
70 // The domain was not found by name.
71 // For subdomains this is not unusual in softlayer.
72 // So in case a subdomain like `sub.toplevel.tld` was used try again using the parent domain
73 // (strip the first part in the domain string -> `toplevel.tld`).
74 _, parent, found := strings.Cut(domain, ".")
75 if !found || !strings.Contains(parent, ".") {
76 return nil, fmt.Errorf("no data found for domain: %s", domain)
77 }
78
79 return getDomainID(service, parent)
80 }
81
82 func findTxtRecords(service services.Dns_Domain, fqdn string) ([]datatypes.Dns_Domain_ResourceRecord, error) {
83 var results []datatypes.Dns_Domain_ResourceRecord
84
85 records, err := service.GetResourceRecords()
86 if err != nil {
87 return nil, err
88 }
89
90 for _, record := range records {
91 if toString(record.Host) == fqdn && toString(record.Type) == "txt" {
92 results = append(results, record)
93 }
94 }
95
96 if len(results) == 0 {
97 return nil, fmt.Errorf("no data found of fqdn: %s", fqdn)
98 }
99
100 return results, nil
101 }
102
103 func deleteResourceRecords(service services.Dns_Domain, records []datatypes.Dns_Domain_ResourceRecord) error {
104 resourceRecord := services.GetDnsDomainResourceRecordService(service.Session)
105
106 // TODO maybe a bug: only the last record will be deleted
107 for _, record := range records {
108 resourceRecord.Options.Id = record.Id
109 }
110
111 _, err := resourceRecord.DeleteObject()
112 if err != nil {
113 return fmt.Errorf("no data found of fqdn: %w", err)
114 }
115
116 return nil
117 }
118
119 func toString(v *string) string {
120 if v == nil {
121 return ""
122 }
123
124 return *v
125 }
126