-
Notifications
You must be signed in to change notification settings - Fork 0
/
actions.go
152 lines (138 loc) · 4.93 KB
/
actions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Package hoverdnsapi offers some API actions to control your Hover/TuCOWS DNS entries
// programmatically. This isn't a supported utility form Hover, it's just a thing I wrote because
// I needed it at the time.
package hoverdnsapi
import (
"fmt"
"net/url"
)
// HoverAct is simply an enum type to typecheck various actions we can perform in a queue
type HoverAct int
const (
// Error is the zero-value, catch a fencepost error
Error HoverAct = iota
// Add a domain record
Add
// Delete of a record will require the list of records
Delete
// Update will also need the list of records and IDs
Update
// Expand is an internal state that will expand a domain to include entries
Expand
)
// String of course gives a string representation of the Act code
func (h HoverAct) String() string {
switch h {
case Error:
return "--Error--"
case Add:
return "Add"
case Delete:
return "Delete"
case Update:
return "Update"
case Expand:
return "--Expand--"
}
return "(error) HoverAct const extended without String() equivalent"
}
// Action is a single action (Add, Update, Delete) to complete in a DoActions() call
type Action struct {
action HoverAct
fqdn string
domain string
value string
ttl uint
}
func (a Action) String() string {
return fmt.Sprintf("{action:%s domain:%s fqdn:%s, value:%s ttl:%d}", a.action, a.domain, a.fqdn, a.value, a.ttl)
}
// NewAction returns a newly-created Action as a way to allow external access to create actions
// during test runs using cmd/hoverdns app
func NewAction(action HoverAct, fqdn, domain, value string, ttl uint) Action {
return Action{action: action, fqdn: fqdn, domain: domain, value: value, ttl: ttl}
}
// DoActions is a way to burn down an accumulated list of actions. Mostly, this stack will be one
// or two deep, but this offers the chance to go grab a GetAuth() (for authentication cookie) if
// needed, or a detailed DNS list if needed, in a sort of lazy-evaluation logic that avoid these
// actions if not needed.
func (c *Client) DoActions(actions ...Action) (err error) {
var expansion = map[HoverAct]bool{
Error: false,
Add: false,
Delete: true,
Update: true,
Expand: false, // of course
}
// precondition the steps: prepend expansion where needed
newActions := make([]Action, 0)
for n, a := range actions {
if b, ok := expansion[a.action]; ok && b {
add := Action{action: Expand, domain: a.domain}
c.log.Printf("current action (%d), %+v pre-pending %+v", n, a, add)
newActions = append(newActions, add)
} else {
c.log.Printf("current action (%d), %+v no pre-pending", n, a)
}
if a.action == Update { // I just could NOT get update to work, so delete and re-add. Sorry.
// NOTE: deleting and re-adding in dumbest way possible to incentivize me to fix it ;)
newActions = append(newActions, Action{action: Delete, fqdn: a.fqdn, domain: a.domain})
newActions = append(newActions, Action{action: Add, fqdn: a.fqdn, domain: a.domain, value: a.value, ttl: a.ttl})
} else {
newActions = append(newActions, a)
}
}
for n, a := range newActions {
c.log.Printf("resulting actions (%d), %+v", n, a)
}
if len(c.domains.Domains) < 1 { // todo make an action in newActions
if err = c.FillDomains(); err != nil {
return err
}
}
// {
// action:2 fqdn:_acme-challenge.domain.com domain: domain.com
// value:xzLAGicQ1PtUwmXLyCsagNI7O4m_Zsn8mcVREy7QrfY ttl:3600
// }
for actnum, a := range newActions {
if domain, ok := c.GetDomainByName(a.domain); ok {
fmt.Printf("Action Stack pre (%02d): [%s]\n", actnum, a)
switch a.action {
case Error:
return fmt.Errorf("Error: unset action code: %+v", a)
case Add:
if resp, err := c.HTTPClient.PostForm(APIURLDNS(domain.ID), url.Values{
"name": {a.fqdn},
"type": {"TXT"},
"content": {a.value},
}); err != nil {
fmt.Printf("hover: Info: posting threw: [%+v]\n", err)
} else {
resp.Body.Close()
domain.Entries = make([]Entry, 0) // discard to force refresh on demand
}
case Delete:
if len(domain.Entries) < 1 {
c.log.Printf(`NOTE: entries for domain "%s" are empty`, domain.DomainName)
} else if e, ok := domain.GetEntryByFQDN(a.fqdn); !ok {
c.log.Printf(`NOTE: FQDN "%s" in domain "%s" not found`, a.fqdn, domain.DomainName)
} else if err := c.HTTPDelete(fmt.Sprintf("%s/%s", APIURLDNS(domain.ID), e.ID)); err != nil {
c.log.Printf("hover: Info: deleting threw: [%+v]\n", err)
}
// As above, I just couldn't get Update to work, so I've doing a delete/add swapped above. Therefore Update here should just fall-through
//case Update:
case Expand:
if len(domain.Entries) < 1 {
if err := c.GetDomainEntries(a.domain); err != nil {
return fmt.Errorf("Domain %s not extended: %v", a.domain, err)
}
}
}
fmt.Printf("Action Stack post (%02d): [%s]\n", actnum, a)
} else {
c.log.Printf("domain %s not found", a.domain)
return fmt.Errorf("Domain %s not found in domains", a.domain)
}
}
return nil
}