@@ -10,6 +10,7 @@ import (
10
10
"log"
11
11
12
12
"github.com/cloudflare/cloudflare-go"
13
+ "github.com/hashicorp/go-tfe"
13
14
"github.com/spf13/cobra"
14
15
"github.com/spf13/viper"
15
16
)
@@ -18,26 +19,49 @@ type DnsCommand struct {
18
19
cfClient * cloudflare.API
19
20
cfZone * cloudflare.ResourceContainer
20
21
domainName string
22
+ tfcOrg string
23
+ tfcToken string
21
24
testMode bool
22
25
}
23
26
27
+ type AlbDnsValues struct {
28
+ internal string
29
+ external string
30
+ }
31
+
24
32
func InitDnsCmd (parentCmd * cobra.Command ) {
25
- parentCmd .AddCommand (& cobra.Command {
33
+ var failback bool
34
+
35
+ cmd := & cobra.Command {
26
36
Use : "dns" ,
27
37
Short : "DNS Failover and Failback" ,
28
- Long : `Configure DNS CNAME values for primary or secondary region hostnames` ,
38
+ Long : `Configure DNS CNAME values for primary or secondary region hostnames. Default is failover, use --failback to switch back to the primary region. ` ,
29
39
Run : func (cmd * cobra.Command , args []string ) {
30
- runDnsCommand ()
40
+ runDnsCommand (failback )
31
41
},
32
- })
42
+ }
43
+ parentCmd .AddCommand (cmd )
44
+
45
+ cmd .PersistentFlags ().BoolVar (& failback , "failback" , false ,
46
+ `set DNS records to switch back to primary` ,
47
+ )
33
48
}
34
49
35
- func runDnsCommand () {
50
+ func runDnsCommand (failback bool ) {
36
51
pFlags := getPersistentFlags ()
37
52
38
- f := newDnsCommand (pFlags )
53
+ d := newDnsCommand (pFlags )
54
+
55
+ var clusterWorkspaceName string
56
+ if failback {
57
+ clusterWorkspaceName = clusterWorkspace (pFlags )
58
+ } else {
59
+ clusterWorkspaceName = clusterSecondaryWorkspace (pFlags )
60
+ }
39
61
40
- f .setDnsToSecondary (pFlags .idp )
62
+ dnsValues := d .getAlbDnsValuesFromTfc (clusterWorkspaceName )
63
+
64
+ d .setDnsRecordValues (pFlags .idp , dnsValues , failback )
41
65
}
42
66
43
67
func newDnsCommand (pFlags PersistentFlags ) * DnsCommand {
@@ -68,38 +92,44 @@ func newDnsCommand(pFlags PersistentFlags) *DnsCommand {
68
92
fmt .Printf ("Using domain name %s with ID %s\n " , d .domainName , zoneID )
69
93
d .cfZone = cloudflare .ZoneIdentifier (zoneID )
70
94
95
+ d .tfcToken = pFlags .tfcToken
96
+ d .tfcOrg = pFlags .org
97
+
71
98
return & d
72
99
}
73
100
74
- func (d * DnsCommand ) setDnsToSecondary (idpKey string ) {
75
- fmt .Println ("Setting DNS records to secondary..." )
101
+ func (d * DnsCommand ) setDnsRecordValues (idpKey string , dnsValues AlbDnsValues , failback bool ) {
102
+ if failback {
103
+ fmt .Println ("Setting DNS records to primary region..." )
104
+ } else {
105
+ fmt .Println ("Setting DNS records to secondary region..." )
106
+ }
76
107
77
108
dnsRecords := []struct {
78
- optionName string
79
- defaultName string
80
- optionValue string
109
+ name string
110
+ optionValue string
111
+ defaultValue string
81
112
}{
82
113
// "mfa-api" is the TOTP API, also known as serverless-mfa-api
83
- {"mfa-api-name " , "mfa-api" , "mfa-api-value " },
114
+ {"mfa-api" , "mfa-api-value " , "" },
84
115
85
116
// "twosv-api" is the Webauthn API, also known as serverless-mfa-api-go
86
- {"twosv-api-name " , "twosv-api" , "twosv-api-value " },
117
+ {"twosv-api" , "twosv-api-value " , "" },
87
118
88
119
// "support-bot" is the idp-support-bot API that is configured in the Slack API dashboard
89
- {"support-bot-name" , " sherlock" , "support-bot-value" },
120
+ {"sherlock" , "support-bot-value" , " " },
90
121
91
122
// ECS services
92
- {"email-service-name" , idpKey + "-email-service " , "email-service-value" },
93
- {"id-broker-name" , idpKey + "-id- broker" , "id-broker-value" },
94
- {"pw-api-name" , idpKey + "-pw-api" , "pw-api-value" },
95
- {"ssp-name" , idpKey + "-ssp" , "ssp-value" },
96
- {"id-sync-name" , idpKey + "-id- sync" , "id-sync-value" },
123
+ {idpKey + "-email" , "email-service-value" , dnsValues . internal },
124
+ {idpKey + "-broker" , "id-broker-value" , dnsValues . internal },
125
+ {idpKey + "-pw-api" , "pw-api-value" , dnsValues . external },
126
+ {idpKey , "ssp-value" , dnsValues . external },
127
+ {idpKey + "-sync" , "id-sync-value" , dnsValues . external },
97
128
}
98
129
99
130
for _ , record := range dnsRecords {
100
- name := getOption (record .optionName , record .defaultName )
101
- value := getOption (record .optionValue , "" )
102
- d .setCloudflareCname (name , value )
131
+ value := getOption (record .optionValue , record .defaultValue )
132
+ d .setCloudflareCname (record .name , value )
103
133
}
104
134
}
105
135
@@ -127,7 +157,7 @@ func (d *DnsCommand) setCloudflareCname(name, value string) {
127
157
}
128
158
129
159
if d .testMode {
130
- fmt .Println (" test mode: skipping API call" )
160
+ fmt .Println (" read-only mode: skipping API call" )
131
161
return
132
162
}
133
163
@@ -146,3 +176,41 @@ func (d *DnsCommand) setCloudflareCname(name, value string) {
146
176
log .Fatalf ("error updating DNS record %s: %s" , name , err )
147
177
}
148
178
}
179
+
180
+ func (d * DnsCommand ) getAlbDnsValuesFromTfc (workspaceName string ) (values AlbDnsValues ) {
181
+ config := & tfe.Config {
182
+ Token : d .tfcToken ,
183
+ RetryServerErrors : true ,
184
+ }
185
+
186
+ client , err := tfe .NewClient (config )
187
+ if err != nil {
188
+ fmt .Printf ("Error creating Terraform client: %s" , err )
189
+ return
190
+ }
191
+
192
+ ctx := context .Background ()
193
+
194
+ w , err := client .Workspaces .Read (ctx , d .tfcOrg , workspaceName )
195
+ if err != nil {
196
+ fmt .Printf ("Error reading Terraform workspace %s: %s" , workspaceName , err )
197
+ return
198
+ }
199
+
200
+ outputs , err := client .StateVersionOutputs .ReadCurrent (ctx , w .ID )
201
+ if err != nil {
202
+ fmt .Printf ("Error reading Terraform state outputs on workspace %s: %s" , workspaceName , err )
203
+ return
204
+ }
205
+
206
+ for _ , item := range outputs .Items {
207
+ itemValue , _ := item .Value .(string )
208
+ switch item .Name {
209
+ case "alb_dns_name" :
210
+ values .external = itemValue
211
+ case "internal_alb_dns_name" :
212
+ values .internal = itemValue
213
+ }
214
+ }
215
+ return
216
+ }
0 commit comments