Skip to content

Commit 8b322d5

Browse files
henrybarretogustavosbarreto
authored andcommitted
docs(gateway): add documentation headers to certbot and certificates
1 parent 6b6c5dc commit 8b322d5

File tree

1 file changed

+87
-16
lines changed

1 file changed

+87
-16
lines changed

gateway/certbot.go

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Package main provides SSL certificate management functionality using CertBot.
2+
// It supports both HTTP-01 and DNS-01 challenge types for certificate generation
3+
// and automatic renewal of SSL certificates.
14
package main
25

36
import (
@@ -15,42 +18,61 @@ import (
1518
"github.com/spf13/afero"
1619
)
1720

21+
// Executor provides an interface for executing system commands.
22+
// This interface allows for easy mocking in tests and provides
23+
// a clean abstraction over the exec package.
24+
//
1825
//go:generate mockery --name=Executor --filename=executor.go
1926
type Executor interface {
27+
// Command creates a new *exec.Cmd with the given name and arguments.
2028
Command(name string, arg ...string) *exec.Cmd
29+
// Run executes the given command and waits for it to complete.
2130
Run(cmd *exec.Cmd) error
2231
}
2332

33+
// executor is the default implementation of the Executor interface.
2434
type executor struct{}
2535

36+
// NewExecutor creates a new Executor instance.
2637
func NewExecutor() Executor {
2738
return &executor{}
2839
}
2940

41+
// Command creates a new *exec.Cmd with the given name and arguments.
3042
func (e *executor) Command(name string, arg ...string) *exec.Cmd {
3143
return exec.Command(name, arg...)
3244
}
3345

46+
// Run executes the given command and waits for it to complete.
3447
func (e *executor) Run(cmd *exec.Cmd) error {
3548
return cmd.Run()
3649
}
3750

51+
// Ticker provides an interface for time-based operations with context support.
52+
// This interface allows for easy mocking in tests and provides a clean
53+
// abstraction over the time package's ticker functionality.
54+
//
3855
//go:generate mockery --name=Ticker --filename=ticker.go
3956
type Ticker interface {
40-
// Init creates a new [time.Ticker] internally with [time.Duration] defined.
57+
// Init creates a new time.Ticker internally with the specified duration.
58+
// The ticker will respect the provided context for cancellation.
4159
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.
60+
// Tick returns a channel that receives the current time on each tick.
61+
// If the ticker wasn't initialized, the channel will be nil.
4462
Tick() chan time.Time
45-
// Stop stops the ticker initialized. If ticker wasn't initialized, nothing happens.
63+
// Stop stops the ticker. If the ticker wasn't initialized, this is a no-op.
4664
Stop()
4765
}
4866

67+
// ticker is the default implementation of the Ticker interface.
4968
type ticker struct {
5069
ticker *time.Ticker
5170
tick chan time.Time
5271
}
5372

73+
// Init creates a new time.Ticker internally with the specified duration.
74+
// It starts a goroutine that forwards ticker events to the tick channel
75+
// and handles context cancellation.
5476
func (t *ticker) Init(ctx context.Context, duration time.Duration) {
5577
t.ticker = time.NewTicker(duration)
5678
t.tick = make(chan time.Time)
@@ -73,10 +95,12 @@ func (t *ticker) Init(ctx context.Context, duration time.Duration) {
7395
}()
7496
}
7597

98+
// Tick returns a channel that receives the current time on each tick.
7699
func (t *ticker) Tick() chan time.Time {
77100
return t.tick
78101
}
79102

103+
// Stop stops the ticker. If the ticker wasn't initialized, this is a no-op.
80104
func (t *ticker) Stop() {
81105
if t.ticker == nil {
82106
return
@@ -85,34 +109,49 @@ func (t *ticker) Stop() {
85109
t.ticker.Stop()
86110
}
87111

88-
// DNSProvider represents a DNS provider to generate certificates.
112+
// DNSProvider represents a DNS provider that can be used for DNS-01 challenges
113+
// when generating SSL certificates.
89114
type DNSProvider string
90115

91116
// DigitalOceanDNSProvider represents the Digital Ocean DNS provider.
92117
const DigitalOceanDNSProvider = "digitalocean"
93118

119+
// Config holds the configuration for CertBot operations.
94120
type Config struct {
95-
// RootDir is the root directory for CertBot configurations.
121+
// RootDir is the root directory where CertBot stores its configurations
122+
// and generated certificates. Typically "/etc/letsencrypt".
96123
RootDir string
97-
// Staging defines if the CertBot will use the staging server to generate certificates.
124+
// Staging defines whether CertBot should use Let's Encrypt's staging server
125+
// instead of the production server. Useful for testing to avoid rate limits.
98126
Staging bool
99-
// RenewedCallback is a callback called after certificate renew.
127+
// RenewedCallback is an optional callback function that gets called
128+
// after a certificate is successfully renewed.
100129
RenewedCallback func()
101130
}
102131

132+
// Certificate represents an SSL certificate that can be generated using CertBot.
103133
type Certificate interface {
134+
// String returns a string representation of the certificate, typically the domain name.
104135
String() string
136+
// Generate creates the SSL certificate using CertBot.
137+
// The staging parameter determines whether to use Let's Encrypt's staging server.
105138
Generate(staging bool) error
106139
}
107140

141+
// DefaultCertificate represents a standard SSL certificate that uses HTTP-01 challenge
142+
// for domain validation. This is suitable for single domains where you have control
143+
// over the web server.
108144
type DefaultCertificate struct {
145+
// RootDir is the root directory for certificate storage.
109146
RootDir string
110-
Domain string
147+
// Domain is the domain name for which the certificate will be generated.
148+
Domain string
111149

112150
ex Executor
113151
fs afero.Fs
114152
}
115153

154+
// NewDefaultCertificate creates a new DefaultCertificate instance for the given domain.
116155
func NewDefaultCertificate(domain string) Certificate {
117156
return &DefaultCertificate{
118157
Domain: domain,
@@ -122,6 +161,9 @@ func NewDefaultCertificate(domain string) Certificate {
122161
}
123162
}
124163

164+
// startACMEServer starts a local HTTP server on port 80 to handle ACME HTTP-01 challenges.
165+
// This server serves files from the .well-known/acme-challenge directory which is
166+
// required for Let's Encrypt domain validation.
125167
func (d *DefaultCertificate) startACMEServer() *http.Server {
126168
mux := http.NewServeMux()
127169
mux.Handle(
@@ -152,23 +194,28 @@ func (d *DefaultCertificate) startACMEServer() *http.Server {
152194
return server
153195
}
154196

155-
// stopACMEServer stops the local ACME server.
197+
// stopACMEServer gracefully stops the local ACME HTTP server.
156198
func (d *DefaultCertificate) stopACMEServer(server *http.Server) {
157199
if err := server.Close(); err != nil {
158200
log.WithError(err).Fatal("could not stop ACME server")
159201
}
160202
}
161203

204+
// Generate creates an SSL certificate for the domain using HTTP-01 challenge.
205+
// It starts a local HTTP server to handle the ACME challenge, runs CertBot,
206+
// and then stops the server.
162207
func (d *DefaultCertificate) Generate(staging bool) error {
163208
log.Info("generating SSL certificate")
164209

210+
// Create the ACME challenge directory
165211
challengeDir := fmt.Sprintf("%s/.well-known/acme-challenge", os.TempDir())
166212
if err := d.fs.MkdirAll(challengeDir, 0o755); err != nil {
167213
log.WithError(err).Error("failed to create acme challenge on filesystem")
168214

169215
return err
170216
}
171217

218+
// Start the ACME server to handle HTTP-01 challenges
172219
acmeServer := d.startACMEServer()
173220

174221
args := []string{
@@ -204,29 +251,36 @@ func (d *DefaultCertificate) Generate(staging bool) error {
204251
return err
205252
}
206253

254+
// Stop the ACME server
207255
d.stopACMEServer(acmeServer)
208256

209257
log.Info("generate run")
210258

211259
return nil
212260
}
213261

262+
// String returns the domain name as the string representation of the certificate.
214263
func (d *DefaultCertificate) String() string {
215264
return d.Domain
216265
}
217266

267+
// TunnelsCertificate represents a wildcard SSL certificate that uses DNS-01 challenge
268+
// for domain validation. This is suitable for wildcard certificates (*.example.com)
269+
// where you have control over the DNS records.
218270
type TunnelsCertificate struct {
219-
// Domain is the default domain used to generate certificate for Tunnels.
271+
// Domain is the base domain used to generate wildcard certificates.
220272
Domain string
221-
// Provider is the DNS provider used to generate wildcard certificates.
273+
// Provider is the DNS provider used for DNS-01 challenges.
222274
Provider DNSProvider
223-
// Token is a DNS token used to generate wildcard certificates.
275+
// Token is the API token for the DNS provider.
224276
Token string
225277

226278
ex Executor
227279
fs afero.Fs
228280
}
229281

282+
// NewTunnelsCertificate creates a new TunnelsCertificate instance for generating
283+
// wildcard certificates using DNS-01 challenges.
230284
func NewTunnelsCertificate(domain string, provider DNSProvider, token string) Certificate {
231285
return &TunnelsCertificate{
232286
Domain: domain,
@@ -239,6 +293,8 @@ func NewTunnelsCertificate(domain string, provider DNSProvider, token string) Ce
239293
}
240294
}
241295

296+
// generateProviderCredentialsFile creates a credentials file for the DNS provider.
297+
// This file contains the API token needed for DNS-01 challenges.
242298
func (d *TunnelsCertificate) generateProviderCredentialsFile() (afero.File, error) {
243299
token := fmt.Sprintf("dns_%s_token = %s", d.Provider, d.Token)
244300

@@ -258,16 +314,21 @@ func (d *TunnelsCertificate) generateProviderCredentialsFile() (afero.File, erro
258314
return file, nil
259315
}
260316

317+
// Generate creates a wildcard SSL certificate for the domain using DNS-01 challenge.
318+
// It creates a credentials file for the DNS provider, runs CertBot with DNS plugin,
319+
// and generates a wildcard certificate.
261320
func (d *TunnelsCertificate) Generate(staging bool) error {
262321
log.Info("generating SSL certificate with DNS")
263322

323+
// Create the DNS provider credentials file
264324
file, err := d.generateProviderCredentialsFile()
265325
if err != nil {
266326
log.WithError(err).Error("failed to generate INI file")
267327

268328
return err
269329
}
270330

331+
// Build the CertBot command arguments for DNS-01 challenge
271332
args := []string{
272333
"certonly",
273334
"--non-interactive",
@@ -306,21 +367,26 @@ func (d *TunnelsCertificate) Generate(staging bool) error {
306367
return nil
307368
}
308369

370+
// String returns the domain name as the string representation of the certificate.
309371
func (d *TunnelsCertificate) String() string {
310372
return d.Domain
311373
}
312374

313-
// CertBot handles the generation and renewal of SSL certificates.
375+
// CertBot is the main structure that handles SSL certificate generation and renewal.
376+
// It manages multiple certificates and provides automatic renewal functionality.
314377
type CertBot struct {
378+
// Config holds the configuration for CertBot operations.
315379
Config *Config
316380

381+
// Certificates is a list of certificates to manage.
317382
Certificates []Certificate
318383

319384
ex Executor
320385
tk Ticker
321386
fs afero.Fs
322387
}
323388

389+
// newCertBot creates a new CertBot instance with the given configuration.
324390
func newCertBot(config *Config) *CertBot {
325391
return &CertBot{
326392
Config: config,
@@ -331,7 +397,8 @@ func newCertBot(config *Config) *CertBot {
331397
}
332398
}
333399

334-
// ensureCertificates checks if the SSL certificate exists and generates if it doesn't.
400+
// ensureCertificates checks if SSL certificates exist for all managed domains.
401+
// If a certificate doesn't exist, it generates a new one.
335402
func (cb *CertBot) ensureCertificates() {
336403
for _, certificate := range cb.Certificates {
337404
certPath := fmt.Sprintf("%s/live/%s/fullchain.pem", cb.Config.RootDir, certificate)
@@ -341,6 +408,8 @@ func (cb *CertBot) ensureCertificates() {
341408
}
342409
}
343410

411+
// executeRenewCertificates runs the CertBot renew command to check and renew
412+
// certificates that are close to expiration.
344413
func (cb *CertBot) executeRenewCertificates() error {
345414
args := []string{
346415
"renew",
@@ -366,7 +435,9 @@ func (cb *CertBot) executeRenewCertificates() error {
366435
return nil
367436
}
368437

369-
// renewCertificates periodically renews the SSL certificates.
438+
// renewCertificates starts a background process that periodically checks and renews
439+
// SSL certificates. It runs in a loop with the specified duration between checks.
440+
// The process respects context cancellation for graceful shutdown.
370441
func (cb *CertBot) renewCertificates(ctx context.Context, duration time.Duration) {
371442
log.Info("starting SSL certificate renewal process")
372443

0 commit comments

Comments
 (0)