feat: use dedicated entrypoint for the tunnels
Co-authored-by: Fernandez Ludovic <[ldez@users.noreply.github.com](mailto:ldez@users.noreply.github.com)>
This commit is contained in:
parent
619621f239
commit
86cc6df374
21 changed files with 386 additions and 384 deletions
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/traefik/traefik/v2/pkg/pilot"
|
"github.com/traefik/traefik/v2/pkg/pilot"
|
||||||
"github.com/traefik/traefik/v2/pkg/provider/acme"
|
"github.com/traefik/traefik/v2/pkg/provider/acme"
|
||||||
"github.com/traefik/traefik/v2/pkg/provider/aggregator"
|
"github.com/traefik/traefik/v2/pkg/provider/aggregator"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||||
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
"github.com/traefik/traefik/v2/pkg/provider/traefik"
|
||||||
"github.com/traefik/traefik/v2/pkg/safe"
|
"github.com/traefik/traefik/v2/pkg/safe"
|
||||||
"github.com/traefik/traefik/v2/pkg/server"
|
"github.com/traefik/traefik/v2/pkg/server"
|
||||||
|
@ -215,8 +216,6 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if staticConfiguration.Pilot != nil {
|
if staticConfiguration.Pilot != nil {
|
||||||
log.WithoutContext().Warn("Traefik Pilot is deprecated and will be removed soon. Please check our Blog for migration instructions later this year")
|
|
||||||
|
|
||||||
version.PilotEnabled = staticConfiguration.Pilot.Dashboard
|
version.PilotEnabled = staticConfiguration.Pilot.Dashboard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +362,7 @@ func getDefaultsEntrypoints(staticConfiguration *static.Configuration) []string
|
||||||
var defaultEntryPoints []string
|
var defaultEntryPoints []string
|
||||||
for name, cfg := range staticConfiguration.EntryPoints {
|
for name, cfg := range staticConfiguration.EntryPoints {
|
||||||
// Traefik Hub entryPoint should not be part of the set of default entryPoints.
|
// Traefik Hub entryPoint should not be part of the set of default entryPoints.
|
||||||
if staticConfiguration.Hub != nil && staticConfiguration.Hub.EntryPoint == name {
|
if hub.APIEntrypoint == name || hub.TunnelEntrypoint == name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -457,10 +457,3 @@ the value for the method label becomes `EXTENSION_METHOD`, instead of the reques
|
||||||
### Tracing
|
### Tracing
|
||||||
|
|
||||||
In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `traefik.service.name` and from `router.name` to `traefik.router.name`.
|
In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `traefik.service.name` and from `router.name` to `traefik.router.name`.
|
||||||
|
|
||||||
## v2.7
|
|
||||||
|
|
||||||
### Traefik Pilot
|
|
||||||
|
|
||||||
In `v2.7`, the `pilot.token` and `pilot.dashboard` options are deprecated.
|
|
||||||
Please check the [feature deprecation page](../deprecation/features.md) and our Blog for migration instructions later this year.
|
|
||||||
|
|
|
@ -5,11 +5,6 @@ description: "Learn how to connect Traefik Proxy with Pilot, a SaaS platform tha
|
||||||
|
|
||||||
# Plugins and Traefik Pilot
|
# Plugins and Traefik Pilot
|
||||||
|
|
||||||
!!! warning "Traefik Pilot Deprecation"
|
|
||||||
|
|
||||||
Traefik Pilot is deprecated and will be removed soon.
|
|
||||||
Please check our Blog for migration instructions later this year.
|
|
||||||
|
|
||||||
Traefik Pilot is a software-as-a-service (SaaS) platform that connects to Traefik to extend its capabilities.
|
Traefik Pilot is a software-as-a-service (SaaS) platform that connects to Traefik to extend its capabilities.
|
||||||
It offers a number of features to enhance observability and control of Traefik through a global control plane and dashboard, including:
|
It offers a number of features to enhance observability and control of Traefik through a global control plane and dashboard, including:
|
||||||
|
|
||||||
|
|
|
@ -222,9 +222,6 @@ The maximal depth of DNS recursive resolving (Default: ```5```)
|
||||||
`--hub`:
|
`--hub`:
|
||||||
Traefik Hub configuration. (Default: ```false```)
|
Traefik Hub configuration. (Default: ```false```)
|
||||||
|
|
||||||
`--hub.entrypoint`:
|
|
||||||
Entrypoint that exposes data for Traefik Hub. It should be a dedicated one, and not used by any router. (Default: ```traefik-hub```)
|
|
||||||
|
|
||||||
`--hub.tls.ca`:
|
`--hub.tls.ca`:
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
The certificate authority authenticates the Traefik Hub Agent certificate.
|
||||||
|
|
||||||
|
|
|
@ -222,9 +222,6 @@ The maximal depth of DNS recursive resolving (Default: ```5```)
|
||||||
`TRAEFIK_HUB`:
|
`TRAEFIK_HUB`:
|
||||||
Traefik Hub configuration. (Default: ```false```)
|
Traefik Hub configuration. (Default: ```false```)
|
||||||
|
|
||||||
`TRAEFIK_HUB_ENTRYPOINT`:
|
|
||||||
Entrypoint that exposes data for Traefik Hub. It should be a dedicated one, and not used by any router. (Default: ```traefik-hub```)
|
|
||||||
|
|
||||||
`TRAEFIK_HUB_TLS_CA`:
|
`TRAEFIK_HUB_TLS_CA`:
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
The certificate authority authenticates the Traefik Hub Agent certificate.
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,6 @@
|
||||||
dashboard = true
|
dashboard = true
|
||||||
|
|
||||||
[hub]
|
[hub]
|
||||||
entrypoint = "foobar"
|
|
||||||
[hub.tls]
|
[hub.tls]
|
||||||
insecure = true
|
insecure = true
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
|
|
|
@ -447,7 +447,6 @@ pilot:
|
||||||
token: foobar
|
token: foobar
|
||||||
dashboard: true
|
dashboard: true
|
||||||
hub:
|
hub:
|
||||||
entrypoint: foobar
|
|
||||||
tls:
|
tls:
|
||||||
insecure: true
|
insecure: true
|
||||||
ca: foobar
|
ca: foobar
|
||||||
|
|
|
@ -1,295 +0,0 @@
|
||||||
# Traefik Hub (Experimental)
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Once the Traefik Hub Experimental feature is enabled in Traefik,
|
|
||||||
Traefik and its local agent communicate together.
|
|
||||||
This agent can:
|
|
||||||
|
|
||||||
* get the Traefik metrics to display them in the Traefik Hub UI
|
|
||||||
* secure the Traefik routers
|
|
||||||
* provide ACME certificates to Traefik
|
|
||||||
* transfer requests from the SaaS Platform to Traefik (and then avoid the users to expose directly their infrastructure on the internet)
|
|
||||||
|
|
||||||
!!! warning "Traefik Hub EntryPoint"
|
|
||||||
|
|
||||||
When the Traefik Hub feature is enabled, Traefik exposes some services meant for the Traefik Hub Agent on a dedicated entryPoint (on port `9900` by default).
|
|
||||||
Given their sensitive nature, those services should not be publicly exposed.
|
|
||||||
Also this dedicated entryPoint, regardless of how it is created (default, or user-defined), should not be used by anything other than the Hub Agent.
|
|
||||||
|
|
||||||
!!! important "Learn More About Traefik Hub"
|
|
||||||
|
|
||||||
This section is intended only as a brief overview for Traefik users who are not familiar with Traefik Hub.
|
|
||||||
To explore all that Traefik Hub has to offer, please consult the [Traefik Hub Documentation](https://doc.traefik.io/traefik-hub).
|
|
||||||
|
|
||||||
!!! Note "Prerequisites"
|
|
||||||
|
|
||||||
* Traefik Hub is compatible with Traefik Proxy 2.7 or later.
|
|
||||||
* The Traefik Hub Agent must be installed to connect to the Traefik Hub platform.
|
|
||||||
* Activate this feature in the experimental section of the static configuration.
|
|
||||||
|
|
||||||
!!! example "Minimal Static Configuration to Activate Traefik Hub"
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
experimental:
|
|
||||||
hub: true
|
|
||||||
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
insecure: true
|
|
||||||
|
|
||||||
metrics:
|
|
||||||
prometheus: {}
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[experimental]
|
|
||||||
hub = true
|
|
||||||
|
|
||||||
[hub]
|
|
||||||
[hub.tls]
|
|
||||||
insecure = true
|
|
||||||
|
|
||||||
[metrics]
|
|
||||||
[metrics.prometheus]
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--experimental.hub
|
|
||||||
--hub.tls.insecure=true
|
|
||||||
--metrics.prometheus=true
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### `entryPoint`
|
|
||||||
|
|
||||||
_Optional, Default="traefik-hub"_
|
|
||||||
|
|
||||||
Defines the entryPoint that exposes data for Traefik Hub Agent.
|
|
||||||
|
|
||||||
!!! info
|
|
||||||
|
|
||||||
* If no entryPoint is defined, a default `traefik-hub` entryPoint is created (on port `9900`).
|
|
||||||
* If defined, the value must match an existing entryPoint name.
|
|
||||||
* This dedicated Traefik Hub entryPoint should not be used by anything other than Traefik Hub.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
entryPoints:
|
|
||||||
hub-ep: ":8000"
|
|
||||||
|
|
||||||
hub:
|
|
||||||
entryPoint: "hub-ep"
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[entryPoints.hub-ep]
|
|
||||||
address = ":8000"
|
|
||||||
|
|
||||||
[hub]
|
|
||||||
entryPoint = "hub-ep"
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--entrypoints.hub-ep.address=:8000
|
|
||||||
--hub.entrypoint=hub-ep
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls`
|
|
||||||
|
|
||||||
_Required, Default=None_
|
|
||||||
|
|
||||||
This section allows configuring mutual TLS connection between Traefik Proxy and the Traefik Hub Agent.
|
|
||||||
The key and the certificate are the credentials for Traefik Proxy as a TLS client.
|
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
|
||||||
|
|
||||||
!!! note "Certificate Domain"
|
|
||||||
|
|
||||||
The certificate must be valid for the `proxy.traefik` domain.
|
|
||||||
|
|
||||||
!!! note "Certificates Definition"
|
|
||||||
|
|
||||||
Certificates can be defined either by their content or their path.
|
|
||||||
|
|
||||||
!!! note "Insecure Mode"
|
|
||||||
|
|
||||||
The `insecure` option is mutually exclusive with any other option.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
ca: /path/to/ca.pem
|
|
||||||
cert: /path/to/cert.pem
|
|
||||||
key: /path/to/key.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
ca= "/path/to/ca.pem"
|
|
||||||
cert= "/path/to/cert.pem"
|
|
||||||
key= "/path/to/key.pem"
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.ca=/path/to/ca.pem
|
|
||||||
--hub.tls.cert=/path/to/cert.pem
|
|
||||||
--hub.tls.key=/path/to/key.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.ca`
|
|
||||||
|
|
||||||
The certificate authority authenticates the Traefik Hub Agent certificate.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
ca: |-
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
ca = """-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----"""
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.ca=-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.cert`
|
|
||||||
|
|
||||||
The TLS certificate for Traefik Proxy as a TLS client.
|
|
||||||
|
|
||||||
!!! note "Certificate Domain"
|
|
||||||
|
|
||||||
The certificate must be valid for the `proxy.traefik` domain.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
cert: |-
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
cert = """-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----"""
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.cert=-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBcjCCARegAwIBAgIQaewCzGdRz5iNnjAiEoO5AzAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMCAXDTIyMDMyMTE2MTY0NFoYDzIxMjIwMjI1MTYxNjQ0
|
|
||||||
WjASMRAwDgYDVQQKEwdBY21lIENvMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
|
|
||||||
ZaKYPj2G8Hnmju6jbHt+vODwKqNDVQMH5nxhtAgSUZS61mLWwZvvUhIYLNPwHz8a
|
|
||||||
x8C7+cuihEC6Tzvn8DeGeKNNMEswDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20w
|
|
||||||
CgYIKoZIzj0EAwIDSQAwRgIhAO8sucDGY+JOrNgQg1a9ZqqYvbxPFnYsSZr7F/vz
|
|
||||||
aUX2AiEAilZ+M5eX4RiMFc3nlm9qVs1LZhV3dZW/u80/mPQ/oaY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.key`
|
|
||||||
|
|
||||||
The TLS key for Traefik Proxy as a TLS client.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
key: |-
|
|
||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgm+XJ3LVrTbbirJea
|
|
||||||
O+Crj2ADVsVHjMuiyd72VE3lgxihRANCAARlopg+PYbweeaO7qNse3684PAqo0NV
|
|
||||||
AwfmfGG0CBJRlLrWYtbBm+9SEhgs0/AfPxrHwLv5y6KEQLpPO+fwN4Z4
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
key = """-----BEGIN PRIVATE KEY-----
|
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgm+XJ3LVrTbbirJea
|
|
||||||
O+Crj2ADVsVHjMuiyd72VE3lgxihRANCAARlopg+PYbweeaO7qNse3684PAqo0NV
|
|
||||||
AwfmfGG0CBJRlLrWYtbBm+9SEhgs0/AfPxrHwLv5y6KEQLpPO+fwN4Z4
|
|
||||||
-----END PRIVATE KEY-----"""
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.key=-----BEGIN PRIVATE KEY-----
|
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgm+XJ3LVrTbbirJea
|
|
||||||
O+Crj2ADVsVHjMuiyd72VE3lgxihRANCAARlopg+PYbweeaO7qNse3684PAqo0NV
|
|
||||||
AwfmfGG0CBJRlLrWYtbBm+9SEhgs0/AfPxrHwLv5y6KEQLpPO+fwN4Z4
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
```
|
|
||||||
|
|
||||||
### `tls.insecure`
|
|
||||||
|
|
||||||
_Optional, Default=false_
|
|
||||||
|
|
||||||
Enables an insecure TLS connection that uses default credentials,
|
|
||||||
and which has no peer authentication between Traefik Proxy and the Traefik Hub Agent.
|
|
||||||
The `insecure` option is mutually exclusive with any other option.
|
|
||||||
|
|
||||||
!!! warning "Security Consideration"
|
|
||||||
|
|
||||||
Do not use this setup in production.
|
|
||||||
This option implies sensitive data can be exposed to potential malicious third-party programs.
|
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
|
||||||
hub:
|
|
||||||
tls:
|
|
||||||
insecure: true
|
|
||||||
```
|
|
||||||
|
|
||||||
```toml tab="File (TOML)"
|
|
||||||
[hub.tls]
|
|
||||||
insecure = true
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash tab="CLI"
|
|
||||||
--hub.tls.insecure=true
|
|
||||||
```
|
|
|
@ -136,7 +136,6 @@ nav:
|
||||||
- 'InFlightConn': 'middlewares/tcp/inflightconn.md'
|
- 'InFlightConn': 'middlewares/tcp/inflightconn.md'
|
||||||
- 'IpWhitelist': 'middlewares/tcp/ipwhitelist.md'
|
- 'IpWhitelist': 'middlewares/tcp/ipwhitelist.md'
|
||||||
- 'Plugins & Traefik Pilot': 'plugins/index.md'
|
- 'Plugins & Traefik Pilot': 'plugins/index.md'
|
||||||
- 'Traefik Hub': 'traefik-hub/index.md'
|
|
||||||
- 'Operations':
|
- 'Operations':
|
||||||
- 'CLI': 'operations/cli.md'
|
- 'CLI': 'operations/cli.md'
|
||||||
- 'Dashboard' : 'operations/dashboard.md'
|
- 'Dashboard' : 'operations/dashboard.md'
|
||||||
|
|
53
pkg/config/static/hub.go
Normal file
53
pkg/config/static/hub.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/traefik/traefik/v2/pkg/log"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Configuration) initHubProvider() error {
|
||||||
|
// Hub provider is an experimental feature. It requires the experimental flag to be enabled before continuing.
|
||||||
|
if c.Experimental == nil || !c.Experimental.Hub {
|
||||||
|
return errors.New("the experimental flag for Hub is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := c.EntryPoints[hub.TunnelEntrypoint]; !ok {
|
||||||
|
var ep EntryPoint
|
||||||
|
ep.SetDefaults()
|
||||||
|
ep.Address = ":9901"
|
||||||
|
c.EntryPoints[hub.TunnelEntrypoint] = &ep
|
||||||
|
log.WithoutContext().Infof("The entryPoint %q is created on port 9901 to allow exposition of services.", hub.TunnelEntrypoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Hub.TLS == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Hub.TLS.Insecure && (c.Hub.TLS.CA != "" || c.Hub.TLS.Cert != "" || c.Hub.TLS.Key != "") {
|
||||||
|
return errors.New("mTLS configuration for Hub and insecure TLS for Hub are mutually exclusive")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Hub.TLS.Insecure && (c.Hub.TLS.CA == "" || c.Hub.TLS.Cert == "" || c.Hub.TLS.Key == "") {
|
||||||
|
return errors.New("incomplete mTLS configuration for Hub")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Hub.TLS.Insecure {
|
||||||
|
log.WithoutContext().Warn("Hub is in `insecure` mode. Do not run in production with this setup.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := c.EntryPoints[hub.APIEntrypoint]; !ok {
|
||||||
|
var ep EntryPoint
|
||||||
|
ep.SetDefaults()
|
||||||
|
ep.Address = ":9900"
|
||||||
|
c.EntryPoints[hub.APIEntrypoint] = &ep
|
||||||
|
log.WithoutContext().Infof("The entryPoint %q is created on port 9900 to allow Traefik to communicate with the Hub Agent for Traefik.", hub.APIEntrypoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.EntryPoints[hub.APIEntrypoint].HTTP.TLS = &TLSConfig{
|
||||||
|
Options: "traefik-hub",
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package static
|
package static
|
||||||
|
|
||||||
// Pilot Configuration related to Traefik Pilot.
|
// Pilot Configuration related to Traefik Pilot.
|
||||||
// Deprecated.
|
|
||||||
type Pilot struct {
|
type Pilot struct {
|
||||||
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
|
||||||
Dashboard bool `description:"Enable Traefik Pilot in the dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty"`
|
Dashboard bool `description:"Enable Traefik Pilot in the dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty"`
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package static
|
package static
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
stdlog "log"
|
stdlog "log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -78,7 +77,6 @@ type Configuration struct {
|
||||||
|
|
||||||
CertificatesResolvers map[string]CertificateResolver `description:"Certificates resolvers configuration." json:"certificatesResolvers,omitempty" toml:"certificatesResolvers,omitempty" yaml:"certificatesResolvers,omitempty" export:"true"`
|
CertificatesResolvers map[string]CertificateResolver `description:"Certificates resolvers configuration." json:"certificatesResolvers,omitempty" toml:"certificatesResolvers,omitempty" yaml:"certificatesResolvers,omitempty" export:"true"`
|
||||||
|
|
||||||
// Deprecated.
|
|
||||||
Pilot *Pilot `description:"Traefik Pilot configuration." json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty" export:"true"`
|
Pilot *Pilot `description:"Traefik Pilot configuration." json:"pilot,omitempty" toml:"pilot,omitempty" yaml:"pilot,omitempty" export:"true"`
|
||||||
|
|
||||||
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||||
|
@ -201,7 +199,7 @@ type Providers struct {
|
||||||
// It also takes care of maintaining backwards compatibility.
|
// It also takes care of maintaining backwards compatibility.
|
||||||
func (c *Configuration) SetEffectiveConfiguration() {
|
func (c *Configuration) SetEffectiveConfiguration() {
|
||||||
// Creates the default entry point if needed
|
// Creates the default entry point if needed
|
||||||
if len(c.EntryPoints) == 0 || (c.Hub != nil && len(c.EntryPoints) == 1 && c.EntryPoints[c.Hub.EntryPoint] != nil) {
|
if !c.hasUserDefinedEntrypoint() {
|
||||||
ep := &EntryPoint{Address: ":80"}
|
ep := &EntryPoint{Address: ":80"}
|
||||||
ep.SetDefaults()
|
ep.SetDefaults()
|
||||||
// TODO: double check this tomorrow
|
// TODO: double check this tomorrow
|
||||||
|
@ -287,6 +285,21 @@ func (c *Configuration) SetEffectiveConfiguration() {
|
||||||
c.initACMEProvider()
|
c.initACMEProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) hasUserDefinedEntrypoint() bool {
|
||||||
|
if len(c.EntryPoints) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch len(c.EntryPoints) {
|
||||||
|
case 1:
|
||||||
|
return c.EntryPoints[hub.TunnelEntrypoint] == nil
|
||||||
|
case 2:
|
||||||
|
return c.EntryPoints[hub.TunnelEntrypoint] == nil || c.EntryPoints[hub.APIEntrypoint] == nil
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Configuration) initACMEProvider() {
|
func (c *Configuration) initACMEProvider() {
|
||||||
for _, resolver := range c.CertificatesResolvers {
|
for _, resolver := range c.CertificatesResolvers {
|
||||||
if resolver.ACME != nil {
|
if resolver.ACME != nil {
|
||||||
|
@ -297,46 +310,6 @@ func (c *Configuration) initACMEProvider() {
|
||||||
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
|
legolog.Logger = stdlog.New(log.WithoutContext().WriterLevel(logrus.DebugLevel), "legolog: ", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) initHubProvider() error {
|
|
||||||
// Hub provider is an experimental feature. Require the experimental flag to be enabled before continuing.
|
|
||||||
if c.Experimental == nil || !c.Experimental.Hub {
|
|
||||||
return errors.New("experimental flag for Hub not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hub.TLS == nil {
|
|
||||||
return errors.New("no TLS configuration defined for Hub")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hub.TLS.Insecure && (c.Hub.TLS.CA != "" || c.Hub.TLS.Cert != "" || c.Hub.TLS.Key != "") {
|
|
||||||
return errors.New("mTLS configuration for Hub and insecure TLS for Hub are mutually exclusive")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.Hub.TLS.Insecure && (c.Hub.TLS.CA == "" || c.Hub.TLS.Cert == "" || c.Hub.TLS.Key == "") {
|
|
||||||
return errors.New("incomplete mTLS configuration for Hub")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hub.TLS.Insecure {
|
|
||||||
log.WithoutContext().Warn("Hub is in `insecure` mode. Do not run in production with this setup.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates the internal Hub entry point if needed.
|
|
||||||
if c.Hub.EntryPoint == hub.DefaultEntryPointName {
|
|
||||||
if _, ok := c.EntryPoints[hub.DefaultEntryPointName]; !ok {
|
|
||||||
var ep EntryPoint
|
|
||||||
ep.SetDefaults()
|
|
||||||
ep.Address = ":9900"
|
|
||||||
c.EntryPoints[hub.DefaultEntryPointName] = &ep
|
|
||||||
log.WithoutContext().Infof("The entryPoint %q is created on port 9900 to allow Traefik to communicate with the Hub Agent for Traefik.", hub.DefaultEntryPointName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.EntryPoints[c.Hub.EntryPoint].HTTP.TLS = &TLSConfig{
|
|
||||||
Options: "traefik-hub",
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateConfiguration validate that configuration is coherent.
|
// ValidateConfiguration validate that configuration is coherent.
|
||||||
func (c *Configuration) ValidateConfiguration() error {
|
func (c *Configuration) ValidateConfiguration() error {
|
||||||
var acmeEmail string
|
var acmeEmail string
|
||||||
|
|
88
pkg/config/static/static_config_test.go
Normal file
88
pkg/config/static/static_config_test.go
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/traefik/traefik/v2/pkg/provider/hub"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHasEntrypoint(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
entryPoints map[string]*EntryPoint
|
||||||
|
assert assert.BoolAssertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "no user defined entryPoints",
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints + hub entryPoint (tunnel)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "hub entryPoint (tunnel)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints + hub entryPoint (api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "hub entryPoint (api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "user defined entryPoints + hub entryPoints (tunnel, api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
"foo": {},
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "hub entryPoints (tunnel, api)",
|
||||||
|
entryPoints: map[string]*EntryPoint{
|
||||||
|
hub.TunnelEntrypoint: {},
|
||||||
|
hub.APIEntrypoint: {},
|
||||||
|
},
|
||||||
|
assert: assert.False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := &Configuration{
|
||||||
|
EntryPoints: test.entryPoints,
|
||||||
|
}
|
||||||
|
|
||||||
|
test.assert(t, cfg.hasUserDefinedEntrypoint())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,12 +17,14 @@ import (
|
||||||
|
|
||||||
var _ provider.Provider = (*Provider)(nil)
|
var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
// DefaultEntryPointName is the name of the default internal entry point.
|
// Entrypoints created for Hub.
|
||||||
const DefaultEntryPointName = "traefik-hub"
|
const (
|
||||||
|
APIEntrypoint = "traefikhub-api"
|
||||||
|
TunnelEntrypoint = "traefikhub-tunl"
|
||||||
|
)
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
EntryPoint string `description:"Entrypoint that exposes data for Traefik Hub. It should be a dedicated one, and not used by any router." json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"`
|
|
||||||
TLS *TLS `description:"TLS configuration for mTLS communication between Traefik and Hub Agent." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
TLS *TLS `description:"TLS configuration for mTLS communication between Traefik and Hub Agent." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||||
|
|
||||||
server *http.Server
|
server *http.Server
|
||||||
|
@ -36,11 +38,6 @@ type TLS struct {
|
||||||
Key ttls.FileOrContent `description:"The TLS key for Traefik Proxy as a TLS client." json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
|
Key ttls.FileOrContent `description:"The TLS key for Traefik Proxy as a TLS client." json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults sets the default values.
|
|
||||||
func (p *Provider) SetDefaults() {
|
|
||||||
p.EntryPoint = DefaultEntryPointName
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init the provider.
|
// Init the provider.
|
||||||
func (p *Provider) Init() error {
|
func (p *Provider) Init() error {
|
||||||
return nil
|
return nil
|
||||||
|
@ -59,7 +56,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Poo
|
||||||
return fmt.Errorf("creating Hub Agent HTTP client: %w", err)
|
return fmt.Errorf("creating Hub Agent HTTP client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.server = &http.Server{Handler: newHandler(p.EntryPoint, port, configurationChan, p.TLS, client)}
|
p.server = &http.Server{Handler: newHandler(APIEntrypoint, port, configurationChan, p.TLS, client)}
|
||||||
|
|
||||||
// TODO: this is going to be leaky (because no context to make it terminate)
|
// TODO: this is going to be leaky (because no context to make it terminate)
|
||||||
// if/when Provide lifecycle differs with Traefik lifecycle.
|
// if/when Provide lifecycle differs with Traefik lifecycle.
|
||||||
|
@ -70,7 +67,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, _ *safe.Poo
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
exposeAPIAndMetrics(configurationChan, p.EntryPoint, port, p.TLS)
|
exposeAPIAndMetrics(configurationChan, APIEntrypoint, port, p.TLS)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ FROM node:14.16
|
||||||
# Current Active LTS release according to (https://nodejs.org/en/about/releases/)
|
# Current Active LTS release according to (https://nodejs.org/en/about/releases/)
|
||||||
|
|
||||||
ENV WEBUI_DIR /src/webui
|
ENV WEBUI_DIR /src/webui
|
||||||
|
ARG ARG_PLATFORM_URL=https://pilot.traefik.io
|
||||||
|
ENV PLATFORM_URL=${ARG_PLATFORM_URL}
|
||||||
RUN mkdir -p $WEBUI_DIR
|
RUN mkdir -p $WEBUI_DIR
|
||||||
|
|
||||||
COPY package.json $WEBUI_DIR/
|
COPY package.json $WEBUI_DIR/
|
||||||
|
|
|
@ -118,11 +118,13 @@ module.exports = function (ctx) {
|
||||||
env: process.env.APP_ENV === 'development'
|
env: process.env.APP_ENV === 'development'
|
||||||
? { // staging:
|
? { // staging:
|
||||||
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
||||||
APP_API: JSON.stringify(process.env.APP_API || '/api')
|
APP_API: JSON.stringify(process.env.APP_API || '/api'),
|
||||||
|
PLATFORM_URL: JSON.stringify(process.env.PLATFORM_URL || 'https://pilot.traefik.io')
|
||||||
}
|
}
|
||||||
: { // production:
|
: { // production:
|
||||||
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
APP_ENV: JSON.stringify(process.env.APP_ENV),
|
||||||
APP_API: JSON.stringify(process.env.APP_API || '/api')
|
APP_API: JSON.stringify(process.env.APP_API || '/api'),
|
||||||
|
PLATFORM_URL: JSON.stringify(process.env.PLATFORM_URL || 'https://pilot.traefik.io')
|
||||||
},
|
},
|
||||||
uglifyOptions: {
|
uglifyOptions: {
|
||||||
compress: {
|
compress: {
|
||||||
|
|
|
@ -1,17 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="q-app">
|
<div id="q-app">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
<platform-panel
|
||||||
|
v-if="pilotEnabled" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { APP } from './_helpers/APP'
|
import { APP } from './_helpers/APP'
|
||||||
|
import PlatformPanel from './components/platform/PlatformPanel'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
PlatformPanel
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('core', { coreVersion: 'version' })
|
...mapGetters('core', { coreVersion: 'version' }),
|
||||||
|
pilotEnabled () {
|
||||||
|
return this.coreVersion.pilotEnabled
|
||||||
|
}
|
||||||
},
|
},
|
||||||
beforeCreate () {
|
beforeCreate () {
|
||||||
// Set vue instance
|
// Set vue instance
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
const APP = {
|
const APP = {
|
||||||
config: {
|
config: {
|
||||||
env: process.env.APP_ENV,
|
env: process.env.APP_ENV,
|
||||||
apiUrl: process.env.APP_API
|
apiUrl: process.env.APP_API,
|
||||||
|
platformUrl: process.env.PLATFORM_URL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<q-tabs>
|
<q-tabs>
|
||||||
<q-btn type="a" href="https://hub.traefik.io/" target="_blank" flat no-caps label="Go to Hub Dashboard →" class="btn-menu btn-hub" />
|
|
||||||
<q-btn @click="$q.dark.toggle()" stretch flat no-caps icon="invert_colors" :label="`${$q.dark.isActive ? 'Light' : 'Dark'} theme`" class="btn-menu" />
|
<q-btn @click="$q.dark.toggle()" stretch flat no-caps icon="invert_colors" :label="`${$q.dark.isActive ? 'Light' : 'Dark'} theme`" class="btn-menu" />
|
||||||
<q-btn stretch flat icon="eva-question-mark-circle-outline">
|
<q-btn stretch flat icon="eva-question-mark-circle-outline">
|
||||||
<q-menu anchor="bottom left" auto-close>
|
<q-menu anchor="bottom left" auto-close>
|
||||||
|
@ -29,6 +28,8 @@
|
||||||
</q-menu>
|
</q-menu>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
|
<platform-auth-state
|
||||||
|
v-if="pilotEnabled" />
|
||||||
</div>
|
</div>
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,10 +45,12 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import config from '../../../package'
|
import config from '../../../package'
|
||||||
|
import PlatformAuthState from '../platform/PlatformAuthState'
|
||||||
import { mapActions, mapGetters } from 'vuex'
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NavBar',
|
name: 'NavBar',
|
||||||
|
components: { PlatformAuthState },
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('core', { coreVersion: 'version' }),
|
...mapGetters('core', { coreVersion: 'version' }),
|
||||||
version () {
|
version () {
|
||||||
|
@ -56,6 +59,9 @@ export default {
|
||||||
? this.coreVersion.Version
|
? this.coreVersion.Version
|
||||||
: this.coreVersion.Version.substring(0, 7)
|
: this.coreVersion.Version.substring(0, 7)
|
||||||
},
|
},
|
||||||
|
pilotEnabled () {
|
||||||
|
return this.coreVersion.pilotEnabled
|
||||||
|
},
|
||||||
parsedVersion () {
|
parsedVersion () {
|
||||||
if (!this.version) {
|
if (!this.version) {
|
||||||
return 'master'
|
return 'master'
|
||||||
|
@ -138,11 +144,6 @@ export default {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-hub {
|
|
||||||
color: #0e204c;
|
|
||||||
background: #deea48;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-item {
|
.q-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
82
webui/src/components/platform/PlatformAuthState.vue
Normal file
82
webui/src/components/platform/PlatformAuthState.vue
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<div class="iframe-wrapper" v-if="isOnline">
|
||||||
|
<iframe
|
||||||
|
id="platform-auth-state"
|
||||||
|
:src="iFrameUrl"
|
||||||
|
v-if="renderIrame"
|
||||||
|
v-resize="resizeOpts"
|
||||||
|
height="64px"
|
||||||
|
frameBorder="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import qs from 'query-string'
|
||||||
|
import '../../_directives/resize'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PlatformPanel',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
renderIrame: true,
|
||||||
|
resizeOpts: {
|
||||||
|
log: false,
|
||||||
|
onMessage: ({ iframe, message }) => {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
// 1st condition for backward compatibility
|
||||||
|
if (message === 'open:profile') {
|
||||||
|
this.openPlatform('/')
|
||||||
|
} else if (message.includes('open:')) {
|
||||||
|
this.openPlatform(message.split('open:')[1])
|
||||||
|
} else if (message === 'logout') {
|
||||||
|
this.closePlatform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.getInstanceInfos()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('platform', { isPlatformOpen: 'isOpen', platformPath: 'path' }),
|
||||||
|
...mapGetters('core', { instanceInfos: 'version' }),
|
||||||
|
isOnline () {
|
||||||
|
return window.navigator.onLine
|
||||||
|
},
|
||||||
|
iFrameUrl () {
|
||||||
|
const instanceInfos = JSON.stringify(this.instanceInfos)
|
||||||
|
const authRedirectUrl = `${window.location.href.split('?')[0]}?platform=${this.platformPath}`
|
||||||
|
|
||||||
|
return qs.stringifyUrl({ url: `${this.platformUrl}/partials/auth-state`, query: { authRedirectUrl, instanceInfos } })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('platform', { openPlatform: 'open' }, { closePlatform: 'close' }),
|
||||||
|
...mapActions('core', { getInstanceInfos: 'getVersion' })
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isPlatformOpen (isOpen, wasOpen) {
|
||||||
|
if (!isOpen && wasOpen) {
|
||||||
|
this.renderIrame = false
|
||||||
|
this.$nextTick().then(() => {
|
||||||
|
this.renderIrame = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../css/sass/variables";
|
||||||
|
|
||||||
|
#platform-auth-state {
|
||||||
|
width: 1px;
|
||||||
|
min-width: 296px;
|
||||||
|
}
|
||||||
|
</style>
|
112
webui/src/components/platform/PlatformPanel.vue
Normal file
112
webui/src/components/platform/PlatformPanel.vue
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<template>
|
||||||
|
<side-panel
|
||||||
|
:isOpen="isPlatformOpen"
|
||||||
|
@onClose="closePlatform()"
|
||||||
|
v-if="isOnline"
|
||||||
|
>
|
||||||
|
<div class="iframe-wrapper">
|
||||||
|
<iframe
|
||||||
|
id="platform-iframe"
|
||||||
|
:src="iFrameUrl"
|
||||||
|
v-resize="resizeOpts"
|
||||||
|
style="position: relative; height: 100%; width: 100%;"
|
||||||
|
frameBorder="0"
|
||||||
|
scrolling="yes"
|
||||||
|
@load="onIFrameLoad"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</side-panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import qs from 'query-string'
|
||||||
|
import SidePanel from '../_commons/SidePanel'
|
||||||
|
import Helps from '../../_helpers/Helps'
|
||||||
|
import '../../_directives/resize'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PlatformPanel',
|
||||||
|
components: {
|
||||||
|
SidePanel
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
resizeOpts: {
|
||||||
|
log: false,
|
||||||
|
resize: false,
|
||||||
|
scrolling: true,
|
||||||
|
onMessage: ({ iframe, message }) => {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
// 1st condition for backward compatibility
|
||||||
|
if (message === 'open:profile') {
|
||||||
|
this.openPlatform('/')
|
||||||
|
} else if (message.includes('open:')) {
|
||||||
|
this.openPlatform(message.split('open:')[1])
|
||||||
|
} else if (message === 'logout') {
|
||||||
|
this.closePlatform()
|
||||||
|
}
|
||||||
|
} else if (message.type) {
|
||||||
|
switch (message.type) {
|
||||||
|
case 'copy-to-clipboard':
|
||||||
|
navigator.clipboard.writeText(message.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (message.isAuthenticated) {
|
||||||
|
this.isAuthenticated = message.isAuthenticated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.getInstanceInfos()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('platform', { isPlatformOpen: 'isOpen', platformPath: 'path' }),
|
||||||
|
...mapGetters('core', { instanceInfos: 'version' }),
|
||||||
|
iFrameUrl () {
|
||||||
|
const instanceInfos = JSON.stringify(this.instanceInfos)
|
||||||
|
const authRedirectUrl = `${window.location.href.split('?')[0]}?platform=${this.platformPath}`
|
||||||
|
|
||||||
|
return qs.stringifyUrl({ url: `${this.platformUrl}${this.platformPath}`, query: { authRedirectUrl, instanceInfos } })
|
||||||
|
},
|
||||||
|
isOnline () {
|
||||||
|
return window.navigator.onLine
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('platform', { openPlatform: 'open', closePlatform: 'close' }),
|
||||||
|
...mapActions('core', { getInstanceInfos: 'getVersion' })
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route (to, from) {
|
||||||
|
const wasOpen = from.query && from.query.platform
|
||||||
|
const isOpen = to.query && to.query.platform
|
||||||
|
|
||||||
|
if (!wasOpen && isOpen) {
|
||||||
|
this.openPlatform(to.query.platform)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isPlatformOpen (newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
document.querySelector('body').style.overflow = newValue ? 'hidden' : 'visible'
|
||||||
|
|
||||||
|
this.$router.push({
|
||||||
|
path: this.$route.path,
|
||||||
|
query: Helps.removeEmptyObjects({
|
||||||
|
...this.$route.query,
|
||||||
|
platform: this.platformPath ? this.platformPath : undefined
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.iframe-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in a new issue