Skip to content

Commit dc1230d

Browse files
committed
Update main.go
1 parent 2fde03d commit dc1230d

File tree

1 file changed

+93
-55
lines changed

1 file changed

+93
-55
lines changed

main.go

Lines changed: 93 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,44 @@ func init() {
2020
DisableColors: true,
2121
FullTimestamp: true,
2222
})
23+
// Set log level based on environment variable or default to info
24+
logLevel := os.Getenv("LOG_LEVEL")
25+
if logLevel != "" {
26+
level, err := log.ParseLevel(logLevel)
27+
if err == nil {
28+
log.SetLevel(level)
29+
}
30+
}
2331
}
2432

2533
func main() {
26-
// Initialize Cloudflare API client
34+
// Validate required environment variables
35+
requiredEnvVars := []string{
36+
"CLOUDFLARE_API_TOKEN",
37+
"CLOUDFLARE_ACCOUNT_ID",
38+
"CLOUDFLARE_TUNNEL_ID",
39+
"CLOUDFLARE_ZONE_ID",
40+
"TRAEFIK_SERVICE_ENDPOINT",
41+
"TRAEFIK_API_ENDPOINT",
42+
}
43+
44+
for _, envVar := range requiredEnvVars {
45+
if os.Getenv(envVar) == "" {
46+
log.Fatalf("Required environment variable %s is not set", envVar)
47+
}
48+
}
49+
2750
cf, err := cloudflare.NewWithAPIToken(os.Getenv("CLOUDFLARE_API_TOKEN"))
2851
if err != nil {
2952
log.Fatal(err)
3053
}
3154

3255
ctx := context.Background()
3356

34-
// Set up Traefik API client
3557
client := resty.New().
36-
SetBaseURL(os.Getenv("TRAEFIK_API_ENDPOINT"))
58+
SetBaseURL(os.Getenv("TRAEFIK_API_ENDPOINT")).
59+
SetTimeout(10 * time.Second).
60+
SetRetryCount(3)
3761

3862
pollCh := pollTraefikRouters(client)
3963
var cache []Router
@@ -42,95 +66,108 @@ func main() {
4266
log.Fatal(poll.Err)
4367
}
4468

45-
// Skip if no changes to Traefik routers
69+
// skip if no changes to traefik routers
4670
if reflect.DeepEqual(cache, poll.Routers) {
4771
continue
4872
}
4973

5074
log.Info("changes detected")
5175

52-
// Update the cache
76+
// update the cache
5377
cache = poll.Routers
5478

55-
// Collect unique domains from applicable routers
56-
uniqueDomains := make(map[string]struct{})
79+
ingress := []cloudflare.UnvalidatedIngressRule{}
80+
5781
for _, r := range poll.Routers {
58-
// Filter routers
82+
// Only enabled routes
5983
if r.Status != "enabled" {
60-
continue
61-
}
62-
if !contains(r.EntryPoints, os.Getenv("TRAEFIK_ENTRYPOINT")) {
84+
log.Debugf("Skipping disabled route: %s", r.Rule)
6385
continue
6486
}
6587

66-
// Log if router has TLS configured for debugging
67-
if r.TLS.CertResolver != "" {
68-
log.WithFields(log.Fields{
69-
"router": r.ServiceName,
70-
"rule": r.Rule,
71-
}).Warn("router has TLS configured but is included for tunnel")
88+
// Handle both HTTP and HTTPS routes
89+
// We want to include all routes, including those with TLS configured
90+
if os.Getenv("TRAEFIK_ENTRYPOINT") != "" {
91+
// If TRAEFIK_ENTRYPOINT is specified, only use routes with that entrypoint
92+
if !contains(r.EntryPoints, os.Getenv("TRAEFIK_ENTRYPOINT")) {
93+
log.Debugf("Skipping route with different entrypoint: %s", r.Rule)
94+
continue
95+
}
7296
}
7397

7498
domains, err := http.ParseDomains(r.Rule)
7599
if err != nil {
76-
log.WithFields(log.Fields{
77-
"rule": r.Rule,
78-
}).Fatal("failed to parse domains: ", err)
100+
log.Errorf("Failed to parse domains from rule %s: %v", r.Rule, err)
101+
continue
79102
}
103+
80104
for _, domain := range domains {
81-
uniqueDomains[domain] = struct{}{}
105+
log.WithFields(log.Fields{
106+
"domain": domain,
107+
"service": os.Getenv("TRAEFIK_SERVICE_ENDPOINT"),
108+
"tls": r.TLS.CertResolver != "",
109+
}).Info("upserting tunnel")
110+
111+
ingress = append(ingress, cloudflare.UnvalidatedIngressRule{
112+
Hostname: domain,
113+
Service: os.Getenv("TRAEFIK_SERVICE_ENDPOINT"),
114+
OriginRequest: &cloudflare.OriginRequestConfig{
115+
HTTPHostHeader: &domain,
116+
// Add other origin request options if needed
117+
NoTLSVerify: boolPtr(true), // Skip TLS verification for internal traffic
118+
},
119+
})
82120
}
83121
}
84122

85-
// Build ingress rules from unique domains
86-
ingress := []cloudflare.UnvalidatedIngressRule{}
87-
for domain := range uniqueDomains {
88-
log.WithFields(log.Fields{
89-
"domain": domain,
90-
"service": os.Getenv("TRAEFIK_SERVICE_ENDPOINT"),
91-
}).Info("adding ingress rule")
92-
93-
ingress = append(ingress, cloudflare.UnvalidatedIngressRule{
94-
Hostname: domain,
95-
Service: os.Getenv("TRAEFIK_SERVICE_ENDPOINT"),
96-
OriginRequest: &cloudflare.OriginRequestConfig{
97-
HTTPHostHeader: &domain,
98-
},
99-
})
100-
}
101-
102-
// Add catch-all rule
123+
// add catch-all rule
103124
ingress = append(ingress, cloudflare.UnvalidatedIngressRule{
104125
Service: "http_status:404",
105126
})
106127

107-
// Update Cloudflare tunnel configuration
108128
err = updateTunnels(ctx, cf, ingress)
109129
if err != nil {
110130
log.Fatal(err)
111131
}
112132
}
113133
}
114134

115-
// pollTraefikRouters and updateTunnels remain unchanged but are included for completeness
135+
// Helper to create a bool pointer
136+
func boolPtr(b bool) *bool {
137+
return &b
138+
}
139+
116140
func pollTraefikRouters(client *resty.Client) (ch chan PollResponse) {
117141
ch = make(chan PollResponse)
118142
go func() {
119-
defer close(ch)
120-
r := rand.New(rand.NewSource(99))
143+
defer func() {
144+
close(ch)
145+
}()
146+
r := rand.New(rand.NewSource(time.Now().UnixNano()))
121147
c := time.Tick(10 * time.Second)
122148

123149
for range c {
124150
var pollRes PollResponse
125151

126-
_, pollRes.Err = client.R().
152+
resp, err := client.R().
127153
EnableTrace().
128154
SetResult(&pollRes.Routers).
129155
Get("/api/http/routers")
130156

131-
if pollRes.Err != nil {
157+
pollRes.Err = err
158+
if err != nil {
159+
log.Errorf("Error polling Traefik API: %v", err)
132160
ch <- pollRes
133-
break
161+
time.Sleep(5 * time.Second) // Wait before retrying
162+
continue
163+
}
164+
165+
if resp.StatusCode() != 200 {
166+
log.Errorf("Unexpected status code from Traefik API: %d", resp.StatusCode())
167+
pollRes.Err = fmt.Errorf("unexpected status code: %d", resp.StatusCode())
168+
ch <- pollRes
169+
time.Sleep(5 * time.Second) // Wait before retrying
170+
continue
134171
}
135172

136173
ch <- pollRes
@@ -143,32 +180,33 @@ func pollTraefikRouters(client *resty.Client) (ch chan PollResponse) {
143180
}
144181

145182
func updateTunnels(ctx context.Context, cf *cloudflare.API, ingress []cloudflare.UnvalidatedIngressRule) error {
146-
// Get current tunnel config
183+
// Get Current tunnel config
147184
aid := cloudflare.AccountIdentifier(os.Getenv("CLOUDFLARE_ACCOUNT_ID"))
148185
cfg, err := cf.GetTunnelConfiguration(ctx, aid, os.Getenv("CLOUDFLARE_TUNNEL_ID"))
149186
if err != nil {
150-
return fmt.Errorf("unable to pull current tunnel config: %s", err)
187+
return fmt.Errorf("unable to pull current tunnel config, %s", err.Error())
151188
}
152189

153190
// Update config with new ingress rules
154191
cfg.Config.Ingress = ingress
155-
_, err = cf.UpdateTunnelConfiguration(ctx, aid, cloudflare.TunnelConfigurationParams{
192+
cfg, err = cf.UpdateTunnelConfiguration(ctx, aid, cloudflare.TunnelConfigurationParams{
156193
TunnelID: os.Getenv("CLOUDFLARE_TUNNEL_ID"),
157194
Config: cfg.Config,
158195
})
159196
if err != nil {
160-
return fmt.Errorf("unable to update tunnel config: %s", err)
197+
return fmt.Errorf("unable to update tunnel config, %s", err.Error())
161198
}
162199

163200
log.Info("tunnel config updated")
164201

165-
// Update DNS records
202+
// Update DNS to point to new tunnel
166203
for _, i := range ingress {
167204
if i.Hostname == "" {
168205
continue
169206
}
170207

171208
var proxied bool = true
209+
172210
record := cloudflare.DNSRecord{
173211
Type: "CNAME",
174212
Name: i.Hostname,
@@ -180,7 +218,7 @@ func updateTunnels(ctx context.Context, cf *cloudflare.API, ingress []cloudflare
180218
zid := cloudflare.ZoneIdentifier(os.Getenv("CLOUDFLARE_ZONE_ID"))
181219
r, _, err := cf.ListDNSRecords(ctx, zid, cloudflare.ListDNSRecordsParams{Name: i.Hostname})
182220
if err != nil {
183-
return fmt.Errorf("error checking DNS records: %s", err)
221+
return fmt.Errorf("err checking DNS records, %s", err.Error())
184222
}
185223

186224
if len(r) == 0 {
@@ -192,7 +230,7 @@ func updateTunnels(ctx context.Context, cf *cloudflare.API, ingress []cloudflare
192230
Proxied: record.Proxied,
193231
})
194232
if err != nil {
195-
return fmt.Errorf("unable to create DNS record: %s", err)
233+
return fmt.Errorf("unable to create DNS record, %s", err.Error())
196234
}
197235
log.WithFields(log.Fields{
198236
"domain": record.Name,
@@ -202,15 +240,15 @@ func updateTunnels(ctx context.Context, cf *cloudflare.API, ingress []cloudflare
202240

203241
if r[0].Content != record.Content {
204242
_, err = cf.UpdateDNSRecord(ctx, zid, cloudflare.UpdateDNSRecordParams{
205-
ID: r[0].ID, // Use existing record ID
243+
ID: r[0].ID, // Use the actual ID from the retrieved record
206244
Name: record.Name,
207245
Type: record.Type,
208246
Content: record.Content,
209247
TTL: record.TTL,
210248
Proxied: record.Proxied,
211249
})
212250
if err != nil {
213-
return fmt.Errorf("could not update record for %s: %s", i.Hostname, err)
251+
return fmt.Errorf("could not update record for %s, %s", i.Hostname, err)
214252
}
215253
log.WithFields(log.Fields{
216254
"domain": record.Name,

0 commit comments

Comments
 (0)