add errcheck validation
Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
parent
d9ffc39075
commit
ac4aa0d182
8 changed files with 129 additions and 85 deletions
|
@ -1,11 +1,10 @@
|
||||||
- repo: git://github.com/pre-commit/pre-commit-hooks
|
- repo: git://github.com/pre-commit/pre-commit-hooks
|
||||||
sha: 97b88d9610bcc03982ddac33caba98bb2b751f5f
|
sha: 44e1753f98b0da305332abe26856c3e621c5c439
|
||||||
hooks:
|
hooks:
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
|
|
||||||
- repo: git://github.com/containous/pre-commit-hooks
|
- repo: git://github.com/containous/pre-commit-hooks
|
||||||
sha: HEAD
|
sha: 35e641b5107671e94102b0ce909648559e568d61
|
||||||
hooks:
|
hooks:
|
||||||
- id: goFmt
|
- id: goFmt
|
||||||
- id: goLint
|
- id: goLint
|
||||||
|
- id: goErrcheck
|
||||||
|
|
128
acme/acme.go
128
acme/acme.go
|
@ -27,6 +27,34 @@ type Account struct {
|
||||||
DomainsCertificate DomainsCertificates
|
DomainsCertificate DomainsCertificates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetEmail returns email
|
||||||
|
func (a Account) GetEmail() string {
|
||||||
|
return a.Email
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegistration returns lets encrypt registration resource
|
||||||
|
func (a Account) GetRegistration() *acme.RegistrationResource {
|
||||||
|
return a.Registration
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrivateKey returns private key
|
||||||
|
func (a Account) GetPrivateKey() crypto.PrivateKey {
|
||||||
|
if privateKey, err := x509.ParsePKCS1PrivateKey(a.PrivateKey); err == nil {
|
||||||
|
return privateKey
|
||||||
|
}
|
||||||
|
log.Errorf("Cannot unmarshall private key %+v", a.PrivateKey)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Certificate is used to store certificate info
|
||||||
|
type Certificate struct {
|
||||||
|
Domain string
|
||||||
|
CertURL string
|
||||||
|
CertStableURL string
|
||||||
|
PrivateKey []byte
|
||||||
|
Certificate []byte
|
||||||
|
}
|
||||||
|
|
||||||
// DomainsCertificates stores a certificate for multiple domains
|
// DomainsCertificates stores a certificate for multiple domains
|
||||||
type DomainsCertificates struct {
|
type DomainsCertificates struct {
|
||||||
Certs []*DomainsCertificate
|
Certs []*DomainsCertificate
|
||||||
|
@ -64,7 +92,7 @@ func (dc *DomainsCertificates) renewCertificates(acmeCert *Certificate, domain D
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errors.New("Certificate to renew to found from domain " + domain.Main)
|
return errors.New("Certificate to renew not found for domain " + domain.Main)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DomainsCertificates) addCertificateForDomains(acmeCert *Certificate, domain Domain) (*DomainsCertificate, error) {
|
func (dc *DomainsCertificates) addCertificateForDomains(acmeCert *Certificate, domain Domain) (*DomainsCertificate, error) {
|
||||||
|
@ -84,7 +112,9 @@ func (dc *DomainsCertificates) getCertificateForDomain(domainToFind string) (*Do
|
||||||
dc.lock.RLock()
|
dc.lock.RLock()
|
||||||
defer dc.lock.RUnlock()
|
defer dc.lock.RUnlock()
|
||||||
for _, domainsCertificate := range dc.Certs {
|
for _, domainsCertificate := range dc.Certs {
|
||||||
domains := append([]string{domainsCertificate.Domains.Main}, domainsCertificate.Domains.SANs...)
|
domains := []string{}
|
||||||
|
domains = append(domains, domainsCertificate.Domains.Main)
|
||||||
|
domains = append(domains, domainsCertificate.Domains.SANs...)
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
if domain == domainToFind {
|
if domain == domainToFind {
|
||||||
return domainsCertificate, true
|
return domainsCertificate, true
|
||||||
|
@ -112,34 +142,6 @@ type DomainsCertificate struct {
|
||||||
tlsCert *tls.Certificate
|
tlsCert *tls.Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmail returns email
|
|
||||||
func (a Account) GetEmail() string {
|
|
||||||
return a.Email
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRegistration returns lets encrypt registration resource
|
|
||||||
func (a Account) GetRegistration() *acme.RegistrationResource {
|
|
||||||
return a.Registration
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPrivateKey returns private key
|
|
||||||
func (a Account) GetPrivateKey() crypto.PrivateKey {
|
|
||||||
if privateKey, err := x509.ParsePKCS1PrivateKey(a.PrivateKey); err == nil {
|
|
||||||
return privateKey
|
|
||||||
}
|
|
||||||
log.Errorf("Cannot unmarshall private key %+v", a.PrivateKey)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Certificate is used to store certificate info
|
|
||||||
type Certificate struct {
|
|
||||||
Domain string
|
|
||||||
CertURL string
|
|
||||||
CertStableURL string
|
|
||||||
PrivateKey []byte
|
|
||||||
Certificate []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// ACME allows to connect to lets encrypt and retrieve certs
|
// ACME allows to connect to lets encrypt and retrieve certs
|
||||||
type ACME struct {
|
type ACME struct {
|
||||||
Email string
|
Email string
|
||||||
|
@ -157,10 +159,9 @@ type Domain struct {
|
||||||
SANs []string
|
SANs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateACMEConfig creates a tls.config from using ACME configuration
|
// CreateConfig creates a tls.config from using ACME configuration
|
||||||
func (a *ACME) CreateACMEConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(domain string) bool) error {
|
func (a *ACME) CreateConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(domain string) bool) error {
|
||||||
acme.Logger = fmtlog.New(ioutil.Discard, "", 0)
|
acme.Logger = fmtlog.New(ioutil.Discard, "", 0)
|
||||||
// TODO: generate default cert if empty
|
|
||||||
|
|
||||||
if len(a.StorageFile) == 0 {
|
if len(a.StorageFile) == 0 {
|
||||||
return errors.New("Empty StorageFile, please provide a filenmae for certs storage")
|
return errors.New("Empty StorageFile, please provide a filenmae for certs storage")
|
||||||
|
@ -225,27 +226,7 @@ func (a *ACME) CreateACMEConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go a.retrieveCertificates(client, account)
|
||||||
log.Infof("Retrieving ACME certificates...")
|
|
||||||
for _, domain := range a.Domains {
|
|
||||||
// check if cert isn't already loaded
|
|
||||||
if _, exists := account.DomainsCertificate.exists(domain); !exists {
|
|
||||||
domains := append([]string{domain.Main}, domain.SANs...)
|
|
||||||
certificateResource, err := a.getDomainsCertificates(client, domains)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error getting ACME certificate for domain %s: %s", domains, err.Error())
|
|
||||||
}
|
|
||||||
_, err = account.DomainsCertificate.addCertificateForDomains(certificateResource, domain)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error adding ACME certificate for domain %s: %s", domains, err.Error())
|
|
||||||
}
|
|
||||||
if err = a.saveAccount(account); err != nil {
|
|
||||||
log.Errorf("Error Saving ACME account %+v: %s", account, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Infof("Retrieved ACME certificates")
|
|
||||||
}()
|
|
||||||
|
|
||||||
tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
if challengeCert, ok := wrapperChallengeProvider.getCertificate(clientHello.ServerName); ok {
|
if challengeCert, ok := wrapperChallengeProvider.getCertificate(clientHello.ServerName); ok {
|
||||||
|
@ -265,7 +246,6 @@ func (a *ACME) CreateACMEConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(
|
||||||
|
|
||||||
ticker := time.NewTicker(24 * time.Hour)
|
ticker := time.NewTicker(24 * time.Hour)
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(24 * time.Hour)
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
@ -280,8 +260,35 @@ func (a *ACME) CreateACMEConfig(tlsConfig *tls.Config, CheckOnDemandDomain func(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ACME) renewCertificates(client *acme.Client, Account *Account) error {
|
func (a *ACME) retrieveCertificates(client *acme.Client, account *Account) {
|
||||||
for _, certificateResource := range Account.DomainsCertificate.Certs {
|
log.Infof("Retrieving ACME certificates...")
|
||||||
|
for _, domain := range a.Domains {
|
||||||
|
// check if cert isn't already loaded
|
||||||
|
if _, exists := account.DomainsCertificate.exists(domain); !exists {
|
||||||
|
domains := []string{}
|
||||||
|
domains = append(domains, domain.Main)
|
||||||
|
domains = append(domains, domain.SANs...)
|
||||||
|
certificateResource, err := a.getDomainsCertificates(client, domains)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error getting ACME certificate for domain %s: %s", domains, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = account.DomainsCertificate.addCertificateForDomains(certificateResource, domain)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error adding ACME certificate for domain %s: %s", domains, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = a.saveAccount(account); err != nil {
|
||||||
|
log.Errorf("Error Saving ACME account %+v: %s", account, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Infof("Retrieved ACME certificates")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACME) renewCertificates(client *acme.Client, account *Account) error {
|
||||||
|
for _, certificateResource := range account.DomainsCertificate.Certs {
|
||||||
// <= 7 days left, renew certificate
|
// <= 7 days left, renew certificate
|
||||||
if certificateResource.tlsCert.Leaf.NotAfter.Before(time.Now().Add(time.Duration(24 * 7 * time.Hour))) {
|
if certificateResource.tlsCert.Leaf.NotAfter.Before(time.Now().Add(time.Duration(24 * 7 * time.Hour))) {
|
||||||
log.Debugf("Renewing certificate %+v", certificateResource.Domains)
|
log.Debugf("Renewing certificate %+v", certificateResource.Domains)
|
||||||
|
@ -303,11 +310,11 @@ func (a *ACME) renewCertificates(client *acme.Client, Account *Account) error {
|
||||||
PrivateKey: renewedCert.PrivateKey,
|
PrivateKey: renewedCert.PrivateKey,
|
||||||
Certificate: renewedCert.Certificate,
|
Certificate: renewedCert.Certificate,
|
||||||
}
|
}
|
||||||
err = Account.DomainsCertificate.renewCertificates(renewedACMECert, certificateResource.Domains)
|
err = account.DomainsCertificate.renewCertificates(renewedACMECert, certificateResource.Domains)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = a.saveAccount(Account); err != nil {
|
if err = a.saveAccount(account); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,9 +323,6 @@ func (a *ACME) renewCertificates(client *acme.Client, Account *Account) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ACME) buildACMEClient(Account *Account) (*acme.Client, error) {
|
func (a *ACME) buildACMEClient(Account *Account) (*acme.Client, error) {
|
||||||
|
|
||||||
// A client facilitates communication with the CA server. This CA URL is
|
|
||||||
// configured for a local dev instance of Boulder running in Docker in a VM.
|
|
||||||
caServer := "https://acme-v01.api.letsencrypt.org/directory"
|
caServer := "https://acme-v01.api.letsencrypt.org/directory"
|
||||||
if len(a.CAServer) > 0 {
|
if len(a.CAServer) > 0 {
|
||||||
caServer = a.CAServer
|
caServer = a.CAServer
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
FROM golang:1.6.0-alpine
|
FROM golang:1.6.0-alpine
|
||||||
|
|
||||||
RUN apk update && apk add git bash gcc
|
RUN apk update && apk add git bash gcc musl-dev \
|
||||||
|
&& go get github.com/Masterminds/glide \
|
||||||
RUN go get github.com/Masterminds/glide
|
&& go get github.com/mitchellh/gox \
|
||||||
RUN go get github.com/mitchellh/gox
|
&& go get github.com/jteeuwen/go-bindata/... \
|
||||||
RUN go get github.com/jteeuwen/go-bindata/...
|
&& go get github.com/golang/lint/golint \
|
||||||
RUN go get github.com/golang/lint/golint
|
&& go get github.com/kisielk/errcheck
|
||||||
|
|
||||||
# Which docker version to test on
|
# Which docker version to test on
|
||||||
ENV DOCKER_VERSION 1.10.1
|
ENV DOCKER_VERSION 1.10.1
|
||||||
|
|
17
cmd.go
17
cmd.go
|
@ -166,13 +166,12 @@ func init() {
|
||||||
traefikCmd.PersistentFlags().StringVar(&arguments.Boltdb.Endpoint, "boltdb.endpoint", "127.0.0.1:4001", "Boltdb server endpoint")
|
traefikCmd.PersistentFlags().StringVar(&arguments.Boltdb.Endpoint, "boltdb.endpoint", "127.0.0.1:4001", "Boltdb server endpoint")
|
||||||
traefikCmd.PersistentFlags().StringVar(&arguments.Boltdb.Prefix, "boltdb.prefix", "/traefik", "Prefix used for KV store")
|
traefikCmd.PersistentFlags().StringVar(&arguments.Boltdb.Prefix, "boltdb.prefix", "/traefik", "Prefix used for KV store")
|
||||||
|
|
||||||
viper.BindPFlag("configFile", traefikCmd.PersistentFlags().Lookup("configFile"))
|
_ = viper.BindPFlag("configFile", traefikCmd.PersistentFlags().Lookup("configFile"))
|
||||||
viper.BindPFlag("graceTimeOut", traefikCmd.PersistentFlags().Lookup("graceTimeOut"))
|
_ = viper.BindPFlag("graceTimeOut", traefikCmd.PersistentFlags().Lookup("graceTimeOut"))
|
||||||
//viper.BindPFlag("defaultEntryPoints", traefikCmd.PersistentFlags().Lookup("defaultEntryPoints"))
|
_ = viper.BindPFlag("logLevel", traefikCmd.PersistentFlags().Lookup("logLevel"))
|
||||||
viper.BindPFlag("logLevel", traefikCmd.PersistentFlags().Lookup("logLevel"))
|
|
||||||
// TODO: wait for this issue to be corrected: https://github.com/spf13/viper/issues/105
|
// TODO: wait for this issue to be corrected: https://github.com/spf13/viper/issues/105
|
||||||
viper.BindPFlag("providersThrottleDuration", traefikCmd.PersistentFlags().Lookup("providersThrottleDuration"))
|
_ = viper.BindPFlag("providersThrottleDuration", traefikCmd.PersistentFlags().Lookup("providersThrottleDuration"))
|
||||||
viper.BindPFlag("maxIdleConnsPerHost", traefikCmd.PersistentFlags().Lookup("maxIdleConnsPerHost"))
|
_ = viper.BindPFlag("maxIdleConnsPerHost", traefikCmd.PersistentFlags().Lookup("maxIdleConnsPerHost"))
|
||||||
viper.SetDefault("providersThrottleDuration", time.Duration(2*time.Second))
|
viper.SetDefault("providersThrottleDuration", time.Duration(2*time.Second))
|
||||||
viper.SetDefault("logLevel", "ERROR")
|
viper.SetDefault("logLevel", "ERROR")
|
||||||
viper.SetDefault("MaxIdleConnsPerHost", 200)
|
viper.SetDefault("MaxIdleConnsPerHost", 200)
|
||||||
|
@ -197,7 +196,11 @@ func run() {
|
||||||
|
|
||||||
if len(globalConfiguration.TraefikLogsFile) > 0 {
|
if len(globalConfiguration.TraefikLogsFile) > 0 {
|
||||||
fi, err := os.OpenFile(globalConfiguration.TraefikLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
fi, err := os.OpenFile(globalConfiguration.TraefikLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
defer fi.Close()
|
defer func() {
|
||||||
|
if err := fi.Close(); err != nil {
|
||||||
|
log.Error("Error closinf file", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error opening file", err)
|
log.Fatal("Error opening file", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -94,7 +94,9 @@ func (ep *EntryPoints) Set(value string) error {
|
||||||
var tls *TLS
|
var tls *TLS
|
||||||
if len(result["TLS"]) > 0 {
|
if len(result["TLS"]) > 0 {
|
||||||
certs := Certificates{}
|
certs := Certificates{}
|
||||||
certs.Set(result["TLS"])
|
if err := certs.Set(result["TLS"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
tls = &TLS{
|
tls = &TLS{
|
||||||
Certificates: certs,
|
Certificates: certs,
|
||||||
}
|
}
|
||||||
|
|
28
script/validate-errcheck
Executable file
28
script/validate-errcheck
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source "$(dirname "$BASH_SOURCE")/.validate"
|
||||||
|
|
||||||
|
IFS=$'\n'
|
||||||
|
files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor/' || true) )
|
||||||
|
unset IFS
|
||||||
|
|
||||||
|
errors=()
|
||||||
|
failedErrcheck=$(errcheck .)
|
||||||
|
if [ "$failedErrcheck" ]; then
|
||||||
|
errors+=( "$failedErrcheck" )
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#errors[@]} -eq 0 ]; then
|
||||||
|
echo 'Congratulations! All Go source files have been errchecked.'
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "Errors from errcheck:"
|
||||||
|
for err in "${errors[@]}"; do
|
||||||
|
echo "$err"
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
echo 'Please fix the above errors. You can test via "errcheck" and commit the result.'
|
||||||
|
echo
|
||||||
|
} >&2
|
||||||
|
false
|
||||||
|
fi
|
14
server.go
14
server.go
|
@ -248,7 +248,7 @@ func (server *Server) createTLSConfig(entryPointName string, tlsOption *TLS, rou
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
err := server.globalConfiguration.ACME.CreateACMEConfig(config, checkOnDemandDomain)
|
err := server.globalConfiguration.ACME.CreateConfig(config, checkOnDemandDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -343,6 +343,10 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
if len(frontend.EntryPoints) == 0 {
|
if len(frontend.EntryPoints) == 0 {
|
||||||
frontend.EntryPoints = globalConfiguration.DefaultEntryPoints
|
frontend.EntryPoints = globalConfiguration.DefaultEntryPoints
|
||||||
}
|
}
|
||||||
|
if len(frontend.EntryPoints) == 0 {
|
||||||
|
log.Errorf("No entrypoint defined for frontend %s, defaultEntryPoints:%s. Skipping it", frontendName, globalConfiguration.DefaultEntryPoints)
|
||||||
|
continue
|
||||||
|
}
|
||||||
for _, entryPointName := range frontend.EntryPoints {
|
for _, entryPointName := range frontend.EntryPoints {
|
||||||
log.Debugf("Wiring frontend %s to entryPoint %s", frontendName, entryPointName)
|
log.Debugf("Wiring frontend %s to entryPoint %s", frontendName, entryPointName)
|
||||||
if _, ok := serverEntryPoints[entryPointName]; !ok {
|
if _, ok := serverEntryPoints[entryPointName]; !ok {
|
||||||
|
@ -390,7 +394,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight)
|
log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight)
|
||||||
rebalancer.UpsertServer(url, roundrobin.Weight(server.Weight))
|
if err := rebalancer.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case types.Wrr:
|
case types.Wrr:
|
||||||
log.Debugf("Creating load-balancer wrr")
|
log.Debugf("Creating load-balancer wrr")
|
||||||
|
@ -401,7 +407,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight)
|
log.Debugf("Creating server %s at %s with weight %d", serverName, url.String(), server.Weight)
|
||||||
rr.UpsertServer(url, roundrobin.Weight(server.Weight))
|
if err := rr.UpsertServer(url, roundrobin.Weight(server.Weight)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var negroni = negroni.New()
|
var negroni = negroni.New()
|
||||||
|
|
Loading…
Reference in a new issue