Skip to content

Commit

Permalink
Migrate rest provider
Browse files Browse the repository at this point in the history
  • Loading branch information
juliens authored and traefiker committed Dec 3, 2018
1 parent 5d91c7e commit c815a73
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 4 deletions.
2 changes: 1 addition & 1 deletion cmd/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import (
"github.com/containous/traefik/old/provider/marathon"
"github.com/containous/traefik/old/provider/mesos"
"github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/rest"
"github.com/containous/traefik/old/provider/zk"
"github.com/containous/traefik/ping"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/provider/rest"
"github.com/containous/traefik/tracing/datadog"
"github.com/containous/traefik/tracing/jaeger"
"github.com/containous/traefik/tracing/zipkin"
Expand Down
2 changes: 1 addition & 1 deletion config/static/static_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import (
"github.com/containous/traefik/old/provider/marathon"
"github.com/containous/traefik/old/provider/mesos"
"github.com/containous/traefik/old/provider/rancher"
"github.com/containous/traefik/old/provider/rest"
"github.com/containous/traefik/old/provider/zk"
"github.com/containous/traefik/ping"
acmeprovider "github.com/containous/traefik/provider/acme"
"github.com/containous/traefik/provider/file"
"github.com/containous/traefik/provider/rest"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/tracing/datadog"
"github.com/containous/traefik/tracing/jaeger"
Expand Down
12 changes: 12 additions & 0 deletions integration/fixtures/rest/simple.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

[entryPoints]
[entryPoints.http]
address = ":8000"

[api]

[log]
logLevel = "DEBUG"

[providers]
[providers.rest]
1 change: 1 addition & 0 deletions integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func init() {
check.Suite(&AcmeSuite{})
check.Suite(&ErrorPagesSuite{})
check.Suite(&FileSuite{})
check.Suite(&RestSuite{})
check.Suite(&GRPCSuite{})
check.Suite(&HealthCheckSuite{})
check.Suite(&HTTPSSuite{})
Expand Down
4 changes: 4 additions & 0 deletions integration/resources/compose/rest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
whoami1:
image: containous/whoami
ports:
- "8881:80"
73 changes: 73 additions & 0 deletions integration/rest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package integration

import (
"bytes"
"encoding/json"
"net/http"
"time"

"github.com/containous/traefik/config"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)

type RestSuite struct{ BaseSuite }

func (s *RestSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "rest")

s.composeProject.Start(c)
}

func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/rest/simple.toml"))

defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()

// Expected a 404 as we did not configure anything.
err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)

config := config.Configuration{
Routers: map[string]*config.Router{
"router1": {
EntryPoints: []string{"http"},
Middlewares: []string{},
Service: "service1",
Rule: "PathPrefix:/",
},
},
Services: map[string]*config.Service{
"service1": {
LoadBalancer: &config.LoadBalancerService{
Servers: []config.Server{
{
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
Weight: 1,
},
},
},
},
},
}

json, err := json.Marshal(config)
c.Assert(err, checker.IsNil)

request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8080/api/providers/rest", bytes.NewReader(json))
c.Assert(err, checker.IsNil)

response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)

err = try.GetRequest("http://127.0.0.1:8080/api/providers/rest/routers", 1000*time.Millisecond, try.BodyContains("PathPrefix:/"))
c.Assert(err, checker.IsNil)

err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
4 changes: 4 additions & 0 deletions provider/aggregator/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ func NewProviderAggregator(conf static.Providers) ProviderAggregator {
p.quietAddProvider(conf.File)
}

if conf.Rest != nil {
p.quietAddProvider(conf.Rest)
}

return p
}

Expand Down
67 changes: 67 additions & 0 deletions provider/rest/rest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package rest

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"

"github.com/containous/mux"
"github.com/containous/traefik/config"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider"
"github.com/containous/traefik/safe"
"github.com/unrolled/render"
)

var _ provider.Provider = (*Provider)(nil)

// Provider is a provider.Provider implementation that provides a Rest API.
type Provider struct {
configurationChan chan<- config.Message
EntryPoint string `description:"EntryPoint" export:"true"`
}

var templatesRenderer = render.New(render.Options{Directory: "nowhere"})

// Init the provider.
func (p *Provider) Init() error {
return nil
}

// Append add rest provider routes on a router.
func (p *Provider) Append(systemRouter *mux.Router) {
systemRouter.
Methods(http.MethodPut).
Path("/api/providers/{provider}").
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {

vars := mux.Vars(request)
if vars["provider"] != "rest" {
response.WriteHeader(http.StatusBadRequest)
fmt.Fprint(response, "Only 'rest' provider can be updated through the REST API")
return
}

configuration := new(config.Configuration)
body, _ := ioutil.ReadAll(request.Body)
err := json.Unmarshal(body, configuration)
if err == nil {
p.configurationChan <- config.Message{ProviderName: "rest", Configuration: configuration}
err := templatesRenderer.JSON(response, http.StatusOK, configuration)
if err != nil {
log.WithoutContext().Error(err)
}
} else {
log.WithoutContext().Errorf("Error parsing configuration %+v", err)
http.Error(response, fmt.Sprintf("%+v", err), http.StatusBadRequest)
}
})
}

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- config.Message, pool *safe.Pool) error {
p.configurationChan = configurationChan
return nil
}
4 changes: 3 additions & 1 deletion server/router/route_appender_aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ func NewRouteAppenderAggregator(ctx context.Context, chainBuilder chainBuilder,

aggregator := &RouteAppenderAggregator{}

// FIXME add REST
if conf.Providers != nil && conf.Providers.Rest != nil {
aggregator.AddAppender(conf.Providers.Rest)
}

if conf.API != nil && conf.API.EntryPoint == entryPointName {
chain, err := chainBuilder.BuildChain(ctx, conf.API.Middlewares)
Expand Down
15 changes: 15 additions & 0 deletions server/router/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ func TestRouterManager_Get(t *testing.T) {
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusOK},
},
{
desc: "no load balancer",
routersConfig: map[string]*config.Router{
"foo": {
EntryPoints: []string{"web"},
Service: "foo-service",
Rule: "Host:foo.bar",
},
},
serviceConfig: map[string]*config.Service{
"foo-service": {},
},
entryPoints: []string{"web"},
expected: ExpectedResult{StatusCode: http.StatusNotFound},
},
{
desc: "no middleware, default entry point",
routersConfig: map[string]*config.Router{
Expand Down
5 changes: 4 additions & 1 deletion server/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ func (m *Manager) Build(rootCtx context.Context, serviceName string, responseMod
// TODO refactor ?
if conf, ok := m.configs[serviceName]; ok {
// FIXME Should handle multiple service types
return m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
if conf.LoadBalancer != nil {
return m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
}
return nil, fmt.Errorf("the service %q doesn't have any load balancer", serviceName)
}
return nil, fmt.Errorf("the service %q does not exits", serviceName)
}
Expand Down

0 comments on commit c815a73

Please sign in to comment.