Add Traefik Hub access and remove Pilot access
This commit is contained in:
parent
dad76e0478
commit
0d58e8d1ad
13 changed files with 27 additions and 222 deletions
4
Makefile
4
Makefile
|
@ -36,8 +36,6 @@ DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) $(if $(DOCKER_NON_INT
|
||||||
|
|
||||||
IN_DOCKER ?= true
|
IN_DOCKER ?= true
|
||||||
|
|
||||||
PLATFORM_URL := $(if $(PLATFORM_URL),$(PLATFORM_URL),"https://pilot.traefik.io")
|
|
||||||
|
|
||||||
default: binary
|
default: binary
|
||||||
|
|
||||||
## Build Dev Docker image
|
## Build Dev Docker image
|
||||||
|
@ -54,7 +52,7 @@ dist:
|
||||||
|
|
||||||
## Build WebUI Docker image
|
## Build WebUI Docker image
|
||||||
build-webui-image:
|
build-webui-image:
|
||||||
docker build -t traefik-webui --build-arg ARG_PLATFORM_URL=$(PLATFORM_URL) -f webui/Dockerfile webui
|
docker build -t traefik-webui -f webui/Dockerfile webui
|
||||||
|
|
||||||
## Clean WebUI static generated assets
|
## Clean WebUI static generated assets
|
||||||
clean-webui:
|
clean-webui:
|
||||||
|
|
|
@ -215,6 +215,8 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -452,3 +452,10 @@ 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 our Blog for migration instructions later this year.
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
# 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:
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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"`
|
||||||
|
|
|
@ -76,6 +76,7 @@ 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"`
|
||||||
|
|
||||||
Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
|
Experimental *Experimental `description:"experimental features." json:"experimental,omitempty" toml:"experimental,omitempty" yaml:"experimental,omitempty" export:"true"`
|
||||||
|
|
|
@ -2,8 +2,6 @@ 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,13 +118,11 @@ 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,26 +1,17 @@
|
||||||
<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,8 +1,7 @@
|
||||||
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,6 +15,7 @@
|
||||||
</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>
|
||||||
|
@ -28,8 +29,6 @@
|
||||||
</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>
|
||||||
|
@ -45,12 +44,10 @@
|
||||||
|
|
||||||
<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 () {
|
||||||
|
@ -59,9 +56,6 @@ 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'
|
||||||
|
@ -144,6 +138,11 @@ export default {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-hub {
|
||||||
|
color: #0e204c;
|
||||||
|
background: #deea48;
|
||||||
|
}
|
||||||
|
|
||||||
.q-item {
|
.q-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
<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>
|
|
|
@ -1,112 +0,0 @@
|
||||||
<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