1
0
Fork 0

Separate command from the main package

This commit is contained in:
SALLEYRON Julien 2018-03-01 08:10:04 +01:00 committed by Traefiker Bot
parent a2db3e0499
commit 831a3e384b
12 changed files with 63 additions and 51 deletions

View file

@ -1,136 +0,0 @@
package anonymize
import (
"encoding/json"
"fmt"
"reflect"
"regexp"
"github.com/mitchellh/copystructure"
"github.com/mvdan/xurls"
)
const (
maskShort = "xxxx"
maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort
)
// Do configuration.
func Do(baseConfig interface{}, indent bool) (string, error) {
anomConfig, err := copystructure.Copy(baseConfig)
if err != nil {
return "", err
}
val := reflect.ValueOf(anomConfig)
err = doOnStruct(val)
if err != nil {
return "", err
}
configJSON, err := marshal(anomConfig, indent)
if err != nil {
return "", err
}
return doOnJSON(string(configJSON)), nil
}
func doOnJSON(input string) string {
mailExp := regexp.MustCompile(`\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3}"`)
return xurls.Relaxed.ReplaceAllString(mailExp.ReplaceAllString(input, maskLarge+"\""), maskLarge)
}
func doOnStruct(field reflect.Value) error {
switch field.Kind() {
case reflect.Ptr:
if !field.IsNil() {
if err := doOnStruct(field.Elem()); err != nil {
return err
}
}
case reflect.Struct:
for i := 0; i < field.NumField(); i++ {
fld := field.Field(i)
stField := field.Type().Field(i)
if !isExported(stField) {
continue
}
if stField.Tag.Get("export") == "true" {
if err := doOnStruct(fld); err != nil {
return err
}
} else {
if err := reset(fld, stField.Name); err != nil {
return err
}
}
}
case reflect.Map:
for _, key := range field.MapKeys() {
if err := doOnStruct(field.MapIndex(key)); err != nil {
return err
}
}
case reflect.Slice:
for j := 0; j < field.Len(); j++ {
if err := doOnStruct(field.Index(j)); err != nil {
return err
}
}
}
return nil
}
func reset(field reflect.Value, name string) error {
if !field.CanSet() {
return fmt.Errorf("cannot reset field %s", name)
}
switch field.Kind() {
case reflect.Ptr:
if !field.IsNil() {
field.Set(reflect.Zero(field.Type()))
}
case reflect.Struct:
if field.IsValid() {
field.Set(reflect.Zero(field.Type()))
}
case reflect.String:
if field.String() != "" {
field.Set(reflect.ValueOf(maskShort))
}
case reflect.Map:
if field.Len() > 0 {
field.Set(reflect.MakeMap(field.Type()))
}
case reflect.Slice:
if field.Len() > 0 {
field.Set(reflect.MakeSlice(field.Type(), 0, 0))
}
case reflect.Interface:
if !field.IsNil() {
return reset(field.Elem(), "")
}
default:
// Primitive type
field.Set(reflect.Zero(field.Type()))
}
return nil
}
// isExported return true is a struct field is exported, else false
func isExported(f reflect.StructField) bool {
if f.PkgPath != "" && !f.Anonymous {
return false
}
return true
}
func marshal(anomConfig interface{}, indent bool) ([]byte, error) {
if indent {
return json.MarshalIndent(anomConfig, "", " ")
}
return json.Marshal(anomConfig)
}

View file

@ -1,663 +0,0 @@
package anonymize
import (
"crypto/tls"
"testing"
"time"
"github.com/containous/flaeg"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/boltdb"
"github.com/containous/traefik/provider/consul"
"github.com/containous/traefik/provider/consulcatalog"
"github.com/containous/traefik/provider/docker"
"github.com/containous/traefik/provider/dynamodb"
"github.com/containous/traefik/provider/ecs"
"github.com/containous/traefik/provider/etcd"
"github.com/containous/traefik/provider/eureka"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/provider/kv"
"github.com/containous/traefik/provider/marathon"
"github.com/containous/traefik/provider/mesos"
"github.com/containous/traefik/provider/rancher"
"github.com/containous/traefik/provider/zk"
traefikTls "github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
)
func TestDo_globalConfiguration(t *testing.T) {
config := &configuration.GlobalConfiguration{}
config.GraceTimeOut = flaeg.Duration(666 * time.Second)
config.Debug = true
config.CheckNewVersion = true
config.AccessLogsFile = "AccessLogsFile"
config.AccessLog = &types.AccessLog{
FilePath: "AccessLog FilePath",
Format: "AccessLog Format",
}
config.TraefikLogsFile = "TraefikLogsFile"
config.LogLevel = "LogLevel"
config.EntryPoints = configuration.EntryPoints{
"foo": {
Address: "foo Address",
TLS: &traefikTls.TLS{
MinVersion: "foo MinVersion",
CipherSuites: []string{"foo CipherSuites 1", "foo CipherSuites 2", "foo CipherSuites 3"},
Certificates: traefikTls.Certificates{
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
},
ClientCA: traefikTls.ClientCA{
Files: []string{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"},
Optional: false,
},
},
Redirect: &types.Redirect{
Replacement: "foo Replacement",
Regex: "foo Regex",
EntryPoint: "foo EntryPoint",
},
Auth: &types.Auth{
Basic: &types.Basic{
UsersFile: "foo Basic UsersFile",
Users: types.Users{"foo Basic Users 1", "foo Basic Users 2", "foo Basic Users 3"},
},
Digest: &types.Digest{
UsersFile: "foo Digest UsersFile",
Users: types.Users{"foo Digest Users 1", "foo Digest Users 2", "foo Digest Users 3"},
},
Forward: &types.Forward{
Address: "foo Address",
TLS: &types.ClientTLS{
CA: "foo CA",
Cert: "foo Cert",
Key: "foo Key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
},
WhitelistSourceRange: []string{"foo WhitelistSourceRange 1", "foo WhitelistSourceRange 2", "foo WhitelistSourceRange 3"},
Compress: true,
ProxyProtocol: &configuration.ProxyProtocol{
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
},
},
"fii": {
Address: "fii Address",
TLS: &traefikTls.TLS{
MinVersion: "fii MinVersion",
CipherSuites: []string{"fii CipherSuites 1", "fii CipherSuites 2", "fii CipherSuites 3"},
Certificates: traefikTls.Certificates{
{CertFile: "CertFile 1", KeyFile: "KeyFile 1"},
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
},
ClientCA: traefikTls.ClientCA{
Files: []string{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"},
Optional: false,
},
},
Redirect: &types.Redirect{
Replacement: "fii Replacement",
Regex: "fii Regex",
EntryPoint: "fii EntryPoint",
},
Auth: &types.Auth{
Basic: &types.Basic{
UsersFile: "fii Basic UsersFile",
Users: types.Users{"fii Basic Users 1", "fii Basic Users 2", "fii Basic Users 3"},
},
Digest: &types.Digest{
UsersFile: "fii Digest UsersFile",
Users: types.Users{"fii Digest Users 1", "fii Digest Users 2", "fii Digest Users 3"},
},
Forward: &types.Forward{
Address: "fii Address",
TLS: &types.ClientTLS{
CA: "fii CA",
Cert: "fii Cert",
Key: "fii Key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
},
WhitelistSourceRange: []string{"fii WhitelistSourceRange 1", "fii WhitelistSourceRange 2", "fii WhitelistSourceRange 3"},
Compress: true,
ProxyProtocol: &configuration.ProxyProtocol{
TrustedIPs: []string{"127.0.0.1/32", "192.168.0.1"},
},
},
}
config.Cluster = &types.Cluster{
Node: "Cluster Node",
Store: &types.Store{
Prefix: "Cluster Store Prefix",
// ...
},
}
config.Constraints = types.Constraints{
{
Key: "Constraints Key 1",
Regex: "Constraints Regex 2",
MustMatch: true,
},
{
Key: "Constraints Key 1",
Regex: "Constraints Regex 2",
MustMatch: true,
},
}
config.ACME = &acme.ACME{
Email: "acme Email",
Domains: []acme.Domain{
{
Main: "Domains Main",
SANs: []string{"Domains acme SANs 1", "Domains acme SANs 2", "Domains acme SANs 3"},
},
},
Storage: "Storage",
StorageFile: "StorageFile",
OnDemand: true,
OnHostRule: true,
CAServer: "CAServer",
EntryPoint: "EntryPoint",
DNSChallenge: &acme.DNSChallenge{Provider: "DNSProvider"},
DelayDontCheckDNS: 666,
ACMELogging: true,
TLSConfig: &tls.Config{
InsecureSkipVerify: true,
// ...
},
}
config.DefaultEntryPoints = configuration.DefaultEntryPoints{"DefaultEntryPoints 1", "DefaultEntryPoints 2", "DefaultEntryPoints 3"}
config.ProvidersThrottleDuration = flaeg.Duration(666 * time.Second)
config.MaxIdleConnsPerHost = 666
config.IdleTimeout = flaeg.Duration(666 * time.Second)
config.InsecureSkipVerify = true
config.RootCAs = traefikTls.RootCAs{"RootCAs 1", "RootCAs 2", "RootCAs 3"}
config.Retry = &configuration.Retry{
Attempts: 666,
}
config.HealthCheck = &configuration.HealthCheckConfig{
Interval: flaeg.Duration(666 * time.Second),
}
config.RespondingTimeouts = &configuration.RespondingTimeouts{
ReadTimeout: flaeg.Duration(666 * time.Second),
WriteTimeout: flaeg.Duration(666 * time.Second),
IdleTimeout: flaeg.Duration(666 * time.Second),
}
config.ForwardingTimeouts = &configuration.ForwardingTimeouts{
DialTimeout: flaeg.Duration(666 * time.Second),
ResponseHeaderTimeout: flaeg.Duration(666 * time.Second),
}
config.Docker = &docker.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "docker Filename",
Constraints: types.Constraints{
{
Key: "docker Constraints Key 1",
Regex: "docker Constraints Regex 2",
MustMatch: true,
},
{
Key: "docker Constraints Key 1",
Regex: "docker Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "docker Endpoint",
Domain: "docker Domain",
TLS: &types.ClientTLS{
CA: "docker CA",
Cert: "docker Cert",
Key: "docker Key",
InsecureSkipVerify: true,
},
ExposedByDefault: true,
UseBindPortIP: true,
SwarmMode: true,
}
config.File = &file.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "file Filename",
Constraints: types.Constraints{
{
Key: "file Constraints Key 1",
Regex: "file Constraints Regex 2",
MustMatch: true,
},
{
Key: "file Constraints Key 1",
Regex: "file Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Directory: "file Directory",
}
config.Web = &configuration.WebCompatibility{
Address: "web Address",
CertFile: "web CertFile",
KeyFile: "web KeyFile",
ReadOnly: true,
Statistics: &types.Statistics{
RecentErrors: 666,
},
Metrics: &types.Metrics{
Prometheus: &types.Prometheus{
Buckets: types.Buckets{6.5, 6.6, 6.7},
},
Datadog: &types.Datadog{
Address: "Datadog Address",
PushInterval: "Datadog PushInterval",
},
StatsD: &types.Statsd{
Address: "StatsD Address",
PushInterval: "StatsD PushInterval",
},
},
Path: "web Path",
Auth: &types.Auth{
Basic: &types.Basic{
UsersFile: "web Basic UsersFile",
Users: types.Users{"web Basic Users 1", "web Basic Users 2", "web Basic Users 3"},
},
Digest: &types.Digest{
UsersFile: "web Digest UsersFile",
Users: types.Users{"web Digest Users 1", "web Digest Users 2", "web Digest Users 3"},
},
Forward: &types.Forward{
Address: "web Address",
TLS: &types.ClientTLS{
CA: "web CA",
Cert: "web Cert",
Key: "web Key",
InsecureSkipVerify: true,
},
TrustForwardHeader: true,
},
},
Debug: true,
}
config.Marathon = &marathon.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "marathon Filename",
Constraints: types.Constraints{
{
Key: "marathon Constraints Key 1",
Regex: "marathon Constraints Regex 2",
MustMatch: true,
},
{
Key: "marathon Constraints Key 1",
Regex: "marathon Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "",
Domain: "",
ExposedByDefault: true,
GroupsAsSubDomains: true,
DCOSToken: "",
MarathonLBCompatibility: true,
TLS: &types.ClientTLS{
CA: "marathon CA",
Cert: "marathon Cert",
Key: "marathon Key",
InsecureSkipVerify: true,
},
DialerTimeout: flaeg.Duration(666 * time.Second),
KeepAlive: flaeg.Duration(666 * time.Second),
ForceTaskHostname: true,
Basic: &marathon.Basic{
HTTPBasicAuthUser: "marathon HTTPBasicAuthUser",
HTTPBasicPassword: "marathon HTTPBasicPassword",
},
RespectReadinessChecks: true,
}
config.ConsulCatalog = &consulcatalog.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "ConsulCatalog Filename",
Constraints: types.Constraints{
{
Key: "ConsulCatalog Constraints Key 1",
Regex: "ConsulCatalog Constraints Regex 2",
MustMatch: true,
},
{
Key: "ConsulCatalog Constraints Key 1",
Regex: "ConsulCatalog Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "ConsulCatalog Endpoint",
Domain: "ConsulCatalog Domain",
ExposedByDefault: true,
Prefix: "ConsulCatalog Prefix",
FrontEndRule: "ConsulCatalog FrontEndRule",
}
config.Kubernetes = &kubernetes.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "k8s Filename",
Constraints: types.Constraints{
{
Key: "k8s Constraints Key 1",
Regex: "k8s Constraints Regex 2",
MustMatch: true,
},
{
Key: "k8s Constraints Key 1",
Regex: "k8s Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "k8s Endpoint",
Token: "k8s Token",
CertAuthFilePath: "k8s CertAuthFilePath",
DisablePassHostHeaders: true,
Namespaces: kubernetes.Namespaces{"k8s Namespaces 1", "k8s Namespaces 2", "k8s Namespaces 3"},
LabelSelector: "k8s LabelSelector",
}
config.Mesos = &mesos.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "mesos Filename",
Constraints: types.Constraints{
{
Key: "mesos Constraints Key 1",
Regex: "mesos Constraints Regex 2",
MustMatch: true,
},
{
Key: "mesos Constraints Key 1",
Regex: "mesos Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "mesos Endpoint",
Domain: "mesos Domain",
ExposedByDefault: true,
GroupsAsSubDomains: true,
ZkDetectionTimeout: 666,
RefreshSeconds: 666,
IPSources: "mesos IPSources",
StateTimeoutSecond: 666,
Masters: []string{"mesos Masters 1", "mesos Masters 2", "mesos Masters 3"},
}
config.Eureka = &eureka.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "eureka Filename",
Constraints: types.Constraints{
{
Key: "eureka Constraints Key 1",
Regex: "eureka Constraints Regex 2",
MustMatch: true,
},
{
Key: "eureka Constraints Key 1",
Regex: "eureka Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "eureka Endpoint",
Delay: flaeg.Duration(30 * time.Second),
}
config.ECS = &ecs.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "ecs Filename",
Constraints: types.Constraints{
{
Key: "ecs Constraints Key 1",
Regex: "ecs Constraints Regex 2",
MustMatch: true,
},
{
Key: "ecs Constraints Key 1",
Regex: "ecs Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Domain: "ecs Domain",
ExposedByDefault: true,
RefreshSeconds: 666,
Clusters: ecs.Clusters{"ecs Clusters 1", "ecs Clusters 2", "ecs Clusters 3"},
Cluster: "ecs Cluster",
AutoDiscoverClusters: true,
Region: "ecs Region",
AccessKeyID: "ecs AccessKeyID",
SecretAccessKey: "ecs SecretAccessKey",
}
config.Rancher = &rancher.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "rancher Filename",
Constraints: types.Constraints{
{
Key: "rancher Constraints Key 1",
Regex: "rancher Constraints Regex 2",
MustMatch: true,
},
{
Key: "rancher Constraints Key 1",
Regex: "rancher Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
APIConfiguration: rancher.APIConfiguration{
Endpoint: "rancher Endpoint",
AccessKey: "rancher AccessKey",
SecretKey: "rancher SecretKey",
},
API: &rancher.APIConfiguration{
Endpoint: "rancher Endpoint",
AccessKey: "rancher AccessKey",
SecretKey: "rancher SecretKey",
},
Metadata: &rancher.MetadataConfiguration{
IntervalPoll: true,
Prefix: "rancher Metadata Prefix",
},
Domain: "rancher Domain",
RefreshSeconds: 666,
ExposedByDefault: true,
EnableServiceHealthFilter: true,
}
config.DynamoDB = &dynamodb.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "dynamodb Filename",
Constraints: types.Constraints{
{
Key: "dynamodb Constraints Key 1",
Regex: "dynamodb Constraints Regex 2",
MustMatch: true,
},
{
Key: "dynamodb Constraints Key 1",
Regex: "dynamodb Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
AccessKeyID: "dynamodb AccessKeyID",
RefreshSeconds: 666,
Region: "dynamodb Region",
SecretAccessKey: "dynamodb SecretAccessKey",
TableName: "dynamodb TableName",
Endpoint: "dynamodb Endpoint",
}
config.Etcd = &etcd.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "etcd Filename",
Constraints: types.Constraints{
{
Key: "etcd Constraints Key 1",
Regex: "etcd Constraints Regex 2",
MustMatch: true,
},
{
Key: "etcd Constraints Key 1",
Regex: "etcd Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "etcd Endpoint",
Prefix: "etcd Prefix",
TLS: &types.ClientTLS{
CA: "etcd CA",
Cert: "etcd Cert",
Key: "etcd Key",
InsecureSkipVerify: true,
},
Username: "etcd Username",
Password: "etcd Password",
},
}
config.Zookeeper = &zk.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "zk Filename",
Constraints: types.Constraints{
{
Key: "zk Constraints Key 1",
Regex: "zk Constraints Regex 2",
MustMatch: true,
},
{
Key: "zk Constraints Key 1",
Regex: "zk Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "zk Endpoint",
Prefix: "zk Prefix",
TLS: &types.ClientTLS{
CA: "zk CA",
Cert: "zk Cert",
Key: "zk Key",
InsecureSkipVerify: true,
},
Username: "zk Username",
Password: "zk Password",
},
}
config.Boltdb = &boltdb.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "boltdb Filename",
Constraints: types.Constraints{
{
Key: "boltdb Constraints Key 1",
Regex: "boltdb Constraints Regex 2",
MustMatch: true,
},
{
Key: "boltdb Constraints Key 1",
Regex: "boltdb Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "boltdb Endpoint",
Prefix: "boltdb Prefix",
TLS: &types.ClientTLS{
CA: "boltdb CA",
Cert: "boltdb Cert",
Key: "boltdb Key",
InsecureSkipVerify: true,
},
Username: "boltdb Username",
Password: "boltdb Password",
},
}
config.Consul = &consul.Provider{
Provider: kv.Provider{
BaseProvider: provider.BaseProvider{
Watch: true,
Filename: "consul Filename",
Constraints: types.Constraints{
{
Key: "consul Constraints Key 1",
Regex: "consul Constraints Regex 2",
MustMatch: true,
},
{
Key: "consul Constraints Key 1",
Regex: "consul Constraints Regex 2",
MustMatch: true,
},
},
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "consul Endpoint",
Prefix: "consul Prefix",
TLS: &types.ClientTLS{
CA: "consul CA",
Cert: "consul Cert",
Key: "consul Key",
InsecureSkipVerify: true,
},
Username: "consul Username",
Password: "consul Password",
},
}
cleanJSON, err := Do(config, true)
if err != nil {
t.Fatal(err, cleanJSON)
}
}

View file

@ -1,237 +0,0 @@
package anonymize
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_doOnJSON(t *testing.T) {
baseConfiguration := `
{
"GraceTimeOut": 10000000000,
"Debug": false,
"CheckNewVersion": true,
"AccessLogsFile": "",
"TraefikLogsFile": "",
"LogLevel": "ERROR",
"EntryPoints": {
"http": {
"Network": "",
"Address": ":80",
"TLS": null,
"Redirect": {
"EntryPoint": "https",
"Regex": "",
"Replacement": ""
},
"Auth": null,
"Compress": false
},
"https": {
"Address": ":443",
"TLS": {
"MinVersion": "",
"CipherSuites": null,
"Certificates": null,
"ClientCAFiles": null
},
"Redirect": null,
"Auth": null,
"Compress": false
}
},
"Cluster": null,
"Constraints": [],
"ACME": {
"Email": "foo@bar.com",
"Domains": [
{
"Main": "foo@bar.com",
"SANs": null
},
{
"Main": "foo@bar.com",
"SANs": null
}
],
"Storage": "",
"StorageFile": "/acme/acme.json",
"OnDemand": true,
"OnHostRule": true,
"CAServer": "",
"EntryPoint": "https",
"DNSProvider": "",
"DelayDontCheckDNS": 0,
"ACMELogging": false,
"TLSConfig": null
},
"DefaultEntryPoints": [
"https",
"http"
],
"ProvidersThrottleDuration": 2000000000,
"MaxIdleConnsPerHost": 200,
"IdleTimeout": 180000000000,
"InsecureSkipVerify": false,
"Retry": null,
"HealthCheck": {
"Interval": 30000000000
},
"Docker": null,
"File": null,
"Web": null,
"Marathon": null,
"Consul": null,
"ConsulCatalog": null,
"Etcd": null,
"Zookeeper": null,
"Boltdb": null,
"Kubernetes": null,
"Mesos": null,
"Eureka": null,
"ECS": null,
"Rancher": null,
"DynamoDB": null,
"ConfigFile": "/etc/traefik/traefik.toml"
}
`
expectedConfiguration := `
{
"GraceTimeOut": 10000000000,
"Debug": false,
"CheckNewVersion": true,
"AccessLogsFile": "",
"TraefikLogsFile": "",
"LogLevel": "ERROR",
"EntryPoints": {
"http": {
"Network": "",
"Address": ":80",
"TLS": null,
"Redirect": {
"EntryPoint": "https",
"Regex": "",
"Replacement": ""
},
"Auth": null,
"Compress": false
},
"https": {
"Address": ":443",
"TLS": {
"MinVersion": "",
"CipherSuites": null,
"Certificates": null,
"ClientCAFiles": null
},
"Redirect": null,
"Auth": null,
"Compress": false
}
},
"Cluster": null,
"Constraints": [],
"ACME": {
"Email": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Domains": [
{
"Main": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"SANs": null
},
{
"Main": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"SANs": null
}
],
"Storage": "",
"StorageFile": "/acme/acme.json",
"OnDemand": true,
"OnHostRule": true,
"CAServer": "",
"EntryPoint": "https",
"DNSProvider": "",
"DelayDontCheckDNS": 0,
"ACMELogging": false,
"TLSConfig": null
},
"DefaultEntryPoints": [
"https",
"http"
],
"ProvidersThrottleDuration": 2000000000,
"MaxIdleConnsPerHost": 200,
"IdleTimeout": 180000000000,
"InsecureSkipVerify": false,
"Retry": null,
"HealthCheck": {
"Interval": 30000000000
},
"Docker": null,
"File": null,
"Web": null,
"Marathon": null,
"Consul": null,
"ConsulCatalog": null,
"Etcd": null,
"Zookeeper": null,
"Boltdb": null,
"Kubernetes": null,
"Mesos": null,
"Eureka": null,
"ECS": null,
"Rancher": null,
"DynamoDB": null,
"ConfigFile": "/etc/traefik/traefik.toml"
}
`
anomConfiguration := doOnJSON(baseConfiguration)
if anomConfiguration != expectedConfiguration {
t.Errorf("Got %s, want %s.", anomConfiguration, expectedConfiguration)
}
}
func Test_doOnJSON_simple(t *testing.T) {
testCases := []struct {
name string
input string
expectedOutput string
}{
{
name: "email",
input: `{
"email1": "goo@example.com",
"email2": "foo.bargoo@example.com",
"email3": "foo.bargoo@example.com.us"
}`,
expectedOutput: `{
"email1": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email2": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email3": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}`,
},
{
name: "url",
input: `{
"URL": "foo domain.com foo",
"URL": "foo sub.domain.com foo",
"URL": "foo sub.sub.domain.com foo",
"URL": "foo sub.sub.sub.domain.com.us foo"
}`,
expectedOutput: `{
"URL": "foo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx foo",
"URL": "foo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx foo",
"URL": "foo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx foo",
"URL": "foo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx foo"
}`,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
output := doOnJSON(test.input)
assert.Equal(t, test.expectedOutput, output)
})
}
}

View file

@ -1,176 +0,0 @@
package anonymize
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
type Courgette struct {
Ji string
Ho string
}
type Tomate struct {
Ji string
Ho string
}
type Carotte struct {
Name string
Value int
Courgette Courgette
ECourgette Courgette `export:"true"`
Pourgette *Courgette
EPourgette *Courgette `export:"true"`
Aubergine map[string]string
EAubergine map[string]string `export:"true"`
SAubergine map[string]Tomate
ESAubergine map[string]Tomate `export:"true"`
PSAubergine map[string]*Tomate
EPAubergine map[string]*Tomate `export:"true"`
}
func Test_doOnStruct(t *testing.T) {
testCase := []struct {
name string
base *Carotte
expected *Carotte
hasError bool
}{
{
name: "primitive",
base: &Carotte{
Name: "koko",
Value: 666,
},
expected: &Carotte{
Name: "xxxx",
},
},
{
name: "struct",
base: &Carotte{
Name: "koko",
Courgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
},
},
{
name: "pointer",
base: &Carotte{
Name: "koko",
Pourgette: &Courgette{
Ji: "hoo",
},
},
expected: &Carotte{
Name: "xxxx",
Pourgette: nil,
},
},
{
name: "export struct",
base: &Carotte{
Name: "koko",
ECourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
ECourgette: Courgette{
Ji: "xxxx",
},
},
},
{
name: "export pointer struct",
base: &Carotte{
Name: "koko",
ECourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
ECourgette: Courgette{
Ji: "xxxx",
},
},
},
{
name: "export map string/string",
base: &Carotte{
Name: "koko",
EAubergine: map[string]string{
"foo": "bar",
},
},
expected: &Carotte{
Name: "xxxx",
EAubergine: map[string]string{
"foo": "bar",
},
},
},
{
name: "export map string/pointer",
base: &Carotte{
Name: "koko",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "fdskljf",
},
},
},
expected: &Carotte{
Name: "xxxx",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "xxxx",
},
},
},
},
{
name: "export map string/struct (UNSAFE)",
base: &Carotte{
Name: "koko",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
},
expected: &Carotte{
Name: "xxxx",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
},
hasError: true,
},
}
for _, test := range testCase {
t.Run(test.name, func(t *testing.T) {
val := reflect.ValueOf(test.base).Elem()
err := doOnStruct(val)
if !test.hasError && err != nil {
t.Fatal(err)
}
if test.hasError && err == nil {
t.Fatal("Got no error but want an error.")
}
assert.EqualValues(t, test.expected, test.base)
})
}
}

View file

@ -1,169 +0,0 @@
package main
import (
"bytes"
"fmt"
"net/url"
"os/exec"
"runtime"
"text/template"
"github.com/containous/flaeg"
"github.com/containous/traefik/cmd/traefik/anonymize"
)
const (
bugTracker = "https://github.com/containous/traefik/issues/new"
bugTemplate = `<!--
DO NOT FILE ISSUES FOR GENERAL SUPPORT QUESTIONS.
The issue tracker is for reporting bugs and feature requests only.
For end-user related support questions, refer to one of the following:
- Stack Overflow (using the "traefik" tag): https://stackoverflow.com/questions/tagged/traefik
- the Traefik community Slack channel: https://traefik.herokuapp.com
-->
### Do you want to request a *feature* or report a *bug*?
(If you intend to ask a support question: **DO NOT FILE AN ISSUE**.
Use [Stack Overflow](https://stackoverflow.com/questions/tagged/traefik)
or [Slack](https://traefik.herokuapp.com) instead.)
### What did you do?
<!--
HOW TO WRITE A GOOD ISSUE?
- Respect the issue template as more as possible.
- If it's possible use the command ` + "`" + "traefik bug" + "`" + `. See https://www.youtube.com/watch?v=Lyz62L8m93I.
- The title must be short and descriptive.
- Explain the conditions which led you to write this issue: the context.
- The context should lead to something, an idea or a problem that youre facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->
### What did you expect to see?
### What did you see instead?
### Output of ` + "`" + `traefik version` + "`" + `: (_What version of Traefik are you using?_)
` + "```" + `
{{.Version}}
` + "```" + `
### What is your environment & configuration (arguments, toml, provider, platform, ...)?
` + "```" + `json
{{.Configuration}}
` + "```" + `
<!--
Add more configuration information here.
-->
### If applicable, please paste the log output in debug mode (` + "`" + `--debug` + "`" + ` switch)
` + "```" + `
(paste your output here)
` + "```" + `
`
)
// newBugCmd builds a new Bug command
func newBugCmd(traefikConfiguration *TraefikConfiguration, traefikPointersConfiguration *TraefikConfiguration) *flaeg.Command {
//version Command init
return &flaeg.Command{
Name: "bug",
Description: `Report an issue on Traefik bugtracker`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: runBugCmd(traefikConfiguration),
Metadata: map[string]string{
"parseAllSources": "true",
},
}
}
func runBugCmd(traefikConfiguration *TraefikConfiguration) func() error {
return func() error {
body, err := createBugReport(traefikConfiguration)
if err != nil {
return err
}
sendBugReport(body)
return nil
}
}
func createBugReport(traefikConfiguration *TraefikConfiguration) (string, error) {
var version bytes.Buffer
if err := getVersionPrint(&version); err != nil {
return "", err
}
tmpl, err := template.New("bug").Parse(bugTemplate)
if err != nil {
return "", err
}
config, err := anonymize.Do(traefikConfiguration, true)
if err != nil {
return "", err
}
v := struct {
Version string
Configuration string
}{
Version: version.String(),
Configuration: config,
}
var bug bytes.Buffer
if err := tmpl.Execute(&bug, v); err != nil {
return "", err
}
return bug.String(), nil
}
func sendBugReport(body string) {
URL := bugTracker + "?body=" + url.QueryEscape(body)
if err := openBrowser(URL); err != nil {
fmt.Printf("Please file a new issue at %s using this template:\n\n", bugTracker)
fmt.Print(body)
}
}
func openBrowser(URL string) error {
var err error
switch runtime.GOOS {
case "linux":
err = exec.Command("xdg-open", URL).Start()
case "windows":
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", URL).Start()
case "darwin":
err = exec.Command("open", URL).Start()
default:
err = fmt.Errorf("unsupported platform")
}
return err
}

View file

@ -1,66 +0,0 @@
package main
import (
"testing"
"github.com/containous/traefik/cmd/traefik/anonymize"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
)
func Test_createBugReport(t *testing.T) {
traefikConfiguration := &TraefikConfiguration{
ConfigFile: "FOO",
GlobalConfiguration: configuration.GlobalConfiguration{
EntryPoints: configuration.EntryPoints{
"goo": &configuration.EntryPoint{
Address: "hoo.bar",
Auth: &types.Auth{
Basic: &types.Basic{
UsersFile: "foo Basic UsersFile",
Users: types.Users{"foo Basic Users 1", "foo Basic Users 2", "foo Basic Users 3"},
},
Digest: &types.Digest{
UsersFile: "foo Digest UsersFile",
Users: types.Users{"foo Digest Users 1", "foo Digest Users 2", "foo Digest Users 3"},
},
},
},
},
File: &file.Provider{
Directory: "BAR",
},
RootCAs: tls.RootCAs{"fllf"},
},
}
report, err := createBugReport(traefikConfiguration)
assert.NoError(t, err, report)
// exported anonymous configuration
assert.NotContains(t, "web Basic Users ", report)
assert.NotContains(t, "foo Digest Users ", report)
assert.NotContains(t, "hoo.bar", report)
}
func Test_anonymize_traefikConfiguration(t *testing.T) {
traefikConfiguration := &TraefikConfiguration{
ConfigFile: "FOO",
GlobalConfiguration: configuration.GlobalConfiguration{
EntryPoints: configuration.EntryPoints{
"goo": &configuration.EntryPoint{
Address: "hoo.bar",
},
},
File: &file.Provider{
Directory: "BAR",
},
},
}
_, err := anonymize.Do(traefikConfiguration, true)
assert.NoError(t, err)
assert.Equal(t, "hoo.bar", traefikConfiguration.GlobalConfiguration.EntryPoints["goo"].Address)
}

View file

@ -1,318 +0,0 @@
package main
import (
"time"
"github.com/containous/flaeg"
"github.com/containous/traefik-extra-service-fabric"
"github.com/containous/traefik/api"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/middlewares/accesslog"
"github.com/containous/traefik/middlewares/tracing"
"github.com/containous/traefik/middlewares/tracing/jaeger"
"github.com/containous/traefik/middlewares/tracing/zipkin"
"github.com/containous/traefik/ping"
"github.com/containous/traefik/provider/boltdb"
"github.com/containous/traefik/provider/consul"
"github.com/containous/traefik/provider/consulcatalog"
"github.com/containous/traefik/provider/docker"
"github.com/containous/traefik/provider/dynamodb"
"github.com/containous/traefik/provider/ecs"
"github.com/containous/traefik/provider/etcd"
"github.com/containous/traefik/provider/eureka"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/provider/kubernetes"
"github.com/containous/traefik/provider/marathon"
"github.com/containous/traefik/provider/mesos"
"github.com/containous/traefik/provider/rancher"
"github.com/containous/traefik/provider/rest"
"github.com/containous/traefik/provider/zk"
"github.com/containous/traefik/types"
sf "github.com/jjcollinge/servicefabric"
)
// TraefikConfiguration holds GlobalConfiguration and other stuff
type TraefikConfiguration struct {
configuration.GlobalConfiguration `mapstructure:",squash" export:"true"`
ConfigFile string `short:"c" description:"Configuration file to use (TOML)." export:"true"`
}
// NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values
func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
//default Docker
var defaultDocker docker.Provider
defaultDocker.Watch = true
defaultDocker.ExposedByDefault = true
defaultDocker.Endpoint = "unix:///var/run/docker.sock"
defaultDocker.SwarmMode = false
// default File
var defaultFile file.Provider
defaultFile.Watch = true
defaultFile.Filename = "" //needs equivalent to viper.ConfigFileUsed()
// default Rest
var defaultRest rest.Provider
defaultRest.EntryPoint = configuration.DefaultInternalEntryPointName
// TODO: Deprecated - Web provider, use REST provider instead
var defaultWeb configuration.WebCompatibility
defaultWeb.Address = ":8080"
defaultWeb.Statistics = &types.Statistics{
RecentErrors: 10,
}
// TODO: Deprecated - default Metrics
defaultWeb.Metrics = &types.Metrics{
Prometheus: &types.Prometheus{
Buckets: types.Buckets{0.1, 0.3, 1.2, 5},
EntryPoint: configuration.DefaultInternalEntryPointName,
},
Datadog: &types.Datadog{
Address: "localhost:8125",
PushInterval: "10s",
},
StatsD: &types.Statsd{
Address: "localhost:8125",
PushInterval: "10s",
},
InfluxDB: &types.InfluxDB{
Address: "localhost:8089",
PushInterval: "10s",
},
}
// default Marathon
var defaultMarathon marathon.Provider
defaultMarathon.Watch = true
defaultMarathon.Endpoint = "http://127.0.0.1:8080"
defaultMarathon.ExposedByDefault = true
defaultMarathon.Constraints = types.Constraints{}
defaultMarathon.DialerTimeout = flaeg.Duration(60 * time.Second)
defaultMarathon.KeepAlive = flaeg.Duration(10 * time.Second)
// default Consul
var defaultConsul consul.Provider
defaultConsul.Watch = true
defaultConsul.Endpoint = "127.0.0.1:8500"
defaultConsul.Prefix = "traefik"
defaultConsul.Constraints = types.Constraints{}
// default CatalogProvider
var defaultConsulCatalog consulcatalog.Provider
defaultConsulCatalog.Endpoint = "127.0.0.1:8500"
defaultConsulCatalog.ExposedByDefault = true
defaultConsulCatalog.Constraints = types.Constraints{}
defaultConsulCatalog.Prefix = "traefik"
defaultConsulCatalog.FrontEndRule = "Host:{{.ServiceName}}.{{.Domain}}"
// default Etcd
var defaultEtcd etcd.Provider
defaultEtcd.Watch = true
defaultEtcd.Endpoint = "127.0.0.1:2379"
defaultEtcd.Prefix = "/traefik"
defaultEtcd.Constraints = types.Constraints{}
//default Zookeeper
var defaultZookeeper zk.Provider
defaultZookeeper.Watch = true
defaultZookeeper.Endpoint = "127.0.0.1:2181"
defaultZookeeper.Prefix = "traefik"
defaultZookeeper.Constraints = types.Constraints{}
//default Boltdb
var defaultBoltDb boltdb.Provider
defaultBoltDb.Watch = true
defaultBoltDb.Endpoint = "127.0.0.1:4001"
defaultBoltDb.Prefix = "/traefik"
defaultBoltDb.Constraints = types.Constraints{}
//default Kubernetes
var defaultKubernetes kubernetes.Provider
defaultKubernetes.Watch = true
defaultKubernetes.Constraints = types.Constraints{}
// default Mesos
var defaultMesos mesos.Provider
defaultMesos.Watch = true
defaultMesos.Endpoint = "http://127.0.0.1:5050"
defaultMesos.ExposedByDefault = true
defaultMesos.Constraints = types.Constraints{}
defaultMesos.RefreshSeconds = 30
defaultMesos.ZkDetectionTimeout = 30
defaultMesos.StateTimeoutSecond = 30
//default ECS
var defaultECS ecs.Provider
defaultECS.Watch = true
defaultECS.ExposedByDefault = true
defaultECS.AutoDiscoverClusters = false
defaultECS.Clusters = ecs.Clusters{"default"}
defaultECS.RefreshSeconds = 15
defaultECS.Constraints = types.Constraints{}
//default Rancher
var defaultRancher rancher.Provider
defaultRancher.Watch = true
defaultRancher.ExposedByDefault = true
defaultRancher.RefreshSeconds = 15
// default DynamoDB
var defaultDynamoDB dynamodb.Provider
defaultDynamoDB.Constraints = types.Constraints{}
defaultDynamoDB.RefreshSeconds = 15
defaultDynamoDB.TableName = "traefik"
defaultDynamoDB.Watch = true
// default Eureka
var defaultEureka eureka.Provider
defaultEureka.Delay = flaeg.Duration(30 * time.Second)
// default ServiceFabric
var defaultServiceFabric servicefabric.Provider
defaultServiceFabric.APIVersion = sf.DefaultAPIVersion
defaultServiceFabric.RefreshSeconds = 10
// default Ping
var defaultPing = ping.Handler{
EntryPoint: "traefik",
}
// default TraefikLog
defaultTraefikLog := types.TraefikLog{
Format: "common",
FilePath: "",
}
// default AccessLog
defaultAccessLog := types.AccessLog{
Format: accesslog.CommonFormat,
FilePath: "",
}
// default HealthCheckConfig
healthCheck := configuration.HealthCheckConfig{
Interval: flaeg.Duration(configuration.DefaultHealthCheckInterval),
}
// default RespondingTimeouts
respondingTimeouts := configuration.RespondingTimeouts{
IdleTimeout: flaeg.Duration(configuration.DefaultIdleTimeout),
}
// default ForwardingTimeouts
forwardingTimeouts := configuration.ForwardingTimeouts{
DialTimeout: flaeg.Duration(configuration.DefaultDialTimeout),
}
// default Tracing
defaultTracing := tracing.Tracing{
Backend: "jaeger",
ServiceName: "traefik",
Jaeger: &jaeger.Config{
SamplingServerURL: "http://localhost:5778/sampling",
SamplingType: "const",
SamplingParam: 1.0,
LocalAgentHostPort: "127.0.0.1:6832",
},
Zipkin: &zipkin.Config{
HTTPEndpoint: "http://localhost:9411/api/v1/spans",
SameSpan: false,
ID128Bit: true,
Debug: false,
},
}
// default LifeCycle
defaultLifeCycle := configuration.LifeCycle{
GraceTimeOut: flaeg.Duration(configuration.DefaultGraceTimeout),
}
// default ApiConfiguration
defaultAPI := api.Handler{
EntryPoint: "traefik",
Dashboard: true,
}
defaultAPI.Statistics = &types.Statistics{
RecentErrors: 10,
}
// default Metrics
defaultMetrics := types.Metrics{
Prometheus: &types.Prometheus{
Buckets: types.Buckets{0.1, 0.3, 1.2, 5},
EntryPoint: configuration.DefaultInternalEntryPointName,
},
Datadog: &types.Datadog{
Address: "localhost:8125",
PushInterval: "10s",
},
StatsD: &types.Statsd{
Address: "localhost:8125",
PushInterval: "10s",
},
InfluxDB: &types.InfluxDB{
Address: "localhost:8089",
PushInterval: "10s",
},
}
defaultConfiguration := configuration.GlobalConfiguration{
Docker: &defaultDocker,
File: &defaultFile,
Web: &defaultWeb,
Rest: &defaultRest,
Marathon: &defaultMarathon,
Consul: &defaultConsul,
ConsulCatalog: &defaultConsulCatalog,
Etcd: &defaultEtcd,
Zookeeper: &defaultZookeeper,
Boltdb: &defaultBoltDb,
Kubernetes: &defaultKubernetes,
Mesos: &defaultMesos,
ECS: &defaultECS,
Rancher: &defaultRancher,
Eureka: &defaultEureka,
DynamoDB: &defaultDynamoDB,
Retry: &configuration.Retry{},
HealthCheck: &healthCheck,
RespondingTimeouts: &respondingTimeouts,
ForwardingTimeouts: &forwardingTimeouts,
TraefikLog: &defaultTraefikLog,
AccessLog: &defaultAccessLog,
LifeCycle: &defaultLifeCycle,
Ping: &defaultPing,
API: &defaultAPI,
Metrics: &defaultMetrics,
Tracing: &defaultTracing,
}
return &TraefikConfiguration{
GlobalConfiguration: defaultConfiguration,
}
}
// NewTraefikConfiguration creates a TraefikConfiguration with default values
func NewTraefikConfiguration() *TraefikConfiguration {
return &TraefikConfiguration{
GlobalConfiguration: configuration.GlobalConfiguration{
AccessLogsFile: "",
TraefikLogsFile: "",
LogLevel: "ERROR",
EntryPoints: map[string]*configuration.EntryPoint{},
Constraints: types.Constraints{},
DefaultEntryPoints: []string{"http"},
ProvidersThrottleDuration: flaeg.Duration(2 * time.Second),
MaxIdleConnsPerHost: 200,
IdleTimeout: flaeg.Duration(0),
HealthCheck: &configuration.HealthCheckConfig{
Interval: flaeg.Duration(configuration.DefaultHealthCheckInterval),
},
LifeCycle: &configuration.LifeCycle{
GraceTimeOut: flaeg.Duration(configuration.DefaultGraceTimeout),
},
CheckNewVersion: true,
},
ConfigFile: "",
}
}

View file

@ -1,71 +0,0 @@
package main
import (
"crypto/tls"
"errors"
"fmt"
"net/http"
"os"
"time"
"github.com/containous/flaeg"
"github.com/containous/traefik/configuration"
)
func newHealthCheckCmd(traefikConfiguration *TraefikConfiguration, traefikPointersConfiguration *TraefikConfiguration) *flaeg.Command {
return &flaeg.Command{
Name: "healthcheck",
Description: `Calls traefik /ping to check health (web provider must be enabled)`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: runHealthCheck(traefikConfiguration),
Metadata: map[string]string{
"parseAllSources": "true",
},
}
}
func runHealthCheck(traefikConfiguration *TraefikConfiguration) func() error {
return func() error {
traefikConfiguration.GlobalConfiguration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile)
resp, errPing := healthCheck(traefikConfiguration.GlobalConfiguration)
if errPing != nil {
fmt.Printf("Error calling healthcheck: %s\n", errPing)
os.Exit(1)
}
if resp.StatusCode != http.StatusOK {
fmt.Printf("Bad healthcheck status: %s\n", resp.Status)
os.Exit(1)
}
fmt.Printf("OK: %s\n", resp.Request.URL)
os.Exit(0)
return nil
}
}
func healthCheck(globalConfiguration configuration.GlobalConfiguration) (*http.Response, error) {
if globalConfiguration.Ping == nil {
return nil, errors.New("please enable `ping` to use health check")
}
pingEntryPoint, ok := globalConfiguration.EntryPoints[globalConfiguration.Ping.EntryPoint]
if !ok {
return nil, errors.New("missing `ping` entrypoint")
}
client := &http.Client{Timeout: 5 * time.Second}
protocol := "http"
if pingEntryPoint.TLS != nil {
protocol = "https"
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client.Transport = tr
}
path := "/"
if globalConfiguration.Web != nil {
path = globalConfiguration.Web.Path
}
return client.Head(protocol + "://" + pingEntryPoint.Address + path + "ping")
}

View file

@ -1,149 +0,0 @@
package main
import (
"encoding/json"
"fmt"
stdlog "log"
"github.com/abronan/valkeyrie/store"
"github.com/containous/flaeg"
"github.com/containous/staert"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/cluster"
)
func newStoreConfigCmd(traefikConfiguration *TraefikConfiguration, traefikPointersConfiguration *TraefikConfiguration) *flaeg.Command {
return &flaeg.Command{
Name: "storeconfig",
Description: `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Metadata: map[string]string{
"parseAllSources": "true",
},
}
}
func runStoreConfig(kv *staert.KvSource, traefikConfiguration *TraefikConfiguration) func() error {
return func() error {
if kv == nil {
return fmt.Errorf("error using command storeconfig, no Key-value store defined")
}
fileConfig := traefikConfiguration.GlobalConfiguration.File
if fileConfig != nil {
traefikConfiguration.GlobalConfiguration.File = nil
if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
fileConfig.Filename = traefikConfiguration.ConfigFile
}
}
jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
if err != nil {
return err
}
stdlog.Printf("Storing configuration: %s\n", jsonConf)
err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
if err != nil {
return err
}
if fileConfig != nil {
jsonConf, err = json.Marshal(fileConfig)
if err != nil {
return err
}
stdlog.Printf("Storing file configuration: %s\n", jsonConf)
config, err := fileConfig.BuildConfiguration()
if err != nil {
return err
}
stdlog.Print("Writing config to KV")
err = kv.StoreConfig(config)
if err != nil {
return err
}
}
if traefikConfiguration.GlobalConfiguration.ACME != nil {
var object cluster.Object
if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
// convert ACME json file to KV store
localStore := acme.NewLocalStore(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
object, err = localStore.Load()
if err != nil {
return err
}
} else {
// Create an empty account to create all the keys into the KV store
account := &acme.Account{}
err = account.Init()
if err != nil {
return err
}
object = account
}
meta := cluster.NewMetadata(object)
err = meta.Marshall()
if err != nil {
return err
}
source := staert.KvSource{
Store: kv,
Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
}
err = source.StoreConfig(meta)
if err != nil {
return err
}
// Force to delete storagefile
err = kv.Delete(kv.Prefix + "/acme/storagefile")
if err != nil {
return err
}
}
return nil
}
}
// createKvSource creates KvSource
// TLS support is enable for Consul and Etcd backends
func createKvSource(traefikConfiguration *TraefikConfiguration) (*staert.KvSource, error) {
var kv *staert.KvSource
var kvStore store.Store
var err error
switch {
case traefikConfiguration.Consul != nil:
kvStore, err = traefikConfiguration.Consul.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Consul.Prefix,
}
case traefikConfiguration.Etcd != nil:
kvStore, err = traefikConfiguration.Etcd.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Etcd.Prefix,
}
case traefikConfiguration.Zookeeper != nil:
kvStore, err = traefikConfiguration.Zookeeper.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Zookeeper.Prefix,
}
case traefikConfiguration.Boltdb != nil:
kvStore, err = traefikConfiguration.Boltdb.CreateStore()
kv = &staert.KvSource{
Store: kvStore,
Prefix: traefikConfiguration.Boltdb.Prefix,
}
}
return kv, err
}

View file

@ -14,6 +14,11 @@ import (
"github.com/containous/flaeg"
"github.com/containous/staert"
"github.com/containous/traefik/acme"
"github.com/containous/traefik/cmd"
"github.com/containous/traefik/cmd/bug"
"github.com/containous/traefik/cmd/healthcheck"
"github.com/containous/traefik/cmd/storeconfig"
cmdVersion "github.com/containous/traefik/cmd/version"
"github.com/containous/traefik/collector"
"github.com/containous/traefik/configuration"
"github.com/containous/traefik/job"
@ -33,8 +38,8 @@ import (
func main() {
// traefik config inits
traefikConfiguration := NewTraefikConfiguration()
traefikPointersConfiguration := NewTraefikDefaultPointersConfiguration()
traefikConfiguration := cmd.NewTraefikConfiguration()
traefikPointersConfiguration := cmd.NewTraefikDefaultPointersConfiguration()
// traefik Command init
traefikCmd := &flaeg.Command{
@ -44,13 +49,13 @@ Complete documentation is available at https://traefik.io`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: func() error {
run(&traefikConfiguration.GlobalConfiguration, traefikConfiguration.ConfigFile)
runCmd(&traefikConfiguration.GlobalConfiguration, traefikConfiguration.ConfigFile)
return nil
},
}
// storeconfig Command init
storeConfigCmd := newStoreConfigCmd(traefikConfiguration, traefikPointersConfiguration)
storeConfigCmd := storeconfig.NewCmd(traefikConfiguration, traefikPointersConfiguration)
// init flaeg source
f := flaeg.New(traefikCmd, os.Args[1:])
@ -65,10 +70,10 @@ Complete documentation is available at https://traefik.io`,
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
// add commands
f.AddCommand(newVersionCmd())
f.AddCommand(newBugCmd(traefikConfiguration, traefikPointersConfiguration))
f.AddCommand(cmdVersion.NewCmd())
f.AddCommand(bug.NewCmd(traefikConfiguration, traefikPointersConfiguration))
f.AddCommand(storeConfigCmd)
f.AddCommand(newHealthCheckCmd(traefikConfiguration, traefikPointersConfiguration))
f.AddCommand(healthcheck.NewCmd(traefikConfiguration, traefikPointersConfiguration))
usedCmd, err := f.GetCommand()
if err != nil {
@ -99,12 +104,12 @@ Complete documentation is available at https://traefik.io`,
traefikConfiguration.ConfigFile = toml.ConfigFileUsed()
kv, err := createKvSource(traefikConfiguration)
kv, err := storeconfig.CreateKvSource(traefikConfiguration)
if err != nil {
fmtlog.Printf("Error creating kv store: %s\n", err)
os.Exit(1)
}
storeConfigCmd.Run = runStoreConfig(kv, traefikConfiguration)
storeConfigCmd.Run = storeconfig.Run(kv, traefikConfiguration)
// if a KV Store is enable and no sub-command called in args
if kv != nil && usedCmd == traefikCmd {
@ -137,7 +142,7 @@ Complete documentation is available at https://traefik.io`,
os.Exit(0)
}
func run(globalConfiguration *configuration.GlobalConfiguration, configFile string) {
func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile string) {
configureLogging(globalConfiguration)
if len(configFile) > 0 {
@ -178,7 +183,7 @@ func run(globalConfiguration *configuration.GlobalConfiguration, configFile stri
safe.Go(func() {
tick := time.Tick(t)
for range tick {
_, errHealthCheck := healthCheck(*globalConfiguration)
_, errHealthCheck := healthcheck.Do(*globalConfiguration)
if globalConfiguration.Ping == nil || errHealthCheck == nil {
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
log.Error("Fail to tick watchdog")

View file

@ -1,63 +0,0 @@
package main
import (
"fmt"
"io"
"os"
"runtime"
"text/template"
"github.com/containous/flaeg"
"github.com/containous/traefik/version"
)
var versionTemplate = `Version: {{.Version}}
Codename: {{.Codename}}
Go version: {{.GoVersion}}
Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}`
// newVersionCmd builds a new Version command
func newVersionCmd() *flaeg.Command {
//version Command init
return &flaeg.Command{
Name: "version",
Description: `Print version`,
Config: struct{}{},
DefaultPointersConfig: struct{}{},
Run: func() error {
if err := getVersionPrint(os.Stdout); err != nil {
return err
}
fmt.Print("\n")
return nil
},
}
}
func getVersionPrint(wr io.Writer) error {
tmpl, err := template.New("").Parse(versionTemplate)
if err != nil {
return err
}
v := struct {
Version string
Codename string
GoVersion string
BuildTime string
Os string
Arch string
}{
Version: version.Version,
Codename: version.Codename,
GoVersion: runtime.Version(),
BuildTime: version.BuildDate,
Os: runtime.GOOS,
Arch: runtime.GOARCH,
}
return tmpl.Execute(wr, v)
}