diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6a204a12e..909e71aa6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -16,6 +16,17 @@ For end-user related support questions, please refer to one of the following: If you intend to ask a support question: DO NOT FILE AN ISSUE. --> +### Did you try using a 1.7.x configuration for the version 2.0? + +- [ ] Yes +- [ ] No + + + ### What did you do? + ### What did you do? + +The Traefik Kubernetes provider used to be a Kubernetes Ingress controller in the strict sense of the term; that is to say, +it would manage access to a cluster services by supporting the [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) specification. + +However, as the community expressed the need to benefit from Traefik features without resorting to (lots of) annotations, +we ended up writing a [Custom Resource Definition](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) (alias CRD in the following) for an IngressRoute type, defined below, in order to provide a better way to configure access to a Kubernetes cluster. + +## Traefik IngressRoute definition + +```yaml +--8<-- "content/providers/crd_ingress_route.yml" +``` + +That `IngressRoute` kind can then be used to define an `IngressRoute` object, such as: + +```yaml +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: ingressroutefoo.crd + +spec: + entrypoints: + - web + routes: + # Match is the rule corresponding to an underlying router. + # Later on, match could be the simple form of a path prefix, e.g. just "/bar", + # but for now we only support a traefik style matching rule. + - match: Host(`foo.com`) && PathPrefix(`/bar`) + # kind could eventually be one of "Rule", "Path", "Host", "Method", "Header", + # "Parameter", etc, to support simpler forms of rule matching, but for now we + # only support "Rule". + kind: Rule + # Priority disambiguates rules of the same length, for route matching. + priority: 12 + services: + - name: whoami + port: 80 +``` + +## Middleware + +Additionally, to allow for the use of middlewares in an `IngressRoute`, we defined the CRD below for the `Middleware` kind. + +```yaml +--8<-- "content/providers/crd_middlewares.yml" +``` + +Once the `Middleware` kind has been registered with the Kubernetes cluster, it can then be used in `IngressRoute` definitions, such as: + +```yaml +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: stripprefix + +spec: + stripprefix: + prefixes: + - /stripit + +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: ingressroutebar.crd + +spec: + entrypoints: + - web + routes: + - match: Host(`bar.com`) && PathPrefix(`/stripit`) + kind: Rule + services: + - name: whoami + port: 80 + middlewares: + - name: stripprefix +``` + +## TLS + +To allow for TLS, we made use of the `Secret` kind, as it was already defined, and it can be directly used in an `IngressRoute`: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: supersecret + +data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0= + +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: ingressroutetls.crd + +spec: + entryPoints: + - web + routes: + - match: Host(`foo.com`) && PathPrefix(`/bar`) + kind: Rule + services: + - name: whoami + port: 443 + tls: + secretName: supersecret +``` + +## Full reference example + +[Traefik IngressRoute Reference](../reference/providers/kubernetescrd.md). + +## Further + +Also see the [full example](../user-guides/crd-acme/index.md) with Let's Encrypt. diff --git a/docs/content/providers/kubernetes-ingress.md b/docs/content/providers/kubernetes-ingress.md new file mode 100644 index 000000000..c08f63810 --- /dev/null +++ b/docs/content/providers/kubernetes-ingress.md @@ -0,0 +1,6 @@ +# Traefik & Kubernetes + +Kubernetes Ingress. +{: .subtitle } + +TODO diff --git a/docs/content/providers/overview.md b/docs/content/providers/overview.md index f0f65c1f8..305f31565 100644 --- a/docs/content/providers/overview.md +++ b/docs/content/providers/overview.md @@ -8,7 +8,8 @@ Traefik's Many Friends Configuration discovery in Traefik is achieved through _Providers_. The _providers_ are existing infrastructure components, whether orchestrators, container engines, cloud providers, or key-value stores. -The idea is that Traefik will query the providers' API in order to find relevant information about routing, and each time Traefik detects a change, it dynamically updates the routes. +The idea is that Traefik will query the providers' API in order to find relevant information about routing, +and each time Traefik detects a change, it dynamically updates the routes. Deploy and forget is Traefik's credo. @@ -25,12 +26,12 @@ Even if each provider is different, we can categorize them in four groups: Below is the list of the currently supported providers in Traefik. -| Provider | Type | Configuration Type | -|-----------------------------|--------------|--------------------| -| [Docker](./docker.md) | Orchestrator | Label | -| [File](./file.md) | Orchestrator | Custom Annotation | -| Kubernetes (not documented) | Orchestrator | Custom Annotation | -| Marathon (not documented) | Orchestrator | Label | +| Provider | Type | Configuration Type | +|---------------------------------|--------------|--------------------| +| [Docker](./docker.md) | Orchestrator | Label | +| [File](./file.md) | Orchestrator | Custom Annotation | +| [Kubernetes](kubernetes-crd.md) | Orchestrator | Custom Resource | +| Marathon (not yet documented) | Orchestrator | Label | !!! note "More Providers" @@ -38,7 +39,8 @@ Below is the list of the currently supported providers in Traefik. ## Constraints Configuration -If you want to limit the scope of Traefik service discovery, you can set constraints. Doing so, Traefik will create routes for containers that match these constraints only. +If you want to limit the scope of Traefik service discovery, you can set constraints. +Doing so, Traefik will create routes for containers that match these constraints only. ??? example "Containers with the api Tag" diff --git a/docs/content/reference/providers/kubernetescrd.md b/docs/content/reference/providers/kubernetescrd.md new file mode 100644 index 000000000..b9fedf5af --- /dev/null +++ b/docs/content/reference/providers/kubernetescrd.md @@ -0,0 +1,81 @@ +# Kubernetes -- Reference + +## Kubernetes + +```yaml +################################################################ +# Kubernetes Provider +################################################################ + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: ingressroutes.traefik.containo.us + +spec: + group: traefik.containo.us + version: v1alpha1 + names: + kind: IngressRoute + plural: ingressroutes + singular: ingressroute + scope: Namespaced + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: middlewares.traefik.containo.us +spec: + group: traefik.containo.us + version: v1alpha1 + names: + kind: Middleware + plural: middlewares + singular: middleware + scope: Namespaced + +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: ingressroute.crd +spec: + entrypoints: + - web + - web-secure + routes: + - match: Host(`foo.com`) && PathPrefix(`/bar`) + kind: Rule + priority: 12 + # defining several services is possible and allowed, but for now the servers of + # all the services (for a given route) get merged altogether under the same + # load-balancing strategy. + services: + - name: s1 + port: 80 + healthcheck: + path: /health + host: baz.com + intervalseconds: 7 + timeoutseconds: 60 + # strategy defines the load balancing strategy between the servers. It defaults + # to Round Robin, and for now only Round Robin is supported anyway. + strategy: RoundRobin + - name: s2 + port: 433 + healthcheck: + path: /health + host: baz.com + intervalseconds: 7 + timeoutseconds: 60 + - match: PathPrefix(`/misc`) + services: + - name: s3 + port: 80 + middleware: + - name: stripprefix + - name: addprefix + tls: + secretName: supersecret +``` \ No newline at end of file diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index d043a83b3..ce4fecfca 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -1,6 +1,6 @@ # EntryPoints -Opening Connections for Incomming Requests +Opening Connections for Incoming Requests {: .subtitle } ![EntryPoints](../assets/img/entrypoints.png) @@ -29,11 +29,6 @@ They define the port which will receive the requests (whether HTTP or TCP). [entrypoints.web-secure] address = ":443" - - [entrypoints.web-secure.tls] - [[entrypoints.web-secure.tls.certificates]] - certFile = "tests/traefik.crt" - keyFile = "tests/traefik.key" ``` - Two entrypoints are defined: one called `web`, and the other called `web-secure`. @@ -51,7 +46,7 @@ Entrypoints are part of the [static configuration](../getting-started/configurat ```shell --entryPoints='Name:http Address::80' - --entryPoints='Name:https Address::443 TLS' + --entryPoints='Name:https Address::443' ``` !!! note @@ -64,7 +59,7 @@ Entrypoints are part of the [static configuration](../getting-started/configurat ```yaml traefik: - image: traefik + image: traefik:v2.0 # The official v2.0 Traefik docker image command: - --defaultentrypoints=powpow - "--entryPoints=Name:powpow Address::42 Compress:true" @@ -74,7 +69,7 @@ Entrypoints are part of the [static configuration](../getting-started/configurat ```yaml traefik: - image: traefik + image: traefik:v2.0 # The official v2.0 Traefik docker image command: --defaultentrypoints=powpow --entryPoints='Name:powpow Address::42 Compress:true' ``` @@ -97,7 +92,7 @@ Traefik supports [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy- ??? example "Insecure Mode -- Testing Environnement Only" - In a test environments, you can configure Traefik to trust every incomming connection. Doing so, every remote client address will be replaced (`trustedIPs` won't have any effect) + In a test environments, you can configure Traefik to trust every incoming connection. Doing so, every remote client address will be replaced (`trustedIPs` won't have any effect) ```toml [entrypoints] diff --git a/docs/content/routing/routers/index.md b/docs/content/routing/routers/index.md index a5fde96b4..9cdd60c0f 100644 --- a/docs/content/routing/routers/index.md +++ b/docs/content/routing/routers/index.md @@ -15,7 +15,7 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie ```toml [http.routers] [http.routers.my-router] - rule = "Path(/foo)" + rule = "Path(`/foo`)" service = "service-foo" ``` @@ -24,7 +24,7 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie ```toml [http.routers] [http.routers.my-router] - rule = "Path(/foo)" + rule = "Path(`/foo`)" middlewares = ["authentication"] # declared elsewhere service = "service-foo" ``` @@ -67,7 +67,7 @@ If you want to limit the router scope to a set of entrypoint, set the entrypoint [http.routers] [http.routers.Router-1] # By default, routers listen to every entrypoints - rule = "Host(traefik.io)" + rule = "Host(`traefik.io`)" service = "service-1" ``` @@ -85,7 +85,7 @@ If you want to limit the router scope to a set of entrypoint, set the entrypoint [http.routers] [http.routers.Router-1] entryPoints = ["web-secure", "other"] # won't listen to entrypoint web - rule = "Host(traefik.io)" + rule = "Host(`traefik.io`)" service = "service-1" ``` @@ -248,9 +248,9 @@ If you want to limit the router scope to a set of entrypoints, set the entrypoin ### Rule -| Rule | Description | -|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| -| ``HostSNI(`domain-1`, ...)`` | Check if the Server Name Indication corresponds to the given `domains`. | +| Rule | Description | +|------------------------------|-------------------------------------------------------------------------| +| ``HostSNI(`domain-1`, ...)`` | Check if the Server Name Indication corresponds to the given `domains`. | !!! important "HostSNI & TLS" diff --git a/docs/content/routing/services/index.md b/docs/content/routing/services/index.md index c4af3a8c8..cb4aca7dd 100644 --- a/docs/content/routing/services/index.md +++ b/docs/content/routing/services/index.md @@ -80,6 +80,7 @@ The `weight` option defines the weight of the server for the load balancing algo [http.services.my-service.LoadBalancer] [[http.services.my-service.LoadBalancer.servers]] url = "http://private-ip-server-1/" + weight = 1 ``` #### Load-balancing @@ -97,8 +98,10 @@ Various methods of load balancing are supported: method = "drr" [[http.services.my-service.LoadBalancer.servers]] url = "http://private-ip-server-1/" + weight = 1 [[http.services.my-service.LoadBalancer.servers]] url = "http://private-ip-server-1/" + weight = 1 ``` #### Sticky sessions diff --git a/docs/content/user-guides/crd-acme/01-crd.yml b/docs/content/user-guides/crd-acme/01-crd.yml new file mode 100644 index 000000000..45ace3f90 --- /dev/null +++ b/docs/content/user-guides/crd-acme/01-crd.yml @@ -0,0 +1,91 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: ingressroutes.traefik.containo.us + +spec: + group: traefik.containo.us + version: v1alpha1 + names: + kind: IngressRoute + plural: ingressroutes + singular: ingressroute + scope: Namespaced + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: middlewares.traefik.containo.us + +spec: + group: traefik.containo.us + version: v1alpha1 + names: + kind: Middleware + plural: middlewares + singular: middleware + scope: Namespaced + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: traefik-ingress-controller + +rules: + - apiGroups: + - "" + resources: + - services + - endpoints + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - extensions + resources: + - ingresses + verbs: + - get + - list + - watch + - apiGroups: + - extensions + resources: + - ingresses/status + verbs: + - update + - apiGroups: + - traefik.containo.us + resources: + - middlewares + verbs: + - get + - list + - watch + - apiGroups: + - traefik.containo.us + resources: + - ingressroutes + verbs: + - get + - list + - watch + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: traefik-ingress-controller + +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: traefik-ingress-controller +subjects: + - kind: ServiceAccount + name: traefik-ingress-controller + namespace: default diff --git a/docs/content/user-guides/crd-acme/02-services.yml b/docs/content/user-guides/crd-acme/02-services.yml new file mode 100644 index 000000000..753d9e65b --- /dev/null +++ b/docs/content/user-guides/crd-acme/02-services.yml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: traefik + +spec: + ports: + - protocol: TCP + name: web + port: 8000 + - protocol: TCP + name: admin + port: 8080 + - protocol: TCP + name: websecure + port: 4443 + selector: + app: traefik + +--- +apiVersion: v1 +kind: Service +metadata: + name: whoami + +spec: + ports: + - protocol: TCP + name: web + port: 80 + selector: + app: whoami diff --git a/docs/content/user-guides/crd-acme/03-deployments.yml b/docs/content/user-guides/crd-acme/03-deployments.yml new file mode 100644 index 000000000..712503a53 --- /dev/null +++ b/docs/content/user-guides/crd-acme/03-deployments.yml @@ -0,0 +1,79 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: default + name: traefik-ingress-controller + +--- +kind: Deployment +apiVersion: extensions/v1beta1 +metadata: + namespace: default + name: traefik + labels: + app: traefik + +spec: + replicas: 1 + selector: + matchLabels: + app: traefik + template: + metadata: + labels: + app: traefik + spec: + serviceAccountName: traefik-ingress-controller + containers: + - name: traefik + image: traefik:v2.0 + args: + - --api + - --accesslog + - --entrypoints=Name:web Address::8000 + - --entrypoints=Name:websecure Address::4443 + - --providers.kubernetescrd + - --providers.kubernetescrd.trace + - --acme + - --acme.acmelogging + - --acme.tlschallenge + - --acme.onhostrule + - --acme.email=foo@you.com + - --acme.entrypoint=websecure + - --acme.storage=acme.json + # Please note that this is the staging Let's Encrypt server. + # Once you get things working, you should remove that whole line altogether. + - --acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory + ports: + - name: web + containerPort: 8000 + - name: websecure + containerPort: 4443 + - name: admin + containerPort: 8080 + +--- +kind: Deployment +apiVersion: extensions/v1beta1 +metadata: + namespace: default + name: whoami + labels: + app: whoami + +spec: + replicas: 2 + selector: + matchLabels: + app: whoami + template: + metadata: + labels: + app: whoami + spec: + containers: + - name: whoami + image: containous/whoami + ports: + - name: web + containerPort: 80 diff --git a/docs/content/user-guides/crd-acme/04-ingressroutes.yml b/docs/content/user-guides/crd-acme/04-ingressroutes.yml new file mode 100644 index 000000000..9e67cc83d --- /dev/null +++ b/docs/content/user-guides/crd-acme/04-ingressroutes.yml @@ -0,0 +1,30 @@ +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: simpleingressroute +spec: + entrypoints: + - web + routes: + - match: Host(`your.domain.com`) && PathPrefix(`/notls`) + kind: Rule + services: + - name: whoami + port: 80 + +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: ingressroutetls +spec: + entrypoints: + - websecure + routes: + - match: Host(`your.domain.com`) && PathPrefix(`/tls`) + kind: Rule + services: + - name: whoami + port: 80 + tls: + secretName: "" diff --git a/docs/content/user-guides/crd-acme/index.md b/docs/content/user-guides/crd-acme/index.md new file mode 100644 index 000000000..84c8db503 --- /dev/null +++ b/docs/content/user-guides/crd-acme/index.md @@ -0,0 +1,100 @@ +# Traefik & CRD & Let's Encrypt + +Traefik with an IngressRoute Custom Resource Definition for Kubernetes, and TLS Through Let's Encrypt. +{: .subtitle } + +This document is intended to be a fully working example demonstrating how to set up Traefik in [Kubernetes](https://kubernetes.io), +with the dynamic configuration coming from the [IngressRoute Custom Resource](../../providers/kubernetes-crd.md), +and TLS setup with [Let's Encrypt](https://letsencrypt.org). +However, for the sake of simplicity, we're using [k3s](https://github.com/rancher/k3s) docker image for the Kubernetes cluster setup. + +Please note that for this setup, given that we're going to use ACME's TLS-ALPN-01 challenge, the host you'll be running it on must be able to receive connections from the outside on port 443. +And of course its internet facing IP address must match the domain name you intend to use. + +In the following, the Kubernetes resources defined in YAML configuration files can be applied to the setup in two different ways: + +- the first, and usual way, is simply with the `kubectl apply` command. +- the second, which can be used for this tutorial, is to directly place the files in the directory used by the k3s docker image for such inputs (`/var/lib/rancher/k3s/server/manifests`). + +## k3s Docker-compose Configuration ## + +Our starting point is the docker-compose configuration file, to start the k3s cluster. +You can start it with: + +```bash +docker-compose -f k3s.yml up +``` + +```yaml +--8<-- "content/user-guides/crd-acme/k3s.yml" +``` + +## Cluster Resources ## + +Let's now have a look (in the order they should be applied, if using `kubectl apply`) at all the required resources for the full setup. + +### IngressRoute Definition ### + +First, the definition of the `IngressRoute` and the `Middleware` kinds. +Also note the RBAC authorization resources; they'll be referenced through the `serviceAccountName` of the deployment, later on. + +```yaml +--8<-- "content/user-guides/crd-acme/01-crd.yml" +``` + +### Services ### + +Then, the services. One for Traefik itself, and one for the app it routes for, i.e. in this case our demo HTTP server: [whoami](https://github.com/containous/whoami). + +```yaml +--8<-- "content/user-guides/crd-acme/02-services.yml" +``` + +### Deployments ### + +Next, the deployments, i.e. the actual pods behind the services. +Again, one pod for Traefik, and one for the whoami app. + +```yaml +--8<-- "content/user-guides/crd-acme/03-deployments.yml" +``` + +### Port Forwarding ### + +Now, as an exception to what we said above, please note that you should not let the ingressRoute resources below be applied automatically to your cluster. +The reason is, as soon as the ACME provider of Traefik detects we have TLS routers, it will try to generate the certificates for the corresponding domains. +And this will not work, because as it is, our Traefik pod is not reachable from the outside, which will make the ACME TLS challenge fail. +Therefore, for the whole thing to work, we must delay applying the ingressRoute resources until we have port-forwarding set up properly, which is the next step. + +```bash +kubectl port-forward --address 0.0.0.0 service/traefik 8000:8000 8080:8080 443:4443 -n default +``` + +Also, and this is out of the scope if this guide, please note that because of the privileged ports limitation on Linux, the above command might fail to listen on port 443. +In which case you can use tricks such as elevating caps of `kubectl` with `setcaps`, or using `authbind`, or setting up a NAT between your host and the WAN. +Look it up. + +### Traefik Routers ### + +We can now finally apply the actual ingressRoutes, with: + +```bash +kubectl apply -f 04-ingressroutes.yml +``` + +```yaml +--8<-- "content/user-guides/crd-acme/04-ingressroutes.yml" +``` + +Give it a few seconds for the ACME TLS challenge to complete, and you should then be able to access your whoami pod (routed through Traefik), from the outside. +Both with or (just for fun, do not do that in production) without TLS: + +```bash +curl [-k] https://your.domain.com/tls +``` + +```bash +curl [-k] http://your.domain.com:8000/notls +``` + +Note that you'll have to use `-k` as long as you're using the staging server of Let's Encrypt, since it is not in the root DNS servers. diff --git a/docs/content/user-guides/crd-acme/k3s.yml b/docs/content/user-guides/crd-acme/k3s.yml new file mode 100644 index 000000000..5fe32dfff --- /dev/null +++ b/docs/content/user-guides/crd-acme/k3s.yml @@ -0,0 +1,30 @@ +server: + image: rancher/k3s:v0.2.0 + command: server --disable-agent --no-deploy traefik + environment: + - K3S_CLUSTER_SECRET=somethingtotallyrandom + - K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml + - K3S_KUBECONFIG_MODE=666 + volumes: + # k3s will generate a kubeconfig.yaml in this directory. This volume is mounted + # on your host, so you can then 'export KUBECONFIG=/somewhere/on/your/host/out/kubeconfig.yaml', + # in order for your kubectl commands to work. + - /somewhere/on/your/host/out:/output + # This directory is where you put all the (yaml) configuration files of + # the Kubernetes resources. + - /somewhere/on/your/host/in:/var/lib/rancher/k3s/server/manifests + ports: + - 6443:6443 + +node: + image: rancher/k3s:v0.2.0 + privileged: true + links: + - server + environment: + - K3S_URL=https://server:6443 + - K3S_CLUSTER_SECRET=somethingtotallyrandom + volumes: + # this is where you would place a alternative traefik image (saved as a .tar file with + # 'docker save'), if you want to use it, instead of the traefik:v2.0 image. + - /sowewhere/on/your/host/custom-image:/var/lib/rancher/k3s/agent/images diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index a1e9f2064..34e069940 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -66,19 +66,22 @@ markdown_extensions: # Page tree nav: + - '': 'providers/kubernetes-ingress.md' - '': 'reference/acme.md' - '': 'reference/providers/docker.md' - '': 'reference/providers/file.md' + - '': 'reference/providers/kubernetescrd.md' - '': 'reference/entrypoints.md' - 'Welcome': 'index.md' - 'Getting Started': - 'Concepts' : 'getting-started/concepts.md' - 'Quick Start': 'getting-started/quick-start.md' - - 'Configuration Overview': 'getting-started/configuration-overview.md' + - 'Configuration Introduction': 'getting-started/configuration-overview.md' - 'Configuration Discovery': - 'Overview': 'providers/overview.md' - 'Docker': 'providers/docker.md' - 'File': 'providers/file.md' + - 'Kubernetes IngressRoute': 'providers/kubernetes-crd.md' - 'Routing & Load Balancing': - 'Overview': 'routing/overview.md' - 'Entrypoints': 'routing/entrypoints.md' @@ -119,6 +122,8 @@ nav: - 'Logs': 'observability/logs.md' - 'Access Logs': 'observability/access-logs.md' - 'Tracing': 'observability/tracing.md' + - 'User Guides': + - 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md' - 'Contributing': - 'Thank You!': 'contributing/thank-you.md' - 'Submitting Issues': 'contributing/submitting-issues.md' diff --git a/docs/requirements.txt b/docs/requirements.txt index 4fbf20cb8..e6552aa6a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ mkdocs==1.0.4 pymdown-extensions==6.0 mkdocs-bootswatch==1.0 -mkdocs-material==3.3.0 +mkdocs-material==4.0.2 markdown-include==0.5.1 diff --git a/exp.Dockerfile b/exp.Dockerfile new file mode 100644 index 000000000..ab5d81b2f --- /dev/null +++ b/exp.Dockerfile @@ -0,0 +1,42 @@ +# WEBUI +FROM node:8.15.0 as webui + +ENV WEBUI_DIR /src/webui +RUN mkdir -p $WEBUI_DIR + +COPY ./webui/ $WEBUI_DIR/ + +WORKDIR $WEBUI_DIR +RUN yarn install + +RUN npm run build + +# BUILD +FROM golang:1.12-alpine as gobuild + +RUN apk --update upgrade \ +&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \ +&& rm -rf /var/cache/apk/* + +RUN mkdir -p /usr/local/bin \ + && curl -fsSL -o /usr/local/bin/go-bindata https://github.com/containous/go-bindata/releases/download/v1.0.0/go-bindata \ + && chmod +x /usr/local/bin/go-bindata + +WORKDIR /go/src/github.com/containous/traefik +COPY . /go/src/github.com/containous/traefik + +RUN rm -rf /go/src/github.com/containous/traefik/static/ +COPY --from=webui /src/static/ /go/src/github.com/containous/traefik/static/ + +RUN ./script/make.sh generate binary + +## IMAGE +FROM scratch + +COPY script/ca-certificates.crt /etc/ssl/certs/ +COPY --from=gobuild /go/src/github.com/containous/traefik/dist/traefik / + +EXPOSE 80 +VOLUME ["/tmp"] + +ENTRYPOINT ["/traefik"] diff --git a/integration/docker_test.go b/integration/docker_test.go index e2088a88b..78187f53d 100644 --- a/integration/docker_test.go +++ b/integration/docker_test.go @@ -144,6 +144,43 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) { c.Assert(version["Version"], checker.Equals, "swarm/1.0.0") } +func (s *DockerSuite) TestDockerContainersWithTCPLabels(c *check.C) { + tempObjects := struct { + DockerHost string + DefaultRule string + }{ + DockerHost: s.getDockerHost(), + DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)", + } + + file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects) + defer os.Remove(file) + + // Start a container with some labels + labels := map[string]string{ + "traefik.tcp.Routers.Super.Rule": "HostSNI(`my.super.host`)", + "traefik.tcp.Routers.Super.tls": "true", + "traefik.tcp.Services.Super.Loadbalancer.server.port": "8080", + } + + s.startContainerWithLabels(c, "containous/whoamitcp", labels, "-name", "my.super.host") + + // Start traefik + cmd, display := s.traefikCmd(withConfigFile(file)) + defer display(c) + err := cmd.Start() + c.Assert(err, checker.IsNil) + defer cmd.Process.Kill() + + err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`my.super.host`)")) + c.Assert(err, checker.IsNil) + + who, err := guessWho("127.0.0.1:8000", "my.super.host", true) + c.Assert(err, checker.IsNil) + + c.Assert(who, checker.Contains, "my.super.host") +} + func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) { tempObjects := struct { DockerHost string diff --git a/integration/fixtures/k8s/03-ingressroute.yml b/integration/fixtures/k8s/03-ingressroute.yml index 608b52a42..303d8bdfa 100644 --- a/integration/fixtures/k8s/03-ingressroute.yml +++ b/integration/fixtures/k8s/03-ingressroute.yml @@ -15,4 +15,3 @@ spec: services: - name: whoami port: 80 - diff --git a/pkg/anonymize/anonymize_config_test.go b/pkg/anonymize/anonymize_config_test.go index 27d11e9b0..1d0f132aa 100644 --- a/pkg/anonymize/anonymize_config_test.go +++ b/pkg/anonymize/anonymize_config_test.go @@ -25,7 +25,6 @@ import ( ) func TestDo_globalConfiguration(t *testing.T) { - config := &static.Configuration{} sendAnonymousUsage := true @@ -148,9 +147,15 @@ func TestDo_globalConfiguration(t *testing.T) { } config.Providers.File = &file.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "file Filename", + Directory: "file Directory", + Watch: true, + Filename: "file Filename", + DebugLogGeneratedTemplate: true, + TraefikFile: "", + } + + config.Providers.Docker = &docker.Provider{ + Constrainer: provider.Constrainer{ Constraints: types.Constraints{ { Key: "file Constraints Key 1", @@ -163,20 +168,8 @@ func TestDo_globalConfiguration(t *testing.T) { MustMatch: true, }, }, - Trace: true, - DebugLogGeneratedTemplate: true, - }, - Directory: "file Directory", - } - - config.Providers.Docker = &docker.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "myfilename", - Constraints: nil, - Trace: true, - DebugLogGeneratedTemplate: true, }, + Watch: true, Endpoint: "MyEndPoint", DefaultRule: "PathPrefix(`/`)", TLS: &types.ClientTLS{ @@ -194,24 +187,6 @@ func TestDo_globalConfiguration(t *testing.T) { } config.Providers.Kubernetes = &ingress.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "myFileName", - 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: "MyEndpoint", Token: "MyToken", CertAuthFilePath: "MyCertAuthPath", @@ -222,24 +197,6 @@ func TestDo_globalConfiguration(t *testing.T) { } config.Providers.KubernetesCRD = &crd.Provider{ - BaseProvider: provider.BaseProvider{ - Watch: true, - Filename: "myFileName", - 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: "MyEndpoint", Token: "MyToken", CertAuthFilePath: "MyCertAuthPath", diff --git a/pkg/config/dyn_config.go b/pkg/config/dyn_config.go index 34848bb54..6572f65fa 100644 --- a/pkg/config/dyn_config.go +++ b/pkg/config/dyn_config.go @@ -53,6 +53,23 @@ type TCPLoadBalancerService struct { Method string `json:"method,omitempty" toml:",omitempty"` } +// Mergeable tells if the given service is mergeable. +func (l *TCPLoadBalancerService) Mergeable(loadBalancer *TCPLoadBalancerService) bool { + savedServers := l.Servers + defer func() { + l.Servers = savedServers + }() + l.Servers = nil + + savedServersLB := loadBalancer.Servers + defer func() { + loadBalancer.Servers = savedServersLB + }() + loadBalancer.Servers = nil + + return reflect.DeepEqual(l, loadBalancer) +} + // Mergeable tells if the given service is mergeable. func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool { savedServers := l.Servers @@ -70,6 +87,11 @@ func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool return reflect.DeepEqual(l, loadBalancer) } +// SetDefaults Default values for a LoadBalancerService. +func (l *TCPLoadBalancerService) SetDefaults() { + l.Method = "wrr" +} + // SetDefaults Default values for a LoadBalancerService. func (l *LoadBalancerService) SetDefaults() { l.PassHostHeader = true @@ -97,9 +119,15 @@ type Server struct { // TCPServer holds a TCP Server configuration type TCPServer struct { Address string `json:"address" label:"-"` + Port string `toml:"-" json:"-"` Weight int `json:"weight"` } +// SetDefaults Default values for a Server. +func (s *TCPServer) SetDefaults() { + s.Weight = 1 +} + // SetDefaults Default values for a Server. func (s *Server) SetDefaults() { s.Weight = 1 diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go index 10e8ace5e..5450be014 100644 --- a/pkg/provider/acme/provider.go +++ b/pkg/provider/acme/provider.go @@ -383,6 +383,9 @@ func (p *Provider) watchNewDomains(ctx context.Context) { case config := <-p.configFromListenerChan: if config.TCP != nil { for routerName, route := range config.TCP.Routers { + if route.TLS == nil { + continue + } ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule)) domains, err := rules.ParseHostSNI(route.Rule) @@ -395,6 +398,9 @@ func (p *Provider) watchNewDomains(ctx context.Context) { } for routerName, route := range config.HTTP.Routers { + if route.TLS == nil { + continue + } ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule)) domains, err := rules.ParseDomains(route.Rule) diff --git a/pkg/provider/aggregator/aggregator.go b/pkg/provider/aggregator/aggregator.go index dea68443a..faf814ebc 100644 --- a/pkg/provider/aggregator/aggregator.go +++ b/pkg/provider/aggregator/aggregator.go @@ -82,6 +82,7 @@ func (p ProviderAggregator) Provide(configurationChan chan<- config.Message, poo } for _, prd := range p.providers { + prd := prd safe.Go(func() { launchProvider(configurationChan, pool, prd) }) diff --git a/pkg/provider/base_provider.go b/pkg/provider/base_provider.go deleted file mode 100644 index 5192a9e75..000000000 --- a/pkg/provider/base_provider.go +++ /dev/null @@ -1,105 +0,0 @@ -package provider - -import ( - "bytes" - "strings" - "text/template" - - "github.com/BurntSushi/toml" - "github.com/Masterminds/sprig" - "github.com/containous/traefik/pkg/config" - "github.com/containous/traefik/pkg/log" - "github.com/containous/traefik/pkg/tls" - "github.com/containous/traefik/pkg/types" -) - -// BaseProvider should be inherited by providers. -type BaseProvider struct { - Watch bool `description:"Watch provider" export:"true"` - Filename string `description:"Override default configuration template. For advanced users :)" export:"true"` - Constraints types.Constraints `description:"Filter services by constraint, matching with Traefik tags." export:"true"` - Trace bool `description:"Display additional provider logs (if available)." export:"true"` - DebugLogGeneratedTemplate bool `description:"Enable debug logging of generated configuration template." export:"true"` -} - -// Init for compatibility reason the BaseProvider implements an empty Init. -func (p *BaseProvider) Init() error { - return nil -} - -// MatchConstraints must match with EVERY single constraint -// returns first constraint that do not match or nil. -func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) { - // if there is no tags and no constraints, filtering is disabled - if len(tags) == 0 && len(p.Constraints) == 0 { - return true, nil - } - - for _, constraint := range p.Constraints { - // xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint - if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch { - return false, constraint - } - } - - // If no constraint or every constraints matching - return true, nil -} - -// CreateConfiguration creates a provider configuration from content using templating. -func (p *BaseProvider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) { - var defaultFuncMap = sprig.TxtFuncMap() - // tolower is deprecated in favor of sprig's lower function - defaultFuncMap["tolower"] = strings.ToLower - defaultFuncMap["normalize"] = Normalize - defaultFuncMap["split"] = split - for funcID, funcElement := range funcMap { - defaultFuncMap[funcID] = funcElement - } - - tmpl := template.New(p.Filename).Funcs(defaultFuncMap) - - _, err := tmpl.Parse(tmplContent) - if err != nil { - return nil, err - } - - var buffer bytes.Buffer - err = tmpl.Execute(&buffer, templateObjects) - if err != nil { - return nil, err - } - - var renderedTemplate = buffer.String() - if p.DebugLogGeneratedTemplate { - log.Debugf("Template content: %s", tmplContent) - log.Debugf("Rendering results: %s", renderedTemplate) - } - return p.DecodeConfiguration(renderedTemplate) -} - -// DecodeConfiguration Decodes a *types.Configuration from a content. -func (p *BaseProvider) DecodeConfiguration(content string) (*config.Configuration, error) { - configuration := &config.Configuration{ - HTTP: &config.HTTPConfiguration{ - Routers: make(map[string]*config.Router), - Middlewares: make(map[string]*config.Middleware), - Services: make(map[string]*config.Service), - }, - TCP: &config.TCPConfiguration{ - Routers: make(map[string]*config.TCPRouter), - Services: make(map[string]*config.TCPService), - }, - TLS: make([]*tls.Configuration, 0), - TLSStores: make(map[string]tls.Store), - TLSOptions: make(map[string]tls.TLS), - } - if _, err := toml.Decode(content, configuration); err != nil { - return nil, err - } - return configuration, nil -} - -func split(sep, s string) []string { - return strings.Split(s, sep) -} diff --git a/pkg/provider/configuration.go b/pkg/provider/configuration.go index b233d881d..b80781aca 100644 --- a/pkg/provider/configuration.go +++ b/pkg/provider/configuration.go @@ -36,6 +36,12 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration) routersToDelete := map[string]struct{}{} routers := map[string][]string{} + servicesTCPToDelete := map[string]struct{}{} + servicesTCP := map[string][]string{} + + routersTCPToDelete := map[string]struct{}{} + routersTCP := map[string][]string{} + middlewaresToDelete := map[string]struct{}{} middlewares := map[string][]string{} @@ -61,6 +67,20 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration) } } + for serviceName, service := range conf.TCP.Services { + servicesTCP[serviceName] = append(servicesTCP[serviceName], root) + if !AddServiceTCP(configuration.TCP, serviceName, service) { + servicesTCPToDelete[serviceName] = struct{}{} + } + } + + for routerName, router := range conf.TCP.Routers { + routersTCP[routerName] = append(routersTCP[routerName], root) + if !AddRouterTCP(configuration.TCP, routerName, router) { + routersTCPToDelete[routerName] = struct{}{} + } + } + for middlewareName, middleware := range conf.HTTP.Middlewares { middlewares[middlewareName] = append(middlewares[middlewareName], root) if !AddMiddleware(configuration.HTTP, middlewareName, middleware) { @@ -81,6 +101,18 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration) delete(configuration.HTTP.Routers, routerName) } + for serviceName := range servicesTCPToDelete { + logger.WithField(log.ServiceName, serviceName). + Errorf("Service TCP defined multiple times with different configurations in %v", servicesTCP[serviceName]) + delete(configuration.TCP.Services, serviceName) + } + + for routerName := range routersTCPToDelete { + logger.WithField(log.RouterName, routerName). + Errorf("Router TCP defined multiple times with different configurations in %v", routersTCP[routerName]) + delete(configuration.TCP.Routers, routerName) + } + for middlewareName := range middlewaresToDelete { logger.WithField(log.MiddlewareName, middlewareName). Errorf("Middleware defined multiple times with different configurations in %v", middlewares[middlewareName]) @@ -90,6 +122,31 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration) return configuration } +// AddServiceTCP Adds a service to a configurations. +func AddServiceTCP(configuration *config.TCPConfiguration, serviceName string, service *config.TCPService) bool { + if _, ok := configuration.Services[serviceName]; !ok { + configuration.Services[serviceName] = service + return true + } + + if !configuration.Services[serviceName].LoadBalancer.Mergeable(service.LoadBalancer) { + return false + } + + configuration.Services[serviceName].LoadBalancer.Servers = append(configuration.Services[serviceName].LoadBalancer.Servers, service.LoadBalancer.Servers...) + return true +} + +// AddRouterTCP Adds a router to a configurations. +func AddRouterTCP(configuration *config.TCPConfiguration, routerName string, router *config.TCPRouter) bool { + if _, ok := configuration.Routers[routerName]; !ok { + configuration.Routers[routerName] = router + return true + } + + return reflect.DeepEqual(configuration.Routers[routerName], router) +} + // AddService Adds a service to a configurations. func AddService(configuration *config.HTTPConfiguration, serviceName string, service *config.Service) bool { if _, ok := configuration.Services[serviceName]; !ok { @@ -137,10 +194,33 @@ func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*tem return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule) } +// BuildTCPRouterConfiguration Builds a router configuration. +func BuildTCPRouterConfiguration(ctx context.Context, configuration *config.TCPConfiguration) { + for routerName, router := range configuration.Routers { + loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName) + if len(router.Rule) == 0 { + delete(configuration.Routers, routerName) + loggerRouter.Errorf("Empty rule") + continue + } + + if len(router.Service) == 0 { + if len(configuration.Services) > 1 { + delete(configuration.Routers, routerName) + loggerRouter. + Error("Could not define the service name for the router: too many services") + continue + } + + for serviceName := range configuration.Services { + router.Service = serviceName + } + } + } +} + // BuildRouterConfiguration Builds a router configuration. func BuildRouterConfiguration(ctx context.Context, configuration *config.HTTPConfiguration, defaultRouterName string, defaultRuleTpl *template.Template, model interface{}) { - logger := log.FromContext(ctx) - if len(configuration.Routers) == 0 { if len(configuration.Services) > 1 { log.FromContext(ctx).Info("Could not create a router for the container: too many services") @@ -151,7 +231,7 @@ func BuildRouterConfiguration(ctx context.Context, configuration *config.HTTPCon } for routerName, router := range configuration.Routers { - loggerRouter := logger.WithField(log.RouterName, routerName) + loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName) if len(router.Rule) == 0 { writer := &bytes.Buffer{} if err := defaultRuleTpl.Execute(writer, model); err != nil { diff --git a/pkg/provider/constrainer.go b/pkg/provider/constrainer.go new file mode 100644 index 000000000..44a276c51 --- /dev/null +++ b/pkg/provider/constrainer.go @@ -0,0 +1,27 @@ +package provider + +import "github.com/containous/traefik/pkg/types" + +// Constrainer Filter services by constraint, matching with Traefik tags. +type Constrainer struct { + Constraints types.Constraints `description:"Filter services by constraint, matching with Traefik tags." export:"true"` +} + +// MatchConstraints must match with EVERY single constraint +// returns first constraint that do not match or nil. +func (c *Constrainer) MatchConstraints(tags []string) (bool, *types.Constraint) { + // if there is no tags and no constraints, filtering is disabled + if len(tags) == 0 && len(c.Constraints) == 0 { + return true, nil + } + + for _, constraint := range c.Constraints { + // xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint + if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch { + return false, constraint + } + } + + // If no constraint or every constraints matching + return true, nil +} diff --git a/pkg/provider/docker/config.go b/pkg/provider/docker/config.go index 893c65a22..8bb6a83ec 100644 --- a/pkg/provider/docker/config.go +++ b/pkg/provider/docker/config.go @@ -33,6 +33,21 @@ func (p *Provider) buildConfiguration(ctx context.Context, containersInspected [ continue } + if len(confFromLabel.TCP.Routers) > 0 || len(confFromLabel.TCP.Services) > 0 { + err := p.buildTCPServiceConfiguration(ctxContainer, container, confFromLabel.TCP) + if err != nil { + logger.Error(err) + continue + } + provider.BuildTCPRouterConfiguration(ctxContainer, confFromLabel.TCP) + if len(confFromLabel.HTTP.Routers) == 0 && + len(confFromLabel.HTTP.Middlewares) == 0 && + len(confFromLabel.HTTP.Services) == 0 { + configurations[containerName] = confFromLabel + continue + } + } + err = p.buildServiceConfiguration(ctxContainer, container, confFromLabel.HTTP) if err != nil { logger.Error(err) @@ -57,6 +72,28 @@ func (p *Provider) buildConfiguration(ctx context.Context, containersInspected [ return provider.Merge(ctx, configurations) } +func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, container dockerData, configuration *config.TCPConfiguration) error { + serviceName := getServiceName(container) + + if len(configuration.Services) == 0 { + configuration.Services = make(map[string]*config.TCPService) + lb := &config.TCPLoadBalancerService{} + lb.SetDefaults() + configuration.Services[serviceName] = &config.TCPService{ + LoadBalancer: lb, + } + } + + for _, service := range configuration.Services { + err := p.addServerTCP(ctx, container, service.LoadBalancer) + if err != nil { + return err + } + } + + return nil +} + func (p *Provider) buildServiceConfiguration(ctx context.Context, container dockerData, configuration *config.HTTPConfiguration) error { serviceName := getServiceName(container) @@ -102,6 +139,36 @@ func (p *Provider) keepContainer(ctx context.Context, container dockerData) bool return true } +func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadBalancer *config.TCPLoadBalancerService) error { + serverPort := "" + if loadBalancer != nil && len(loadBalancer.Servers) > 0 { + serverPort = loadBalancer.Servers[0].Port + } + ip, port, err := p.getIPPort(ctx, container, serverPort) + if err != nil { + return err + } + + if len(loadBalancer.Servers) == 0 { + server := config.TCPServer{} + server.SetDefaults() + + loadBalancer.Servers = []config.TCPServer{server} + } + + if serverPort != "" { + port = serverPort + loadBalancer.Servers[0].Port = "" + } + + if port == "" { + return errors.New("port is missing") + } + + loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port) + return nil +} + func (p *Provider) addServer(ctx context.Context, container dockerData, loadBalancer *config.LoadBalancerService) error { serverPort := getLBServerPort(loadBalancer) ip, port, err := p.getIPPort(ctx, container, serverPort) diff --git a/pkg/provider/docker/config_test.go b/pkg/provider/docker/config_test.go index ebab2b95d..a6644d627 100644 --- a/pkg/provider/docker/config_test.go +++ b/pkg/provider/docker/config_test.go @@ -19,7 +19,7 @@ func TestDefaultRule(t *testing.T) { desc string containers []dockerData defaultRule string - expected *config.HTTPConfiguration + expected *config.Configuration }{ { desc: "default rule with no variable", @@ -42,25 +42,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: "Host(`foo.bar`)", - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`foo.bar`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`foo.bar`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -87,25 +93,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: "Host(`{{ .Name }}.foo.bar`)", - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.foo.bar`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.foo.bar`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -134,25 +146,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: `Host("{{ .Name }}.{{ index .Labels "traefik.domain" }}")`, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: `Host("Test.foo.bar")`, - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: `Host("Test.foo.bar")`, + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -179,20 +197,26 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: `Host("{{ .Toto }}")`, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -219,20 +243,26 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: ``, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -259,25 +289,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: DefaultTemplateRule, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -287,7 +323,6 @@ func TestDefaultRule(t *testing.T) { for _, test := range testCases { test := test - t.Run(test.desc, func(t *testing.T) { t.Parallel() @@ -307,7 +342,7 @@ func TestDefaultRule(t *testing.T) { configuration := p.buildConfiguration(context.Background(), test.containers) - assert.Equal(t, test.expected, configuration.HTTP) + assert.Equal(t, test.expected, configuration) }) } } @@ -317,7 +352,7 @@ func Test_buildConfiguration(t *testing.T) { desc string containers []dockerData constraints types.Constraints - expected *config.HTTPConfiguration + expected *config.Configuration }{ { desc: "one container no label", @@ -339,25 +374,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -399,41 +440,47 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, - "Test2": { - Service: "Test2", - Rule: "Host(`Test2.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - }, - Method: "wrr", - PassHostHeader: true, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + "Test2": { + Service: "Test2", + Rule: "Host(`Test2.traefik.wtf`)", }, }, - "Test2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.2:80", - Weight: 1, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, + }, + }, + "Test2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -477,29 +524,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -527,25 +580,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "drr", + PassHostHeader: true, }, - Method: "drr", - PassHostHeader: true, }, }, }, @@ -575,25 +634,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Router1": { - Service: "Service1", - Rule: "Host(`foo.com`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Router1": { + Service: "Service1", + Rule: "Host(`foo.com`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -621,26 +686,32 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, - }, - Routers: map[string]*config.Router{ - "Router1": { - Service: "Test", - Rule: "Host(`foo.com`)", + Routers: map[string]*config.Router{ + "Router1": { + Service: "Test", + Rule: "Host(`foo.com`)", + }, }, }, }, @@ -668,25 +739,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Router1": { - Service: "Service1", - Rule: "Host(`foo.com`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Router1": { + Service: "Service1", + Rule: "Host(`foo.com`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -716,32 +793,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, - }, - "Service2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + "Service2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -789,15 +872,21 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, }, }, { @@ -861,15 +950,21 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, }, }, { @@ -914,29 +1009,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "drr", + PassHostHeader: true, }, - Method: "drr", - PassHostHeader: true, }, }, }, @@ -964,32 +1065,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - }, - Method: "wrr", - PassHostHeader: true, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", }, }, - }, - Middlewares: map[string]*config.Middleware{ - "Middleware1": { - MaxConn: &config.MaxConn{ - Amount: 42, - ExtractorFunc: "request.host", + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, + }, + }, + }, + Middlewares: map[string]*config.Middleware{ + "Middleware1": { + MaxConn: &config.MaxConn{ + Amount: 42, + ExtractorFunc: "request.host", + }, }, }, }, @@ -1037,36 +1144,42 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{ - "Middleware1": { - MaxConn: &config.MaxConn{ - Amount: 42, - ExtractorFunc: "request.host", + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", }, }, - }, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, - }, + Middlewares: map[string]*config.Middleware{ + "Middleware1": { + MaxConn: &config.MaxConn{ + Amount: 42, + ExtractorFunc: "request.host", + }, + }, + }, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1114,29 +1227,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1203,33 +1322,39 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, - }, - { - URL: "http://127.0.0.3:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + { + URL: "http://127.0.0.3:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1277,24 +1402,30 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1361,28 +1492,34 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, - }, - { - URL: "http://127.0.0.3:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + { + URL: "http://127.0.0.3:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1430,29 +1567,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Router1": { - Service: "Test", - Rule: "Host(`foo.com`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Router1": { + Service: "Test", + Rule: "Host(`foo.com`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1498,32 +1641,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, - }, - "Test2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.2:80", - Weight: 1, + "Test2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1551,25 +1700,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1598,25 +1753,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "h2c://127.0.0.1:8080", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "h2c://127.0.0.1:8080", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1645,32 +1806,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, - }, - "Service2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:8080", - Weight: 1, + "Service2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:8080", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1694,10 +1861,16 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1720,10 +1893,16 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1748,10 +1927,16 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1775,10 +1960,16 @@ func Test_buildConfiguration(t *testing.T) { Health: "not_healthy", }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1810,10 +2001,16 @@ func Test_buildConfiguration(t *testing.T) { Regex: "bar", }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1845,25 +2042,31 @@ func Test_buildConfiguration(t *testing.T) { Regex: "foo", }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1892,37 +2095,345 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - Middlewares: []string{"Middleware1"}, - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{ - "Middleware1": { - BasicAuth: &config.BasicAuth{ - Users: []string{ - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", - }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + Middlewares: []string{"Middleware1"}, }, }, - }, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + Middlewares: map[string]*config.Middleware{ + "Middleware1": { + BasicAuth: &config.BasicAuth{ + Users: []string{ + "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", + "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", }, }, - Method: "wrr", - PassHostHeader: true, }, }, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, + }, + }, + }, + }, + }, + }, + { + desc: "tcp with label", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{ + "foo": { + Service: "Test", + Rule: "HostSNI(`foo.bar`)", + TLS: &config.RouterTCPTLSConfig{}, + }, + }, + Services: map[string]*config.TCPService{ + "Test": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, + }, + }, + { + desc: "tcp with label without rule", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.tls": "true", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{ + "Test": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, + }, + }, + { + desc: "tcp with label and port", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{ + "foo": { + Service: "foo", + Rule: "HostSNI(`foo.bar`)", + TLS: &config.RouterTCPTLSConfig{}, + }, + }, + Services: map[string]*config.TCPService{ + "foo": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:8080", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, + }, + }, + { + desc: "tcp with label and port and http service", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + "traefik.http.services.Service1.loadbalancer.method": "drr", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + { + ID: "2", + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + "traefik.http.services.Service1.loadbalancer.method": "drr", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.2", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{ + "foo": { + Service: "foo", + Rule: "HostSNI(`foo.bar`)", + TLS: &config.RouterTCPTLSConfig{}, + }, + }, + Services: map[string]*config.TCPService{ + "foo": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:8080", + Weight: 1, + }, + { + Address: "127.0.0.2:8080", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + }, + Method: "drr", + PassHostHeader: true, + }, + }, + }, + }, + }, + }, + { + desc: "tcp with label for tcp service", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{ + "foo": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:8080", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, }, }, }, @@ -1951,7 +2462,7 @@ func Test_buildConfiguration(t *testing.T) { configuration := p.buildConfiguration(context.Background(), test.containers) - assert.Equal(t, test.expected, configuration.HTTP) + assert.Equal(t, test.expected, configuration) }) } } diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go index 81aca428f..f700f5aba 100644 --- a/pkg/provider/docker/docker.go +++ b/pkg/provider/docker/docker.go @@ -41,7 +41,8 @@ var _ provider.Provider = (*Provider)(nil) // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` + provider.Constrainer `mapstructure:",squash" export:"true"` + Watch bool `description:"Watch provider" export:"true"` Endpoint string `description:"Docker server endpoint. Can be a tcp or a unix socket endpoint"` DefaultRule string `description:"Default rule"` TLS *types.ClientTLS `description:"Enable Docker TLS support" export:"true"` @@ -61,7 +62,7 @@ func (p *Provider) Init() error { } p.defaultRuleTpl = defaultRuleTpl - return p.BaseProvider.Init() + return nil } // dockerData holds the need data to the provider. diff --git a/pkg/provider/file/file.go b/pkg/provider/file/file.go index 95f5bc6ce..805b672cd 100644 --- a/pkg/provider/file/file.go +++ b/pkg/provider/file/file.go @@ -1,6 +1,7 @@ package file import ( + "bytes" "context" "fmt" "io/ioutil" @@ -10,6 +11,8 @@ import ( "strings" "text/template" + "github.com/BurntSushi/toml" + "github.com/Masterminds/sprig" "github.com/containous/traefik/pkg/config" "github.com/containous/traefik/pkg/log" "github.com/containous/traefik/pkg/provider" @@ -25,14 +28,16 @@ var _ provider.Provider = (*Provider)(nil) // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` - Directory string `description:"Load configuration from one or more .toml files in a directory" export:"true"` - TraefikFile string + Directory string `description:"Load configuration from one or more .toml files in a directory" export:"true"` + Watch bool `description:"Watch provider" export:"true"` + Filename string `description:"Override default configuration template. For advanced users :)" export:"true"` + DebugLogGeneratedTemplate bool `description:"Enable debug logging of generated configuration template." export:"true"` + TraefikFile string } // Init the provider func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the file provider to provide configurations to traefik @@ -305,3 +310,55 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st } return configuration, nil } + +// CreateConfiguration creates a provider configuration from content using templating. +func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) { + var defaultFuncMap = sprig.TxtFuncMap() + defaultFuncMap["normalize"] = provider.Normalize + defaultFuncMap["split"] = strings.Split + for funcID, funcElement := range funcMap { + defaultFuncMap[funcID] = funcElement + } + + tmpl := template.New(p.Filename).Funcs(defaultFuncMap) + + _, err := tmpl.Parse(tmplContent) + if err != nil { + return nil, err + } + + var buffer bytes.Buffer + err = tmpl.Execute(&buffer, templateObjects) + if err != nil { + return nil, err + } + + var renderedTemplate = buffer.String() + if p.DebugLogGeneratedTemplate { + log.Debugf("Template content: %s", tmplContent) + log.Debugf("Rendering results: %s", renderedTemplate) + } + return p.DecodeConfiguration(renderedTemplate) +} + +// DecodeConfiguration Decodes a *types.Configuration from a content. +func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, error) { + configuration := &config.Configuration{ + HTTP: &config.HTTPConfiguration{ + Routers: make(map[string]*config.Router), + Middlewares: make(map[string]*config.Middleware), + Services: make(map[string]*config.Service), + }, + TCP: &config.TCPConfiguration{ + Routers: make(map[string]*config.TCPRouter), + Services: make(map[string]*config.TCPService), + }, + TLS: make([]*tls.Configuration, 0), + TLSStores: make(map[string]tls.Store), + TLSOptions: make(map[string]tls.TLS), + } + if _, err := toml.Decode(content, configuration); err != nil { + return nil, err + } + return configuration, nil +} diff --git a/pkg/provider/kubernetes/crd/client.go b/pkg/provider/kubernetes/crd/client.go index e17566841..948453189 100644 --- a/pkg/provider/kubernetes/crd/client.go +++ b/pkg/provider/kubernetes/crd/client.go @@ -65,7 +65,7 @@ type clientWrapper struct { factoriesCrd map[string]externalversions.SharedInformerFactory factoriesKube map[string]informers.SharedInformerFactory - ingressLabelSelector labels.Selector + labelSelector labels.Selector isNamespaceAll bool watchedNamespaces k8s.Namespaces @@ -202,7 +202,7 @@ func (c *clientWrapper) GetIngressRoutes() []*v1alpha1.IngressRoute { var result []*v1alpha1.IngressRoute for ns, factory := range c.factoriesCrd { - ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(c.ingressLabelSelector) + ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(c.labelSelector) if err != nil { log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err) } @@ -216,7 +216,7 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware { var result []*v1alpha1.Middleware for ns, factory := range c.factoriesCrd { - ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.ingressLabelSelector) + ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.labelSelector) if err != nil { log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err) } @@ -230,7 +230,7 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware { func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress { var result []*extensionsv1beta1.Ingress for ns, factory := range c.factoriesKube { - ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.ingressLabelSelector) + ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.labelSelector) if err != nil { log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err) } @@ -320,7 +320,7 @@ func (c *clientWrapper) newResourceEventHandler(events chan<- interface{}) cache // Ignore Ingresses that do not match our custom label selector. if ing, ok := obj.(*extensionsv1beta1.Ingress); ok { lbls := labels.Set(ing.GetLabels()) - return c.ingressLabelSelector.Matches(lbls) + return c.labelSelector.Matches(lbls) } return true }, diff --git a/pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml b/pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml new file mode 100644 index 000000000..dde9941b8 --- /dev/null +++ b/pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml @@ -0,0 +1,20 @@ +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: test.crd + namespace: default + +spec: + entryPoints: + - web + + routes: + - match: Host(`foo.com`) && PathPrefix(`/bar`) + kind: Rule + priority: 12 + services: + - name: whoami + port: 80 + + tls: + secretName: diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index 8d8b50c92..95e0df3d4 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -16,7 +16,6 @@ import ( "github.com/containous/traefik/pkg/config" "github.com/containous/traefik/pkg/job" "github.com/containous/traefik/pkg/log" - "github.com/containous/traefik/pkg/provider" "github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1" "github.com/containous/traefik/pkg/provider/kubernetes/k8s" "github.com/containous/traefik/pkg/safe" @@ -33,23 +32,22 @@ const ( // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"` Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"` CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"` DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"` Namespaces k8s.Namespaces `description:"Kubernetes namespaces" export:"true"` - LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"` + LabelSelector string `description:"Kubernetes label selector to use" export:"true"` IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"` lastConfiguration safe.Safe } -func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string) (*clientWrapper, error) { - ingLabelSel, err := labels.Parse(ingressLabelSelector) +func (p *Provider) newK8sClient(ctx context.Context, labelSelector string) (*clientWrapper, error) { + labelSel, err := labels.Parse(labelSelector) if err != nil { - return nil, fmt.Errorf("invalid ingress label selector: %q", ingressLabelSelector) + return nil, fmt.Errorf("invalid label selector: %q", labelSelector) } - log.FromContext(ctx).Infof("ingress label selector is: %q", ingLabelSel) + log.FromContext(ctx).Infof("label selector is: %q", labelSel) withEndpoint := "" if p.Endpoint != "" { @@ -70,7 +68,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string } if err == nil { - client.ingressLabelSelector = ingLabelSel + client.labelSelector = labelSel } return client, err @@ -78,7 +76,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string // Init the provider. func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the k8s provider to provide configurations to traefik @@ -95,7 +93,7 @@ func (p *Provider) Provide(configurationChan chan<- config.Message, pool *safe.P return err } - logger.Debugf("Using Ingress label selector: %q", p.LabelSelector) + logger.Debugf("Using label selector: %q", p.LabelSelector) k8sClient, err := p.newK8sClient(ctxLog, p.LabelSelector) if err != nil { return err diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index c185ce6e1..689552501 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -310,6 +310,43 @@ func TestLoadIngressRoutes(t *testing.T) { }, }, }, + { + desc: "TLS with ACME", + paths: []string{"services.yml", "with_tls_acme.yml"}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{}, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "default/test.crd-6b204d94623b3df4370c": { + EntryPoints: []string{"web"}, + Service: "default/test.crd-6b204d94623b3df4370c", + Rule: "Host(`foo.com`) && PathPrefix(`/bar`)", + Priority: 12, + TLS: &config.RouterTLSConfig{}, + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "default/test.crd-6b204d94623b3df4370c": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://10.10.0.1:80", + Weight: 1, + }, + { + URL: "http://10.10.0.2:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, + }, + }, + }, + }, + }, + }, { desc: "Simple Ingress Route, defaulting to https for servers", paths: []string{"services.yml", "with_https_default.yml"}, diff --git a/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go b/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go index f4e4ded43..77e7b1534 100644 --- a/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go +++ b/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go @@ -20,8 +20,11 @@ type Route struct { Middlewares []MiddlewareRef `json:"middlewares"` } -// TLS contains the TLS certificates configuration of the routes. +// TLS contains the TLS certificates configuration of the routes. To enable +// Let's Encrypt, set a SecretName with an empty value. type TLS struct { + // SecretName is the name of the referenced Kubernetes Secret to specify the + // certificate details. SecretName string `json:"secretName"` // TODO MinimumProtocolVersion string `json:"minimumProtocolVersion,omitempty"` } diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index d60daacaa..bc567f599 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -16,7 +16,6 @@ import ( "github.com/containous/traefik/pkg/config" "github.com/containous/traefik/pkg/job" "github.com/containous/traefik/pkg/log" - "github.com/containous/traefik/pkg/provider" "github.com/containous/traefik/pkg/provider/kubernetes/k8s" "github.com/containous/traefik/pkg/safe" "github.com/containous/traefik/pkg/tls" @@ -34,7 +33,6 @@ const ( // Provider holds configurations of the provider. type Provider struct { - provider.BaseProvider `mapstructure:",squash" export:"true"` Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"` Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"` CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"` @@ -90,7 +88,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string // Init the provider. func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the k8s provider to provide configurations to traefik diff --git a/pkg/provider/label/parser_test.go b/pkg/provider/label/parser_test.go index 53a44d3f8..ef2d7ee71 100644 --- a/pkg/provider/label/parser_test.go +++ b/pkg/provider/label/parser_test.go @@ -115,6 +115,7 @@ func TestDecodeConfiguration(t *testing.T) { "traefik.http.routers.Router0.middlewares": "foobar, fiibar", "traefik.http.routers.Router0.priority": "42", "traefik.http.routers.Router0.rule": "foobar", + "traefik.http.routers.Router0.tls": "true", "traefik.http.routers.Router0.service": "foobar", "traefik.http.routers.Router1.entrypoints": "foobar, fiibar", "traefik.http.routers.Router1.middlewares": "foobar, fiibar", @@ -171,6 +172,7 @@ func TestDecodeConfiguration(t *testing.T) { Service: "foobar", Rule: "foobar", Priority: 42, + TLS: &config.RouterTLSConfig{}, }, "Router1": { EntryPoints: []string{ @@ -504,6 +506,7 @@ func TestEncodeConfiguration(t *testing.T) { Service: "foobar", Rule: "foobar", Priority: 42, + TLS: &config.RouterTLSConfig{}, }, "Router1": { EntryPoints: []string{ @@ -925,6 +928,7 @@ func TestEncodeConfiguration(t *testing.T) { "traefik.HTTP.Routers.Router0.Priority": "42", "traefik.HTTP.Routers.Router0.Rule": "foobar", "traefik.HTTP.Routers.Router0.Service": "foobar", + "traefik.HTTP.Routers.Router0.TLS": "true", "traefik.HTTP.Routers.Router1.EntryPoints": "foobar, fiibar", "traefik.HTTP.Routers.Router1.Middlewares": "foobar, fiibar", "traefik.HTTP.Routers.Router1.Priority": "42", diff --git a/pkg/provider/marathon/label_test.go b/pkg/provider/marathon/label_test.go index 8eee255e5..7cb011939 100644 --- a/pkg/provider/marathon/label_test.go +++ b/pkg/provider/marathon/label_test.go @@ -4,7 +4,6 @@ import ( "math" "testing" - "github.com/containous/traefik/pkg/provider" "github.com/gambol99/go-marathon" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -24,7 +23,6 @@ func TestGetConfiguration(t *testing.T) { Labels: &map[string]string{}, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: false, }, @@ -45,7 +43,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: false, }, @@ -66,7 +63,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: false, }, @@ -87,7 +83,6 @@ func TestGetConfiguration(t *testing.T) { Labels: &map[string]string{}, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: false, FilterMarathonConstraints: true, }, @@ -108,7 +103,6 @@ func TestGetConfiguration(t *testing.T) { Labels: &map[string]string{}, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: true, FilterMarathonConstraints: false, }, @@ -129,7 +123,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: true, FilterMarathonConstraints: false, }, @@ -150,7 +143,6 @@ func TestGetConfiguration(t *testing.T) { }, }, p: Provider{ - BaseProvider: provider.BaseProvider{}, ExposedByDefault: true, FilterMarathonConstraints: false, }, diff --git a/pkg/provider/marathon/marathon.go b/pkg/provider/marathon/marathon.go index 5e6268d1a..2a4ad9c73 100644 --- a/pkg/provider/marathon/marathon.go +++ b/pkg/provider/marathon/marathon.go @@ -46,7 +46,9 @@ var _ provider.Provider = (*Provider)(nil) // Provider holds configuration of the provider. type Provider struct { - provider.BaseProvider + provider.Constrainer `mapstructure:",squash" export:"true"` + Trace bool `description:"Display additional provider logs." export:"true"` + Watch bool `description:"Watch provider" export:"true"` Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon" export:"true"` DefaultRule string `description:"Default rule"` ExposedByDefault bool `description:"Expose Marathon apps by default" export:"true"` @@ -89,7 +91,7 @@ func (p *Provider) Init() error { } p.defaultRuleTpl = defaultRuleTpl - return p.BaseProvider.Init() + return nil } // Provide allows the marathon provider to provide configurations to traefik diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go index a3443cc8a..b2ee10eba 100644 --- a/pkg/server/server_entrypoint_tcp.go +++ b/pkg/server/server_entrypoint_tcp.go @@ -312,11 +312,13 @@ func (c *connectionTracker) Shutdown(ctx context.Context) error { // Close close all the connections in the tracked connections list func (c *connectionTracker) Close() { + c.lock.Lock() + defer c.lock.Unlock() for conn := range c.conns { if err := conn.Close(); err != nil { log.WithoutContext().Errorf("Error while closing connection: %v", err) } - c.RemoveConnection(conn) + delete(c.conns, conn) } } diff --git a/script/.validate b/script/.validate index 42b4cc70c..c8c87e3bc 100644 --- a/script/.validate +++ b/script/.validate @@ -5,14 +5,9 @@ if [ -z "${VALIDATE_UPSTREAM:-}" ]; then # are running more than one validate bundlescript VALIDATE_REPO='https://github.com/containous/traefik.git' + ## FIXME wrong assumption VALIDATE_BRANCH='master' - # Should not be needed for now O:) - # if [ "$TRAVIS" = 'true' -a "$TRAVIS_PULL_REQUEST" != 'false' ]; then - # VALIDATE_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git" - # VALIDATE_BRANCH="${TRAVIS_BRANCH}" - # fi - VALIDATE_HEAD="$(git rev-parse --verify HEAD)" git fetch -q "$VALIDATE_REPO" "refs/heads/$VALIDATE_BRANCH" @@ -26,9 +21,4 @@ if [ -z "${VALIDATE_UPSTREAM:-}" ]; then git diff "$VALIDATE_COMMIT_DIFF" "$@" fi } - validate_log() { - if [ "$VALIDATE_UPSTREAM" != "$VALIDATE_HEAD" ]; then - git log "$VALIDATE_COMMIT_LOG" "$@" - fi - } fi diff --git a/script/crossbinary b/script/crossbinary deleted file mode 100755 index a0ee7817b..000000000 --- a/script/crossbinary +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -e - -./script/crossbinary-default -./script/crossbinary-others diff --git a/script/crossbinary-others b/script/crossbinary-others deleted file mode 100755 index aca441662..000000000 --- a/script/crossbinary-others +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -set -e - -if ! test -e autogen/genstatic/gen.go; then - echo >&2 'error: generate must be run before crossbinary' - false -fi - -if [ -z "$VERSION" ]; then - VERSION=$(git rev-parse HEAD) -fi - -if [ -z "$CODENAME" ]; then - CODENAME=cheddar -fi - -if [ -z "$DATE" ]; then - DATE=$(date -u '+%Y-%m-%d_%I:%M:%S%p') -fi - -echo "Building ${VERSION} ${CODENAME} ${DATE}" - -GIT_REPO_URL='github.com/containous/traefik/pkg/version' -GO_BUILD_CMD="go build -ldflags" -GO_BUILD_OPT="-s -w -X ${GIT_REPO_URL}.Version=${VERSION} -X ${GIT_REPO_URL}.Codename=${CODENAME} -X ${GIT_REPO_URL}.BuildDate=${DATE}" - -# Build arm binaries -OS_PLATFORM_ARG=(linux windows darwin) -OS_ARCH_ARG=(386) -for OS in ${OS_PLATFORM_ARG[@]}; do - BIN_EXT='' - if [ "$OS" == "windows" ]; then - BIN_EXT='.exe' - fi - for ARCH in ${OS_ARCH_ARG[@]}; do - echo "Building binary for ${OS}/${ARCH}..." - GOARCH=${ARCH} GOOS=${OS} CGO_ENABLED=0 ${GO_BUILD_CMD} "${GO_BUILD_OPT}" -o "dist/traefik_${OS}-${ARCH}${BIN_EXT}" ./cmd/traefik/ - done -done - -# Build Bsd binaries -OS_PLATFORM_ARG=(freebsd openbsd) -OS_ARCH_ARG=(386 amd64) -for OS in ${OS_PLATFORM_ARG[@]}; do - for ARCH in ${OS_ARCH_ARG[@]}; do - # Get rid of existing binaries - rm -f dist/traefik_${OS}-${ARCH} - echo "Building binary for $OS/$ARCH..." - GOARCH=${ARCH} GOOS=${OS} CGO_ENABLED=0 ${GO_BUILD_CMD} "$GO_BUILD_OPT" -o "dist/traefik_$OS-$ARCH" ./cmd/traefik/ - done -done - -# Build arm binaries -OS_PLATFORM_ARG=(linux) -OS_ARCH_ARG=(arm) -ARM_ARG=(6) -for OS in ${OS_PLATFORM_ARG[@]}; do - for ARCH in ${OS_ARCH_ARG[@]}; do - for ARM in ${ARM_ARG[@]}; do - echo "Building binary for $OS/${ARCH}32v${ARM}..." - GOARCH=${ARCH} GOOS=${OS} GOARM=${ARM} CGO_ENABLED=0 ${GO_BUILD_CMD} "$GO_BUILD_OPT" -o "dist/traefik_$OS-${ARCH}" ./cmd/traefik/ - done - done -done - -# Build ppc64le binaries -OS_PLATFORM_ARG=(linux) -OS_ARCH_ARG=(ppc64le) -for OS in ${OS_PLATFORM_ARG[@]}; do - for ARCH in ${OS_ARCH_ARG[@]}; do - echo "Building binary for ${OS}/${ARCH}..." - GOARCH=${ARCH} GOOS=${OS} CGO_ENABLED=0 ${GO_BUILD_CMD} "${GO_BUILD_OPT}" -o "dist/traefik_${OS}-${ARCH}" ./cmd/traefik/ - done -done diff --git a/script/deploy-docker.sh b/script/deploy-docker.sh deleted file mode 100644 index d73a95faa..000000000 --- a/script/deploy-docker.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [ -n "$TRAVIS_COMMIT" ]; then - echo "Deploying PR..." -else - echo "Skipping deploy PR" - exit 0 -fi - -# create docker image containous/traefik -echo "Updating docker containous/traefik image..." -docker login -u $DOCKER_USER -p $DOCKER_PASS -docker tag containous/traefik containous/traefik:${TRAVIS_COMMIT} -docker push containous/traefik:${TRAVIS_COMMIT} -docker tag containous/traefik containous/traefik:experimental -docker push containous/traefik:experimental - -echo "Deployed" diff --git a/script/deploy.sh b/script/deploy.sh index 8504e4ffb..6f67e99a6 100755 --- a/script/deploy.sh +++ b/script/deploy.sh @@ -22,7 +22,7 @@ ssh-add ~/.ssh/traefiker_rsa echo "Updating traefik-library-imag repo..." git clone git@github.com:containous/traefik-library-image.git cd traefik-library-image -./update.sh $VERSION +./updatev2.sh $VERSION git add -A echo $VERSION | git commit --file - echo $VERSION | git tag -a $VERSION --file - diff --git a/traefik.sample.toml b/traefik.sample.toml index 6d3368719..e409edab3 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -1,20 +1,9 @@ ################################################################ # Global configuration ################################################################ - -# Enable debug mode -# -# Optional -# Default: false -# -# debug = true - -# Log level -# -# Optional -# Default: "ERROR" -# -# logLevel = "DEBUG" +[global] + checkNewVersion = true + sendAnonymousUsage = true ################################################################ # Entrypoints configuration @@ -37,7 +26,14 @@ # # Optional # -# [traefikLog] +[log] + +# Log level +# +# Optional +# Default: "ERROR" +# +# logLevel = "DEBUG" # Sets the filepath for the traefik log. If not specified, stdout will be used. # Intermediate directories are created if necessary. @@ -121,7 +117,7 @@ ################################################################ # Enable Docker configuration backend -[docker] +[providers.docker] # Docker server endpoint. Can be a tcp or a unix socket endpoint. # @@ -130,13 +126,12 @@ # # endpoint = "tcp://10.10.10.10:2375" -# Default domain used. -# Can be overridden by setting the "traefik.domain" label on a container. +# Default host rule. # # Optional # Default: "" # -# domain = "docker.localhost" +# DefaultRule = "Host(`{{ normalize .Name }}.docker.localhost`)" # Expose containers by default in traefik # diff --git a/webui/src/app/app.component.ts b/webui/src/app/app.component.ts index 4218b7340..abed5b68c 100644 --- a/webui/src/app/app.component.ts +++ b/webui/src/app/app.component.ts @@ -1,4 +1,5 @@ -import { Component } from '@angular/core'; +import { Component, Inject } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-root', @@ -6,9 +7,30 @@ import { Component } from '@angular/core';
logo
-

Work in progress...

+

+ + Work in progress... +

+

+ In the meantime, you can review your current configuration by using + the + {{ href }}/api/rawdata endpoint +

+ Also, please keep your on our + documentation + to stay informed +

+

` }) -export class AppComponent {} +export class AppComponent { + public href: string; + + constructor(@Inject(DOCUMENT) private document: Document) { + this.href = this.document.location.origin; + } +}