@@ -16,17 +16,23 @@ import (
16
16
)
17
17
18
18
type DnsCommand struct {
19
- cfClient * cloudflare.API
20
- cfZone * cloudflare.ResourceContainer
21
- domainName string
22
- tfcOrg string
23
- tfcToken string
24
- testMode bool
19
+ cfClient * cloudflare.API
20
+ cfZone * cloudflare.ResourceContainer
21
+ domainName string
22
+ failback bool
23
+ tfcOrg string
24
+ tfcOrgAlt string
25
+ tfcToken string
26
+ tfcTokenAlt string
27
+ testMode bool
25
28
}
26
29
27
- type AlbDnsValues struct {
28
- internal string
29
- external string
30
+ type DnsValues struct {
31
+ albInternal string
32
+ albExternal string
33
+ bot string
34
+ mfa string
35
+ twosv string
30
36
}
31
37
32
38
func InitDnsCmd (parentCmd * cobra.Command ) {
@@ -50,24 +56,16 @@ func InitDnsCmd(parentCmd *cobra.Command) {
50
56
func runDnsCommand (failback bool ) {
51
57
pFlags := getPersistentFlags ()
52
58
53
- d := newDnsCommand (pFlags )
59
+ d := newDnsCommand (pFlags , failback )
54
60
55
- var clusterWorkspaceName string
56
- if failback {
57
- clusterWorkspaceName = clusterWorkspace (pFlags )
58
- } else {
59
- clusterWorkspaceName = clusterSecondaryWorkspace (pFlags )
60
- }
61
-
62
- dnsValues := d .getAlbDnsValuesFromTfc (clusterWorkspaceName )
63
-
64
- d .setDnsRecordValues (pFlags .idp , dnsValues , failback )
61
+ values := d .getDnsValuesFromTfc (pFlags )
62
+ d .setDnsRecordValues (pFlags .idp , values )
65
63
}
66
64
67
- func newDnsCommand (pFlags PersistentFlags ) * DnsCommand {
65
+ func newDnsCommand (pFlags PersistentFlags , failback bool ) * DnsCommand {
68
66
d := DnsCommand {
69
67
testMode : pFlags .readOnlyMode ,
70
- domainName : viper .GetString ("domain-name" ),
68
+ domainName : viper .GetString (flagDomainName ),
71
69
}
72
70
73
71
if d .domainName == "" {
@@ -93,46 +91,56 @@ func newDnsCommand(pFlags PersistentFlags) *DnsCommand {
93
91
d .cfZone = cloudflare .ZoneIdentifier (zoneID )
94
92
95
93
d .tfcToken = pFlags .tfcToken
94
+ d .tfcTokenAlt = pFlags .tfcTokenAlt
96
95
d .tfcOrg = pFlags .org
96
+ d .tfcOrgAlt = pFlags .orgAlt
97
+ d .failback = failback
97
98
98
99
return & d
99
100
}
100
101
101
- func (d * DnsCommand ) setDnsRecordValues (idpKey string , dnsValues AlbDnsValues , failback bool ) {
102
- if failback {
102
+ func (d * DnsCommand ) setDnsRecordValues (idpKey string , dnsValues DnsValues ) {
103
+ if d . failback {
103
104
fmt .Println ("Setting DNS records to primary region..." )
104
105
} else {
105
106
fmt .Println ("Setting DNS records to secondary region..." )
106
107
}
107
108
108
109
dnsRecords := []struct {
109
- name string
110
- optionValue string
111
- defaultValue string
110
+ name string
111
+ valueFlag string
112
+ tfcValue string
112
113
}{
113
114
// "mfa-api" is the TOTP API, also known as serverless-mfa-api
114
- {"mfa-api" , "mfa-api-value" , "" },
115
+ {"mfa-api" , "mfa-api-value" , dnsValues . mfa },
115
116
116
117
// "twosv-api" is the Webauthn API, also known as serverless-mfa-api-go
117
- {"twosv-api" , "twosv-api-value" , "" },
118
+ {"twosv-api" , "twosv-api-value" , dnsValues . twosv },
118
119
119
120
// "support-bot" is the idp-support-bot API that is configured in the Slack API dashboard
120
- {"sherlock" , "support-bot-value" , "" },
121
+ {"sherlock" , "support-bot-value" , dnsValues . bot },
121
122
122
123
// ECS services
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 },
124
+ {idpKey + "-email" , "email-service-value" , dnsValues .albInternal },
125
+ {idpKey + "-broker" , "id-broker-value" , dnsValues .albInternal },
126
+ {idpKey + "-pw-api" , "pw-api-value" , dnsValues .albExternal },
127
+ {idpKey , "ssp-value" , dnsValues .albExternal },
128
+ {idpKey + "-sync" , "id-sync-value" , dnsValues .albExternal },
128
129
}
129
130
130
131
for _ , record := range dnsRecords {
131
- value := getOption (record .optionValue , record .defaultValue )
132
+ value := getDnsValue (record .valueFlag , record .tfcValue )
132
133
d .setCloudflareCname (record .name , value )
133
134
}
134
135
}
135
136
137
+ func getDnsValue (valueFlag , tfcValue string ) string {
138
+ if tfcValue != "" {
139
+ return tfcValue
140
+ }
141
+ return viper .GetString (valueFlag )
142
+ }
143
+
136
144
func (d * DnsCommand ) setCloudflareCname (name , value string ) {
137
145
if value == "" {
138
146
fmt .Printf (" skipping %s (no value provided)\n " , name )
@@ -177,27 +185,48 @@ func (d *DnsCommand) setCloudflareCname(name, value string) {
177
185
}
178
186
}
179
187
180
- func (d * DnsCommand ) getAlbDnsValuesFromTfc (workspaceName string ) (values AlbDnsValues ) {
181
- config := & tfe.Config {
182
- Token : d .tfcToken ,
183
- RetryServerErrors : true ,
188
+ func (d * DnsCommand ) getDnsValuesFromTfc (pFlags PersistentFlags ) (values DnsValues ) {
189
+ ctx := context .Background ()
190
+
191
+ var clusterWorkspaceName string
192
+ if d .failback {
193
+ clusterWorkspaceName = clusterWorkspace (pFlags )
194
+ } else {
195
+ clusterWorkspaceName = clusterSecondaryWorkspace (pFlags )
184
196
}
185
197
186
- client , err := tfe .NewClient (config )
187
- if err != nil {
188
- fmt .Printf ("Error creating Terraform client: %s" , err )
189
- return
198
+ internal , external := d .getAlbValuesFromTfc (ctx , clusterWorkspaceName )
199
+ values .albInternal = internal
200
+ values .albExternal = external
201
+
202
+ bot := "idp-support-bot-prod"
203
+ if pFlags .env != envProd {
204
+ bot = "idp-support-bot-dev" // TODO: consider renaming the workspace name so this can be simplified
190
205
}
206
+ values .bot = d .getLambdaDnsValueFromTfc (ctx , bot )
191
207
192
- ctx := context .Background ()
208
+ twosv := "serverless-mfa-api-go-prod"
209
+ if pFlags .env != envProd {
210
+ twosv = "serverless-mfa-api-go-dev" // TODO: consider renaming the workspace name so this can be simplified
211
+ }
212
+ values .twosv = d .getLambdaDnsValueFromTfc (ctx , twosv )
193
213
194
- w , err := client .Workspaces .Read (ctx , d .tfcOrg , workspaceName )
214
+ mfa := "serverless-mfa-api-prod"
215
+ if pFlags .env != envProd {
216
+ mfa = "serverless-mfa-api-dev" // TODO: consider renaming the workspace name so this can be simplified
217
+ }
218
+ values .mfa = d .getLambdaDnsValueFromTfc (ctx , mfa )
219
+ return
220
+ }
221
+
222
+ func (d * DnsCommand ) getAlbValuesFromTfc (ctx context.Context , workspaceName string ) (internal , external string ) {
223
+ workspaceID , client , err := d .findTfcWorkspace (ctx , workspaceName )
195
224
if err != nil {
196
- fmt .Printf ("Error reading Terraform workspace %s : %s" , workspaceName , err )
225
+ fmt .Printf ("Failed to get ALB DNS values : %s\n Will use DNS config values if provided. \n " , err )
197
226
return
198
227
}
199
228
200
- outputs , err := client .StateVersionOutputs .ReadCurrent (ctx , w . ID )
229
+ outputs , err := client .StateVersionOutputs .ReadCurrent (ctx , workspaceID )
201
230
if err != nil {
202
231
fmt .Printf ("Error reading Terraform state outputs on workspace %s: %s" , workspaceName , err )
203
232
return
@@ -207,10 +236,88 @@ func (d *DnsCommand) getAlbDnsValuesFromTfc(workspaceName string) (values AlbDns
207
236
itemValue , _ := item .Value .(string )
208
237
switch item .Name {
209
238
case "alb_dns_name" :
210
- values . external = itemValue
239
+ external = itemValue
211
240
case "internal_alb_dns_name" :
212
- values . internal = itemValue
241
+ internal = itemValue
213
242
}
214
243
}
215
244
return
216
245
}
246
+
247
+ func (d * DnsCommand ) getLambdaDnsValueFromTfc (ctx context.Context , workspaceName string ) string {
248
+ outputName := "secondary_region_domain_name"
249
+ if d .failback {
250
+ outputName = "primary_region_domain_name"
251
+ }
252
+ return d .getTfcOutputFromWorkspace (ctx , workspaceName , outputName )
253
+ }
254
+
255
+ func (d * DnsCommand ) getTfcOutputFromWorkspace (ctx context.Context , workspaceName , outputName string ) string {
256
+ workspaceID , client , err := d .findTfcWorkspace (ctx , workspaceName )
257
+ if err != nil {
258
+ fmt .Printf ("Failed to get DNS value from %s: %s\n Will use config value if provided.\n " , workspaceName , err )
259
+ return ""
260
+ }
261
+
262
+ outputs , err := client .StateVersionOutputs .ReadCurrent (ctx , workspaceID )
263
+ if err != nil {
264
+ fmt .Printf ("Error reading Terraform state outputs on workspace %s: %s" , workspaceName , err )
265
+ return ""
266
+ }
267
+
268
+ for _ , item := range outputs .Items {
269
+ if item .Name == outputName {
270
+ if itemValue , ok := item .Value .(string ); ok {
271
+ return itemValue
272
+ }
273
+ break
274
+ }
275
+ }
276
+
277
+ fmt .Printf ("Value for %s not found in %s\n " , outputName , workspaceName )
278
+ return ""
279
+ }
280
+
281
+ // findTfcWorkspace looks for a workspace by name in two different Terraform Cloud accounts and returns
282
+ // the workspace ID and an API client for the account where the workspace was found
283
+ func (d * DnsCommand ) findTfcWorkspace (ctx context.Context , workspaceName string ) (id string , client * tfe.Client , err error ) {
284
+ config := & tfe.Config {
285
+ Token : d .tfcToken ,
286
+ RetryServerErrors : true ,
287
+ }
288
+
289
+ client , err = tfe .NewClient (config )
290
+ if err != nil {
291
+ err = fmt .Errorf ("error creating Terraform client: %s" , err )
292
+ return
293
+ }
294
+
295
+ w , err := client .Workspaces .Read (ctx , d .tfcOrg , workspaceName )
296
+ if err == nil {
297
+ id = w .ID
298
+ return
299
+ }
300
+
301
+ if d .tfcTokenAlt == "" {
302
+ err = fmt .Errorf ("error reading Terraform workspace %s: %s" , workspaceName , err )
303
+ return
304
+ }
305
+
306
+ fmt .Printf ("Workspace %s not found using %s, trying %s\n " , workspaceName , flagTfcToken , flagTfcTokenAlternate )
307
+
308
+ config .Token = d .tfcTokenAlt
309
+ client , err = tfe .NewClient (config )
310
+ if err != nil {
311
+ err = fmt .Errorf ("error creating alternate Terraform client: %s" , err )
312
+ return
313
+ }
314
+
315
+ w , err = client .Workspaces .Read (ctx , d .tfcOrgAlt , workspaceName )
316
+ if err != nil {
317
+ err = fmt .Errorf ("error reading Terraform workspace %s using %s: %s" , workspaceName , flagTfcTokenAlternate , err )
318
+ return
319
+ }
320
+
321
+ id = w .ID
322
+ return
323
+ }
0 commit comments