@@ -14,6 +14,26 @@ import (
1414 "github.com/spf13/afero"
1515)
1616
17+ //go:generate mockery --name=Executor --filename=executor.go
18+ type Executor interface {
19+ Command (name string , arg ... string ) * exec.Cmd
20+ Run (cmd * exec.Cmd ) error
21+ }
22+
23+ type executor struct {}
24+
25+ func NewExecutor () Executor {
26+ return & executor {}
27+ }
28+
29+ func (e * executor ) Command (name string , arg ... string ) * exec.Cmd {
30+ return exec .Command (name , arg ... )
31+ }
32+
33+ func (e * executor ) Run (cmd * exec.Cmd ) error {
34+ return cmd .Run ()
35+ }
36+
1737// DNSProvider represents a DNS provider to generate certificates.
1838type DNSProvider string
1939
@@ -46,13 +66,16 @@ type Config struct {
4666type CertBot struct {
4767 Config * Config
4868
69+ ex Executor
4970 fs afero.Fs
5071}
5172
5273func newCertBot (config * Config ) * CertBot {
5374 return & CertBot {
5475 Config : config ,
55- fs : afero .NewOsFs (),
76+
77+ ex : new (executor ),
78+ fs : afero .NewOsFs (),
5679 }
5780}
5881
@@ -69,7 +92,9 @@ func (cb *CertBot) ensureCertificates() {
6992
7093 certPath := fmt .Sprintf ("%s/live/*.%s/fullchain.pem" , cb .Config .RootDir , cb .Config .Tunnels .Domain )
7194 if _ , err := cb .fs .Stat (certPath ); os .IsNotExist (err ) {
72- cb .generateCertificateFromDNS ()
95+ if err := cb .generateCertificateFromDNS (); err != nil {
96+ log .WithError (err ).Fatal ("failed to generate the certificate from DNS" )
97+ }
7398 }
7499 }
75100}
@@ -85,7 +110,7 @@ func (cb *CertBot) generateCertificate() {
85110
86111 acmeServer := cb .startACMEServer ()
87112
88- cmd := exec .Command (
113+ cmd := cb . ex .Command (
89114 "certbot" ,
90115 "certonly" ,
91116 "--non-interactive" ,
@@ -128,16 +153,17 @@ func (cb *CertBot) generateProviderCredentialsFile() (afero.File, error) {
128153 return file , nil
129154}
130155
131- func (cb * CertBot ) generateCertificateFromDNS () {
156+ func (cb * CertBot ) generateCertificateFromDNS () error {
132157 log .Info ("generating SSL certificate with DNS" )
133158
134159 file , err := cb .generateProviderCredentialsFile ()
135160 if err != nil {
136- log .WithError (err ).Fatal ("failed to generate INI file" )
161+ log .WithError (err ).Error ("failed to generate INI file" )
162+
163+ return err
137164 }
138165
139- cmd := exec .Command ( //nolint:gosec
140- "certbot" ,
166+ args := []string {
141167 "certonly" ,
142168 "--non-interactive" ,
143169 "--agree-tos" ,
@@ -149,20 +175,30 @@ func (cb *CertBot) generateCertificateFromDNS() {
149175 file .Name (),
150176 "-d" ,
151177 fmt .Sprintf ("*.%s" , cb .Config .Tunnels .Domain ),
152- )
178+ }
179+
153180 if cb .Config .Staging {
154181 log .Info ("running generate with staging on dns" )
155182
156- cmd . Args = append (cmd . Args , "--staging" )
183+ args = append (args , "--staging" )
157184 }
158185
186+ cmd := cb .ex .Command ( //nolint:gosec
187+ "certbot" ,
188+ args ... ,
189+ )
190+
159191 cmd .Stdout , cmd .Stderr = os .Stdout , os .Stderr
160192
161- if err := cmd .Run (); err != nil {
162- log .WithError (err ).Fatal ("failed to generate SSL certificate" )
193+ if err := cb .ex .Run (cmd ); err != nil {
194+ log .WithError (err ).Error ("failed to generate SSL certificate" )
195+
196+ return err
163197 }
164198
165199 log .Info ("generate run on dns" )
200+
201+ return nil
166202}
167203
168204// startACMEServer starts a local HTTP server for the ACME challenge.
@@ -204,7 +240,7 @@ func (cb *CertBot) stopACMEServer(server *http.Server) {
204240}
205241
206242func (cb * CertBot ) executeRenewCertificates () error {
207- cmd := exec .Command ( //nolint:gosec
243+ cmd := cb . ex .Command ( //nolint:gosec
208244 "certbot" ,
209245 "renew" ,
210246 )
@@ -215,7 +251,7 @@ func (cb *CertBot) executeRenewCertificates() error {
215251 cmd .Args = append (cmd .Args , "--staging" )
216252 }
217253
218- if err := cmd . Run (); err != nil {
254+ if err := cb . ex . Run (cmd ); err != nil {
219255 return err
220256 }
221257
0 commit comments