Add Traefik Hub button and deprecate Pilot

Co-authored-by: Tom Moulard <tom.moulard@traefik.io>
This commit is contained in:
Ludovic Fernandez 2022-06-13 11:04:08 +02:00 committed by GitHub
parent aa0b5466a9
commit 91f4ccf087
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 21 additions and 250 deletions

View file

@ -216,7 +216,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
}
if staticConfiguration.Pilot != nil {
version.PilotEnabled = staticConfiguration.Pilot.Dashboard
log.WithoutContext().Warn("Traefik Pilot is deprecated and will be removed soon. Please check our Blog for migration instructions later this year.")
}
// Plugins

View file

@ -468,3 +468,8 @@ This option available in the ForwardAuth middleware, as well as in the HTTP, Con
### Consul Enterprise Namespaces
In `v2.8`, the `namespace` option of Consul and Consul Catalog providers is deprecated, please use the `namespaces` options instead.
### Traefik Pilot
In `v2.8`, the `pilot.token` and `pilot.dashboard` options are deprecated.
Please check our Blog for migration instructions later this year.

View file

@ -1,6 +1,7 @@
package static
// Pilot Configuration related to Traefik Pilot.
// Deprecated.
type Pilot struct {
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"`

View file

@ -78,6 +78,7 @@ type Configuration struct {
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"`
Hub *hub.Provider `description:"Traefik Hub configuration." json:"hub,omitempty" toml:"hub,omitempty" yaml:"hub,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`

View file

@ -194,8 +194,6 @@ func (c *client) SendInstanceInfo(ctx context.Context, pilotMetrics []metrics.Pi
if err != nil {
return fmt.Errorf("failed to create UUID: %w", err)
}
version.UUID = c.uuid
}
info := instanceInfo{

View file

@ -23,9 +23,6 @@ var (
// StartDate holds the start date of traefik.
StartDate = time.Now()
// UUID instance uuid.
UUID string
// PilotEnabled activate integration of pilot into the dashboard.
PilotEnabled bool
)
// Handler expose version routes.
@ -46,11 +43,9 @@ func (v Handler) Append(router *mux.Router) {
UUID string `json:"uuid,omitempty"`
PilotEnabled bool `json:"pilotEnabled"`
}{
Version: Version,
Codename: Codename,
StartDate: StartDate,
UUID: UUID,
PilotEnabled: PilotEnabled,
Version: Version,
Codename: Codename,
StartDate: StartDate,
}
if err := templatesRenderer.JSON(response, http.StatusOK, v); err != nil {

View file

@ -2,8 +2,6 @@ FROM node:14.16
# Current Active LTS release according to (https://nodejs.org/en/about/releases/)
ENV WEBUI_DIR /src/webui
ARG ARG_PLATFORM_URL=https://pilot.traefik.io
ENV PLATFORM_URL=${ARG_PLATFORM_URL}
RUN mkdir -p $WEBUI_DIR
COPY package.json $WEBUI_DIR/

View file

@ -118,13 +118,11 @@ module.exports = function (ctx) {
env: process.env.APP_ENV === 'development'
? { // staging:
APP_ENV: JSON.stringify(process.env.APP_ENV),
APP_API: JSON.stringify(process.env.APP_API || '/api'),
PLATFORM_URL: JSON.stringify(process.env.PLATFORM_URL || 'https://pilot.traefik.io')
APP_API: JSON.stringify(process.env.APP_API || '/api')
}
: { // production:
APP_ENV: JSON.stringify(process.env.APP_ENV),
APP_API: JSON.stringify(process.env.APP_API || '/api'),
PLATFORM_URL: JSON.stringify(process.env.PLATFORM_URL || 'https://pilot.traefik.io')
APP_API: JSON.stringify(process.env.APP_API || '/api')
},
uglifyOptions: {
compress: {

View file

@ -1,26 +1,17 @@
<template>
<div id="q-app">
<router-view />
<platform-panel
v-if="pilotEnabled" />
</div>
</template>
<script>
import { APP } from './_helpers/APP'
import PlatformPanel from './components/platform/PlatformPanel'
import { mapGetters } from 'vuex'
export default {
name: 'App',
components: {
PlatformPanel
},
computed: {
...mapGetters('core', { coreVersion: 'version' }),
pilotEnabled () {
return this.coreVersion.pilotEnabled
}
...mapGetters('core', { coreVersion: 'version' })
},
beforeCreate () {
// Set vue instance

View file

@ -1,8 +1,7 @@
const APP = {
config: {
env: process.env.APP_ENV,
apiUrl: process.env.APP_API,
platformUrl: process.env.PLATFORM_URL
apiUrl: process.env.APP_API
}
}

View file

@ -30,6 +30,7 @@
</q-tabs>
<div class="right-menu">
<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 stretch flat icon="eva-question-mark-circle-outline">
<q-menu anchor="bottom left" auto-close>
@ -43,8 +44,6 @@
</q-menu>
</q-btn>
</q-tabs>
<platform-auth-state
v-if="pilotEnabled" />
</div>
</q-toolbar>
</div>
@ -60,12 +59,10 @@
<script>
import config from '../../../package'
import PlatformAuthState from '../platform/PlatformAuthState'
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'NavBar',
components: { PlatformAuthState },
computed: {
...mapGetters('core', { coreVersion: 'version' }),
version () {
@ -74,9 +71,6 @@ export default {
? this.coreVersion.Version
: this.coreVersion.Version.substring(0, 7)
},
pilotEnabled () {
return this.coreVersion.pilotEnabled
},
parsedVersion () {
if (!this.version) {
return 'master'
@ -159,6 +153,11 @@ export default {
font-weight: 600;
}
.btn-hub {
color: #0e204c;
background: #deea48;
}
.q-item {
padding: 0;
}

View file

@ -1,20 +0,0 @@
<template>
<q-btn color="accent" class="btn" @click="$emit('click', $event)" :bind="$attrs">{{label}}</q-btn>
</template>
<script>
export default {
name: 'ConnectButton',
props: ['label']
}
</script>
<style>
.btn {
font-family: 'Nunito', 'Roboto', sans-serif;
font-weight: bold;
font-size: 14px;
text-transform: inherit;
}
</style>

View file

@ -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>

View file

@ -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>