Skip to content

Commit 1d58a86

Browse files
henrybarretogustavosbarreto
authored andcommitted
feat(gateway): create and use ticker abstraction to renew
1 parent 2b0975a commit 1d58a86

File tree

2 files changed

+81
-13
lines changed

2 files changed

+81
-13
lines changed

gateway/certbot.go

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"net/http"
@@ -34,6 +35,56 @@ func (e *executor) Run(cmd *exec.Cmd) error {
3435
return cmd.Run()
3536
}
3637

38+
//go:generate mockery --name=Ticker --filename=ticker.go
39+
type Ticker interface {
40+
// Init creates a new [time.Ticker] internally with [time.Duration] defined.
41+
Init(context.Context, time.Duration)
42+
// Tick waits for a ticker's tick and return the value. If ticker wasn't initialized, a [time.Time] with zero-value
43+
// will be returned.
44+
Tick() chan time.Time
45+
// Stop stops the ticker initialized. If ticker wasn't initialized, nothing happens.
46+
Stop()
47+
}
48+
49+
type ticker struct {
50+
ticker *time.Ticker
51+
tick chan time.Time
52+
}
53+
54+
func (t *ticker) Init(ctx context.Context, duration time.Duration) {
55+
t.ticker = time.NewTicker(duration)
56+
t.tick = make(chan time.Time)
57+
58+
go func() {
59+
defer close(t.tick)
60+
61+
for {
62+
select {
63+
case <-ctx.Done():
64+
return
65+
case ticked, ok := <-t.ticker.C:
66+
if !ok {
67+
return
68+
}
69+
70+
t.tick <- ticked
71+
}
72+
}
73+
}()
74+
}
75+
76+
func (t *ticker) Tick() chan time.Time {
77+
return t.tick
78+
}
79+
80+
func (t *ticker) Stop() {
81+
if t.ticker == nil {
82+
return
83+
}
84+
85+
t.ticker.Stop()
86+
}
87+
3788
// DNSProvider represents a DNS provider to generate certificates.
3889
type DNSProvider string
3990

@@ -67,6 +118,7 @@ type CertBot struct {
67118
Config *Config
68119

69120
ex Executor
121+
tk Ticker
70122
fs afero.Fs
71123
}
72124

@@ -75,6 +127,7 @@ func newCertBot(config *Config) *CertBot {
75127
Config: config,
76128

77129
ex: new(executor),
130+
tk: new(ticker),
78131
fs: afero.NewOsFs(),
79132
}
80133
}
@@ -265,21 +318,30 @@ func (cb *CertBot) executeRenewCertificates() error {
265318
}
266319

267320
// renewCertificates periodically renews the SSL certificates.
268-
func (cb *CertBot) renewCertificates() {
321+
func (cb *CertBot) renewCertificates(ctx context.Context, duration time.Duration) {
269322
log.Info("starting SSL certificate renewal process")
270323

271-
ticker := time.NewTicker(24 * time.Hour)
272-
defer ticker.Stop()
324+
cb.tk.Init(ctx, duration)
325+
defer cb.tk.Stop()
273326

274-
for range ticker.C {
275-
log.Info("checking if SSL certificate needs to be renewed")
276-
if err := cb.executeRenewCertificates(); err != nil {
277-
log.WithError(err).Error("failed to renew SSL certificate")
327+
ticker := cb.tk.Tick()
278328

279-
continue
280-
}
329+
for {
330+
select {
331+
case <-ctx.Done():
332+
log.Info("renew certificates loop was closed due context cancellation")
333+
334+
return
335+
case <-ticker:
336+
log.Info("checking if SSL certificate needs to be renewed")
337+
if err := cb.executeRenewCertificates(); err != nil {
338+
log.WithError(err).Error("failed to renew SSL certificate")
281339

282-
log.Info("ssl certificate successfully renewed")
283-
cb.Config.RenewedCallback()
340+
continue
341+
}
342+
343+
log.Info("ssl certificate successfully renewed")
344+
cb.Config.RenewedCallback()
345+
}
284346
}
285347
}

gateway/main.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package main
22

33
import (
4+
"context"
5+
"time"
6+
47
"github.com/shellhub-io/shellhub/pkg/loglevel"
58
log "github.com/sirupsen/logrus"
69
)
@@ -12,12 +15,15 @@ const (
1215
defaultNginxTemplateDir = "/templates"
1316
// defaultCertBotRootDir is the default directory where Certbot keeps
1417
// generated certificates, keys, and related assets.
15-
defaultCertBotRootDir = "/etc/letsencrypt"
18+
defaultCertBotRootDir = "/etc/letsencrypt"
19+
defaultTickerRenewCertificates = 24 * time.Hour
1620
)
1721

1822
func main() {
1923
loglevel.UseEnvs()
2024

25+
ctx := context.Background()
26+
2127
config, err := loadGatewayConfig()
2228
if err != nil {
2329
log.Fatalf("failed to load configuration: %v", err)
@@ -68,7 +74,7 @@ func main() {
6874
certBot.executeRenewCertificates()
6975
log.Info("renew executed")
7076

71-
go certBot.renewCertificates()
77+
go certBot.renewCertificates(ctx, defaultTickerRenewCertificates)
7278
}
7379

7480
if config.Env == "development" {

0 commit comments

Comments
 (0)