1
0
Fork 0

Add KV store providers (dynamic configuration only)

Co-authored-by: Jean-Baptiste Doumenjou <jb.doumenjou@gmail.com>
This commit is contained in:
Ludovic Fernandez 2019-11-28 21:56:04 +01:00 committed by Traefiker Bot
parent 028683666d
commit 9b9f4be6a4
61 changed files with 5825 additions and 70 deletions

159
integration/consul_test.go Normal file
View file

@ -0,0 +1,159 @@
package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"time"
"github.com/abronan/valkeyrie"
"github.com/abronan/valkeyrie/store"
"github.com/abronan/valkeyrie/store/consul"
"github.com/containous/traefik/v2/integration/try"
"github.com/containous/traefik/v2/pkg/api"
"github.com/go-check/check"
"github.com/pmezard/go-difflib/difflib"
checker "github.com/vdemeester/shakers"
)
// Consul test suites (using libcompose)
type ConsulSuite struct {
BaseSuite
kvClient store.Store
}
func (s *ConsulSuite) setupStore(c *check.C) {
s.createComposeProject(c, "consul")
s.composeProject.Start(c)
consul.Register()
kv, err := valkeyrie.NewStore(
store.CONSUL,
[]string{s.composeProject.Container(c, "consul").NetworkSettings.IPAddress + ":8500"},
&store.Config{
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store consul")
}
s.kvClient = kv
// wait for consul
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
func (s *ConsulSuite) TearDownTest(c *check.C) {
// shutdown and delete compose project
if s.composeProject != nil {
s.composeProject.Stop(c)
}
}
func (s *ConsulSuite) TearDownSuite(c *check.C) {}
func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
address := "http://" + s.composeProject.Container(c, "consul").NetworkSettings.IPAddress + ":8500"
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulAddress string }{address})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
"traefik/http/routers/Router0/middlewares/0": "compressor",
"traefik/http/routers/Router0/middlewares/1": "striper",
"traefik/http/routers/Router0/service": "simplesvc",
"traefik/http/routers/Router0/rule": "Host(`kv1.localhost`)",
"traefik/http/routers/Router0/priority": "42",
"traefik/http/routers/Router0/tls": "",
"traefik/http/routers/Router1/rule": "Host(`kv2.localhost`)",
"traefik/http/routers/Router1/priority": "42",
"traefik/http/routers/Router1/tls/domains/0/main": "aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/0": "aaa.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/1": "bbb.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/1/main": "bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/0": "aaa.bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/1": "bbb.bbb.localhost",
"traefik/http/routers/Router1/entryPoints/0": "web",
"traefik/http/routers/Router1/service": "simplesvc",
"traefik/http/services/simplesvc/loadBalancer/servers/0/url": "http://10.0.1.1:8888",
"traefik/http/services/simplesvc/loadBalancer/servers/1/url": "http://10.0.1.1:8889",
"traefik/http/services/srvcA/loadBalancer/servers/0/url": "http://10.0.1.2:8888",
"traefik/http/services/srvcA/loadBalancer/servers/1/url": "http://10.0.1.2:8889",
"traefik/http/services/srvcB/loadBalancer/servers/0/url": "http://10.0.1.3:8888",
"traefik/http/services/srvcB/loadBalancer/servers/1/url": "http://10.0.1.3:8889",
"traefik/http/services/mirror/mirroring/service": "simplesvc",
"traefik/http/services/mirror/mirroring/mirrors/0/name": "srvcA",
"traefik/http/services/mirror/mirroring/mirrors/0/percent": "42",
"traefik/http/services/mirror/mirroring/mirrors/1/name": "srvcB",
"traefik/http/services/mirror/mirroring/mirrors/1/percent": "42",
"traefik/http/services/Service03/weighted/services/0/name": "srvcA",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "srvcB",
"traefik/http/services/Service03/weighted/services/1/weight": "42",
"traefik/http/middlewares/compressor/compress": "",
"traefik/http/middlewares/striper/stripPrefix/prefixes/0": "foo",
"traefik/http/middlewares/striper/stripPrefix/prefixes/1": "bar",
"traefik/http/middlewares/striper/stripPrefix/forceSlash": "true",
}
for k, v := range data {
err := s.kvClient.Put(k, []byte(v), nil)
c.Assert(err, checker.IsNil)
}
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("@consul"))
c.Assert(err, checker.IsNil)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
expectedJSON := filepath.FromSlash("testdata/rawdata-consul.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
FromFile: "Expected",
A: difflib.SplitLines(string(expected)),
ToFile: "Got",
B: difflib.SplitLines(string(got)),
Context: 3,
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
}
}

159
integration/etcd_test.go Normal file
View file

@ -0,0 +1,159 @@
package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"time"
"github.com/abronan/valkeyrie"
"github.com/abronan/valkeyrie/store"
etcdv3 "github.com/abronan/valkeyrie/store/etcd/v3"
"github.com/containous/traefik/v2/integration/try"
"github.com/containous/traefik/v2/pkg/api"
"github.com/go-check/check"
"github.com/pmezard/go-difflib/difflib"
checker "github.com/vdemeester/shakers"
)
// etcd test suites (using libcompose)
type EtcdSuite struct {
BaseSuite
kvClient store.Store
}
func (s *EtcdSuite) setupStore(c *check.C) {
s.createComposeProject(c, "etcd")
s.composeProject.Start(c)
etcdv3.Register()
kv, err := valkeyrie.NewStore(
store.ETCDV3,
[]string{s.composeProject.Container(c, "etcd").NetworkSettings.IPAddress + ":2379"},
&store.Config{
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store etcd")
}
s.kvClient = kv
// wait for etcd
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
func (s *EtcdSuite) TearDownTest(c *check.C) {
// shutdown and delete compose project
if s.composeProject != nil {
s.composeProject.Stop(c)
}
}
func (s *EtcdSuite) TearDownSuite(c *check.C) {}
func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
address := s.composeProject.Container(c, "etcd").NetworkSettings.IPAddress + ":2379"
file := s.adaptFile(c, "fixtures/etcd/simple.toml", struct{ EtcdAddress string }{address})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
"traefik/http/routers/Router0/middlewares/0": "compressor",
"traefik/http/routers/Router0/middlewares/1": "striper",
"traefik/http/routers/Router0/service": "simplesvc",
"traefik/http/routers/Router0/rule": "Host(`kv1.localhost`)",
"traefik/http/routers/Router0/priority": "42",
"traefik/http/routers/Router0/tls": "",
"traefik/http/routers/Router1/rule": "Host(`kv2.localhost`)",
"traefik/http/routers/Router1/priority": "42",
"traefik/http/routers/Router1/tls/domains/0/main": "aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/0": "aaa.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/1": "bbb.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/1/main": "bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/0": "aaa.bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/1": "bbb.bbb.localhost",
"traefik/http/routers/Router1/entryPoints/0": "web",
"traefik/http/routers/Router1/service": "simplesvc",
"traefik/http/services/simplesvc/loadBalancer/servers/0/url": "http://10.0.1.1:8888",
"traefik/http/services/simplesvc/loadBalancer/servers/1/url": "http://10.0.1.1:8889",
"traefik/http/services/srvcA/loadBalancer/servers/0/url": "http://10.0.1.2:8888",
"traefik/http/services/srvcA/loadBalancer/servers/1/url": "http://10.0.1.2:8889",
"traefik/http/services/srvcB/loadBalancer/servers/0/url": "http://10.0.1.3:8888",
"traefik/http/services/srvcB/loadBalancer/servers/1/url": "http://10.0.1.3:8889",
"traefik/http/services/mirror/mirroring/service": "simplesvc",
"traefik/http/services/mirror/mirroring/mirrors/0/name": "srvcA",
"traefik/http/services/mirror/mirroring/mirrors/0/percent": "42",
"traefik/http/services/mirror/mirroring/mirrors/1/name": "srvcB",
"traefik/http/services/mirror/mirroring/mirrors/1/percent": "42",
"traefik/http/services/Service03/weighted/services/0/name": "srvcA",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "srvcB",
"traefik/http/services/Service03/weighted/services/1/weight": "42",
"traefik/http/middlewares/compressor/compress": "",
"traefik/http/middlewares/striper/stripPrefix/prefixes/0": "foo",
"traefik/http/middlewares/striper/stripPrefix/prefixes/1": "bar",
"traefik/http/middlewares/striper/stripPrefix/forceSlash": "true",
}
for k, v := range data {
err := s.kvClient.Put(k, []byte(v), nil)
c.Assert(err, checker.IsNil)
}
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("@etcd"))
c.Assert(err, checker.IsNil)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
expectedJSON := filepath.FromSlash("testdata/rawdata-etcd.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
FromFile: "Expected",
A: difflib.SplitLines(string(expected)),
ToFile: "Got",
B: difflib.SplitLines(string(got)),
Context: 3,
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
}
}

View file

@ -0,0 +1,16 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints.web]
address = ":8000"
[api]
insecure = true
[providers.consul]
rootKey = "traefik"
endpoints = ["{{ .ConsulAddress }}"]

View file

@ -0,0 +1,16 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints.web]
address = ":8000"
[api]
insecure = true
[providers.etcd]
rootKey = "traefik"
endpoints = ["{{ .EtcdAddress }}"]

View file

@ -0,0 +1,16 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints.web]
address = ":8000"
[api]
insecure = true
[providers.redis]
rootKey = "traefik"
endpoints = ["{{ .RedisAddress }}"]

View file

@ -0,0 +1,16 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints.web]
address = ":8000"
[api]
insecure = true
[providers.zookeeper]
rootKey = "traefik"
endpoints = ["{{ .ZkAddress }}"]

View file

@ -36,6 +36,8 @@ func Test(t *testing.T) {
// tests launched from a container
check.Suite(&AccessLogSuite{})
check.Suite(&AcmeSuite{})
check.Suite(&EtcdSuite{})
check.Suite(&ConsulSuite{})
check.Suite(&ConsulCatalogSuite{})
check.Suite(&DockerComposeSuite{})
check.Suite(&DockerSuite{})
@ -51,6 +53,7 @@ func Test(t *testing.T) {
check.Suite(&MarathonSuite{})
check.Suite(&MarathonSuite15{})
check.Suite(&RateLimitSuite{})
check.Suite(&RedisSuite{})
check.Suite(&RestSuite{})
check.Suite(&RetrySuite{})
check.Suite(&SimpleSuite{})
@ -58,6 +61,7 @@ func Test(t *testing.T) {
check.Suite(&TLSClientHeadersSuite{})
check.Suite(&TracingSuite{})
check.Suite(&WebsocketSuite{})
check.Suite(&ZookeeperSuite{})
}
if *host {
// tests launched from the host

159
integration/redis_test.go Normal file
View file

@ -0,0 +1,159 @@
package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"time"
"github.com/abronan/valkeyrie"
"github.com/abronan/valkeyrie/store"
"github.com/abronan/valkeyrie/store/redis"
"github.com/containous/traefik/v2/integration/try"
"github.com/containous/traefik/v2/pkg/api"
"github.com/go-check/check"
"github.com/pmezard/go-difflib/difflib"
checker "github.com/vdemeester/shakers"
)
// Redis test suites (using libcompose)
type RedisSuite struct {
BaseSuite
kvClient store.Store
}
func (s *RedisSuite) setupStore(c *check.C) {
s.createComposeProject(c, "redis")
s.composeProject.Start(c)
redis.Register()
kv, err := valkeyrie.NewStore(
store.REDIS,
[]string{s.composeProject.Container(c, "redis").NetworkSettings.IPAddress + ":6379"},
&store.Config{
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store redis")
}
s.kvClient = kv
// wait for redis
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
func (s *RedisSuite) TearDownTest(c *check.C) {
// shutdown and delete compose project
if s.composeProject != nil {
s.composeProject.Stop(c)
}
}
func (s *RedisSuite) TearDownSuite(c *check.C) {}
func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
address := s.composeProject.Container(c, "redis").NetworkSettings.IPAddress + ":6379"
file := s.adaptFile(c, "fixtures/redis/simple.toml", struct{ RedisAddress string }{address})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
"traefik/http/routers/Router0/middlewares/0": "compressor",
"traefik/http/routers/Router0/middlewares/1": "striper",
"traefik/http/routers/Router0/service": "simplesvc",
"traefik/http/routers/Router0/rule": "Host(`kv1.localhost`)",
"traefik/http/routers/Router0/priority": "42",
"traefik/http/routers/Router0/tls": "",
"traefik/http/routers/Router1/rule": "Host(`kv2.localhost`)",
"traefik/http/routers/Router1/priority": "42",
"traefik/http/routers/Router1/tls/domains/0/main": "aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/0": "aaa.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/1": "bbb.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/1/main": "bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/0": "aaa.bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/1": "bbb.bbb.localhost",
"traefik/http/routers/Router1/entryPoints/0": "web",
"traefik/http/routers/Router1/service": "simplesvc",
"traefik/http/services/simplesvc/loadBalancer/servers/0/url": "http://10.0.1.1:8888",
"traefik/http/services/simplesvc/loadBalancer/servers/1/url": "http://10.0.1.1:8889",
"traefik/http/services/srvcA/loadBalancer/servers/0/url": "http://10.0.1.2:8888",
"traefik/http/services/srvcA/loadBalancer/servers/1/url": "http://10.0.1.2:8889",
"traefik/http/services/srvcB/loadBalancer/servers/0/url": "http://10.0.1.3:8888",
"traefik/http/services/srvcB/loadBalancer/servers/1/url": "http://10.0.1.3:8889",
"traefik/http/services/mirror/mirroring/service": "simplesvc",
"traefik/http/services/mirror/mirroring/mirrors/0/name": "srvcA",
"traefik/http/services/mirror/mirroring/mirrors/0/percent": "42",
"traefik/http/services/mirror/mirroring/mirrors/1/name": "srvcB",
"traefik/http/services/mirror/mirroring/mirrors/1/percent": "42",
"traefik/http/services/Service03/weighted/services/0/name": "srvcA",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "srvcB",
"traefik/http/services/Service03/weighted/services/1/weight": "42",
"traefik/http/middlewares/compressor/compress": "",
"traefik/http/middlewares/striper/stripPrefix/prefixes/0": "foo",
"traefik/http/middlewares/striper/stripPrefix/prefixes/1": "bar",
"traefik/http/middlewares/striper/stripPrefix/forceSlash": "true",
}
for k, v := range data {
err := s.kvClient.Put(k, []byte(v), nil)
c.Assert(err, checker.IsNil)
}
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("@redis"))
c.Assert(err, checker.IsNil)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
expectedJSON := filepath.FromSlash("testdata/rawdata-redis.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
FromFile: "Expected",
A: difflib.SplitLines(string(expected)),
ToFile: "Got",
B: difflib.SplitLines(string(got)),
Context: 3,
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
}
}

View file

@ -0,0 +1,4 @@
consul:
image: consul:1.6
ports:
- "8500:8500"

View file

@ -0,0 +1,5 @@
etcd:
image: quay.io/coreos/etcd:v3.3.18
command: etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2380
ports:
- "2379:2379"

View file

@ -0,0 +1,4 @@
redis:
image: redis:5.0
ports:
- "6379:6379"

View file

@ -0,0 +1,4 @@
zookeeper:
image: zookeeper:3.5
ports:
- "2181:2181"

219
integration/testdata/rawdata-consul.json vendored Normal file
View file

@ -0,0 +1,219 @@
{
"routers": {
"Router0@consul": {
"entryPoints": [
"web"
],
"middlewares": [
"compressor@consul",
"striper@consul"
],
"service": "simplesvc",
"rule": "Host(`kv1.localhost`)",
"priority": 42,
"tls": {},
"status": "enabled",
"using": [
"web"
]
},
"Router1@consul": {
"entryPoints": [
"web"
],
"service": "simplesvc",
"rule": "Host(`kv2.localhost`)",
"priority": 42,
"tls": {
"domains": [
{
"main": "aaa.localhost",
"sans": [
"aaa.aaa.localhost",
"bbb.aaa.localhost"
]
},
{
"main": "bbb.localhost",
"sans": [
"aaa.bbb.localhost",
"bbb.bbb.localhost"
]
}
]
},
"status": "enabled",
"using": [
"web"
]
},
"api@internal": {
"entryPoints": [
"traefik"
],
"service": "api@internal",
"rule": "PathPrefix(`/api`)",
"priority": 2147483646,
"status": "enabled",
"using": [
"traefik"
]
},
"dashboard@internal": {
"entryPoints": [
"traefik"
],
"middlewares": [
"dashboard_redirect@internal",
"dashboard_stripprefix@internal"
],
"service": "dashboard@internal",
"rule": "PathPrefix(`/`)",
"priority": 2147483645,
"status": "enabled",
"using": [
"traefik"
]
}
},
"middlewares": {
"compressor@consul": {
"compress": {},
"status": "enabled",
"usedBy": [
"Router0@consul"
]
},
"dashboard_redirect@internal": {
"redirectRegex": {
"regex": "^(http:\\/\\/[^:]+(:\\d+)?)/$",
"replacement": "${1}/dashboard/",
"permanent": true
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"dashboard_stripprefix@internal": {
"stripPrefix": {
"prefixes": [
"/dashboard/",
"/dashboard"
]
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"striper@consul": {
"stripPrefix": {
"prefixes": [
"foo",
"bar"
],
"forceSlash": true
},
"status": "enabled",
"usedBy": [
"Router0@consul"
]
}
},
"services": {
"Service03@consul": {
"weighted": {
"services": [
{
"name": "srvcA",
"weight": 42
},
{
"name": "srvcB",
"weight": 42
}
]
},
"status": "enabled"
},
"api@internal": {
"status": "enabled",
"usedBy": [
"api@internal"
]
},
"dashboard@internal": {
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"mirror@consul": {
"mirroring": {
"service": "simplesvc",
"mirrors": [
{
"name": "srvcA",
"percent": 42
},
{
"name": "srvcB",
"percent": 42
}
]
},
"status": "enabled"
},
"simplesvc@consul": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.1:8888"
},
{
"url": "http://10.0.1.1:8889"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"Router0@consul",
"Router1@consul"
],
"serverStatus": {
"http://10.0.1.1:8888": "UP",
"http://10.0.1.1:8889": "UP"
}
},
"srvcA@consul": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.2:8888"
},
{
"url": "http://10.0.1.2:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
},
"srvcB@consul": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.3:8888"
},
{
"url": "http://10.0.1.3:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
}
}
}

219
integration/testdata/rawdata-etcd.json vendored Normal file
View file

@ -0,0 +1,219 @@
{
"routers": {
"Router0@etcd": {
"entryPoints": [
"web"
],
"middlewares": [
"compressor@etcd",
"striper@etcd"
],
"service": "simplesvc",
"rule": "Host(`kv1.localhost`)",
"priority": 42,
"tls": {},
"status": "enabled",
"using": [
"web"
]
},
"Router1@etcd": {
"entryPoints": [
"web"
],
"service": "simplesvc",
"rule": "Host(`kv2.localhost`)",
"priority": 42,
"tls": {
"domains": [
{
"main": "aaa.localhost",
"sans": [
"aaa.aaa.localhost",
"bbb.aaa.localhost"
]
},
{
"main": "bbb.localhost",
"sans": [
"aaa.bbb.localhost",
"bbb.bbb.localhost"
]
}
]
},
"status": "enabled",
"using": [
"web"
]
},
"api@internal": {
"entryPoints": [
"traefik"
],
"service": "api@internal",
"rule": "PathPrefix(`/api`)",
"priority": 2147483646,
"status": "enabled",
"using": [
"traefik"
]
},
"dashboard@internal": {
"entryPoints": [
"traefik"
],
"middlewares": [
"dashboard_redirect@internal",
"dashboard_stripprefix@internal"
],
"service": "dashboard@internal",
"rule": "PathPrefix(`/`)",
"priority": 2147483645,
"status": "enabled",
"using": [
"traefik"
]
}
},
"middlewares": {
"compressor@etcd": {
"compress": {},
"status": "enabled",
"usedBy": [
"Router0@etcd"
]
},
"dashboard_redirect@internal": {
"redirectRegex": {
"regex": "^(http:\\/\\/[^:]+(:\\d+)?)/$",
"replacement": "${1}/dashboard/",
"permanent": true
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"dashboard_stripprefix@internal": {
"stripPrefix": {
"prefixes": [
"/dashboard/",
"/dashboard"
]
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"striper@etcd": {
"stripPrefix": {
"prefixes": [
"foo",
"bar"
],
"forceSlash": true
},
"status": "enabled",
"usedBy": [
"Router0@etcd"
]
}
},
"services": {
"Service03@etcd": {
"weighted": {
"services": [
{
"name": "srvcA",
"weight": 42
},
{
"name": "srvcB",
"weight": 42
}
]
},
"status": "enabled"
},
"api@internal": {
"status": "enabled",
"usedBy": [
"api@internal"
]
},
"dashboard@internal": {
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"mirror@etcd": {
"mirroring": {
"service": "simplesvc",
"mirrors": [
{
"name": "srvcA",
"percent": 42
},
{
"name": "srvcB",
"percent": 42
}
]
},
"status": "enabled"
},
"simplesvc@etcd": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.1:8888"
},
{
"url": "http://10.0.1.1:8889"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"Router0@etcd",
"Router1@etcd"
],
"serverStatus": {
"http://10.0.1.1:8888": "UP",
"http://10.0.1.1:8889": "UP"
}
},
"srvcA@etcd": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.2:8888"
},
{
"url": "http://10.0.1.2:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
},
"srvcB@etcd": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.3:8888"
},
{
"url": "http://10.0.1.3:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
}
}
}

219
integration/testdata/rawdata-redis.json vendored Normal file
View file

@ -0,0 +1,219 @@
{
"routers": {
"Router0@redis": {
"entryPoints": [
"web"
],
"middlewares": [
"compressor@redis",
"striper@redis"
],
"service": "simplesvc",
"rule": "Host(`kv1.localhost`)",
"priority": 42,
"tls": {},
"status": "enabled",
"using": [
"web"
]
},
"Router1@redis": {
"entryPoints": [
"web"
],
"service": "simplesvc",
"rule": "Host(`kv2.localhost`)",
"priority": 42,
"tls": {
"domains": [
{
"main": "aaa.localhost",
"sans": [
"aaa.aaa.localhost",
"bbb.aaa.localhost"
]
},
{
"main": "bbb.localhost",
"sans": [
"aaa.bbb.localhost",
"bbb.bbb.localhost"
]
}
]
},
"status": "enabled",
"using": [
"web"
]
},
"api@internal": {
"entryPoints": [
"traefik"
],
"service": "api@internal",
"rule": "PathPrefix(`/api`)",
"priority": 2147483646,
"status": "enabled",
"using": [
"traefik"
]
},
"dashboard@internal": {
"entryPoints": [
"traefik"
],
"middlewares": [
"dashboard_redirect@internal",
"dashboard_stripprefix@internal"
],
"service": "dashboard@internal",
"rule": "PathPrefix(`/`)",
"priority": 2147483645,
"status": "enabled",
"using": [
"traefik"
]
}
},
"middlewares": {
"compressor@redis": {
"compress": {},
"status": "enabled",
"usedBy": [
"Router0@redis"
]
},
"dashboard_redirect@internal": {
"redirectRegex": {
"regex": "^(http:\\/\\/[^:]+(:\\d+)?)/$",
"replacement": "${1}/dashboard/",
"permanent": true
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"dashboard_stripprefix@internal": {
"stripPrefix": {
"prefixes": [
"/dashboard/",
"/dashboard"
]
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"striper@redis": {
"stripPrefix": {
"prefixes": [
"foo",
"bar"
],
"forceSlash": true
},
"status": "enabled",
"usedBy": [
"Router0@redis"
]
}
},
"services": {
"Service03@redis": {
"weighted": {
"services": [
{
"name": "srvcA",
"weight": 42
},
{
"name": "srvcB",
"weight": 42
}
]
},
"status": "enabled"
},
"api@internal": {
"status": "enabled",
"usedBy": [
"api@internal"
]
},
"dashboard@internal": {
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"mirror@redis": {
"mirroring": {
"service": "simplesvc",
"mirrors": [
{
"name": "srvcA",
"percent": 42
},
{
"name": "srvcB",
"percent": 42
}
]
},
"status": "enabled"
},
"simplesvc@redis": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.1:8888"
},
{
"url": "http://10.0.1.1:8889"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"Router0@redis",
"Router1@redis"
],
"serverStatus": {
"http://10.0.1.1:8888": "UP",
"http://10.0.1.1:8889": "UP"
}
},
"srvcA@redis": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.2:8888"
},
{
"url": "http://10.0.1.2:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
},
"srvcB@redis": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.3:8888"
},
{
"url": "http://10.0.1.3:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
}
}
}

219
integration/testdata/rawdata-zk.json vendored Normal file
View file

@ -0,0 +1,219 @@
{
"routers": {
"Router0@zookeeper": {
"entryPoints": [
"web"
],
"middlewares": [
"compressor@zookeeper",
"striper@zookeeper"
],
"service": "simplesvc",
"rule": "Host(`kv1.localhost`)",
"priority": 42,
"tls": {},
"status": "enabled",
"using": [
"web"
]
},
"Router1@zookeeper": {
"entryPoints": [
"web"
],
"service": "simplesvc",
"rule": "Host(`kv2.localhost`)",
"priority": 42,
"tls": {
"domains": [
{
"main": "aaa.localhost",
"sans": [
"aaa.aaa.localhost",
"bbb.aaa.localhost"
]
},
{
"main": "bbb.localhost",
"sans": [
"aaa.bbb.localhost",
"bbb.bbb.localhost"
]
}
]
},
"status": "enabled",
"using": [
"web"
]
},
"api@internal": {
"entryPoints": [
"traefik"
],
"service": "api@internal",
"rule": "PathPrefix(`/api`)",
"priority": 2147483646,
"status": "enabled",
"using": [
"traefik"
]
},
"dashboard@internal": {
"entryPoints": [
"traefik"
],
"middlewares": [
"dashboard_redirect@internal",
"dashboard_stripprefix@internal"
],
"service": "dashboard@internal",
"rule": "PathPrefix(`/`)",
"priority": 2147483645,
"status": "enabled",
"using": [
"traefik"
]
}
},
"middlewares": {
"compressor@zookeeper": {
"compress": {},
"status": "enabled",
"usedBy": [
"Router0@zookeeper"
]
},
"dashboard_redirect@internal": {
"redirectRegex": {
"regex": "^(http:\\/\\/[^:]+(:\\d+)?)/$",
"replacement": "${1}/dashboard/",
"permanent": true
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"dashboard_stripprefix@internal": {
"stripPrefix": {
"prefixes": [
"/dashboard/",
"/dashboard"
]
},
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"striper@zookeeper": {
"stripPrefix": {
"prefixes": [
"foo",
"bar"
],
"forceSlash": true
},
"status": "enabled",
"usedBy": [
"Router0@zookeeper"
]
}
},
"services": {
"Service03@zookeeper": {
"weighted": {
"services": [
{
"name": "srvcA",
"weight": 42
},
{
"name": "srvcB",
"weight": 42
}
]
},
"status": "enabled"
},
"api@internal": {
"status": "enabled",
"usedBy": [
"api@internal"
]
},
"dashboard@internal": {
"status": "enabled",
"usedBy": [
"dashboard@internal"
]
},
"mirror@zookeeper": {
"mirroring": {
"service": "simplesvc",
"mirrors": [
{
"name": "srvcA",
"percent": 42
},
{
"name": "srvcB",
"percent": 42
}
]
},
"status": "enabled"
},
"simplesvc@zookeeper": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.1:8888"
},
{
"url": "http://10.0.1.1:8889"
}
],
"passHostHeader": true
},
"status": "enabled",
"usedBy": [
"Router0@zookeeper",
"Router1@zookeeper"
],
"serverStatus": {
"http://10.0.1.1:8888": "UP",
"http://10.0.1.1:8889": "UP"
}
},
"srvcA@zookeeper": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.2:8888"
},
{
"url": "http://10.0.1.2:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
},
"srvcB@zookeeper": {
"loadBalancer": {
"servers": [
{
"url": "http://10.0.1.3:8888"
},
{
"url": "http://10.0.1.3:8889"
}
],
"passHostHeader": true
},
"status": "enabled"
}
}
}

159
integration/zk_test.go Normal file
View file

@ -0,0 +1,159 @@
package integration
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"time"
"github.com/abronan/valkeyrie"
"github.com/abronan/valkeyrie/store"
"github.com/abronan/valkeyrie/store/zookeeper"
"github.com/containous/traefik/v2/integration/try"
"github.com/containous/traefik/v2/pkg/api"
"github.com/go-check/check"
"github.com/pmezard/go-difflib/difflib"
checker "github.com/vdemeester/shakers"
)
// Zk test suites (using libcompose)
type ZookeeperSuite struct {
BaseSuite
kvClient store.Store
}
func (s *ZookeeperSuite) setupStore(c *check.C) {
s.createComposeProject(c, "zookeeper")
s.composeProject.Start(c)
zookeeper.Register()
kv, err := valkeyrie.NewStore(
store.ZK,
[]string{s.composeProject.Container(c, "zookeeper").NetworkSettings.IPAddress + ":2181"},
&store.Config{
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store zookeeper")
}
s.kvClient = kv
// wait for zk
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
func (s *ZookeeperSuite) TearDownTest(c *check.C) {
// shutdown and delete compose project
if s.composeProject != nil {
s.composeProject.Stop(c)
}
}
func (s *ZookeeperSuite) TearDownSuite(c *check.C) {}
func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
address := s.composeProject.Container(c, "zookeeper").NetworkSettings.IPAddress + ":2181"
file := s.adaptFile(c, "fixtures/zookeeper/simple.toml", struct{ ZkAddress string }{address})
defer os.Remove(file)
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
"traefik/http/routers/Router0/middlewares/0": "compressor",
"traefik/http/routers/Router0/middlewares/1": "striper",
"traefik/http/routers/Router0/service": "simplesvc",
"traefik/http/routers/Router0/rule": "Host(`kv1.localhost`)",
"traefik/http/routers/Router0/priority": "42",
"traefik/http/routers/Router0/tls": "",
"traefik/http/routers/Router1/rule": "Host(`kv2.localhost`)",
"traefik/http/routers/Router1/priority": "42",
"traefik/http/routers/Router1/tls/domains/0/main": "aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/0": "aaa.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/1": "bbb.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/1/main": "bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/0": "aaa.bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/1": "bbb.bbb.localhost",
"traefik/http/routers/Router1/entryPoints/0": "web",
"traefik/http/routers/Router1/service": "simplesvc",
"traefik/http/services/simplesvc/loadBalancer/servers/0/url": "http://10.0.1.1:8888",
"traefik/http/services/simplesvc/loadBalancer/servers/1/url": "http://10.0.1.1:8889",
"traefik/http/services/srvcA/loadBalancer/servers/0/url": "http://10.0.1.2:8888",
"traefik/http/services/srvcA/loadBalancer/servers/1/url": "http://10.0.1.2:8889",
"traefik/http/services/srvcB/loadBalancer/servers/0/url": "http://10.0.1.3:8888",
"traefik/http/services/srvcB/loadBalancer/servers/1/url": "http://10.0.1.3:8889",
"traefik/http/services/mirror/mirroring/service": "simplesvc",
"traefik/http/services/mirror/mirroring/mirrors/0/name": "srvcA",
"traefik/http/services/mirror/mirroring/mirrors/0/percent": "42",
"traefik/http/services/mirror/mirroring/mirrors/1/name": "srvcB",
"traefik/http/services/mirror/mirroring/mirrors/1/percent": "42",
"traefik/http/services/Service03/weighted/services/0/name": "srvcA",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "srvcB",
"traefik/http/services/Service03/weighted/services/1/weight": "42",
"traefik/http/middlewares/compressor/compress": "",
"traefik/http/middlewares/striper/stripPrefix/prefixes/0": "foo",
"traefik/http/middlewares/striper/stripPrefix/prefixes/1": "bar",
"traefik/http/middlewares/striper/stripPrefix/forceSlash": "true",
}
for k, v := range data {
err := s.kvClient.Put(k, []byte(v), nil)
c.Assert(err, checker.IsNil)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("@zookeeper"))
c.Assert(err, checker.IsNil)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
expectedJSON := filepath.FromSlash("testdata/rawdata-zk.json")
if *updateExpected {
err = ioutil.WriteFile(expectedJSON, got, 0666)
c.Assert(err, checker.IsNil)
}
expected, err := ioutil.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
FromFile: "Expected",
A: difflib.SplitLines(string(expected)),
ToFile: "Got",
B: difflib.SplitLines(string(got)),
Context: 3,
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
}
}