diff --git a/Dockerfile b/Dockerfile index aadbe6e..bd9014c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,7 +45,7 @@ ARG KUBECTL_CHECKSUM_LINUX_AMD64=aaa5ea3b3630730d2b8a8ef3cccb14b47754602c7207c7b ARG KUBECTL_CHECKSUM_WINDOWS_AMD64=ed404eb0c3b74341d2ff799e78f9c0352e2bbd5c1b645652de2725ec77c0a78e # https://github.com/epinio/epinio/releases -ARG EPINIO_VERSION=1.10.0 +ARG EPINIO_VERSION=1.11.0 # /darwin amd64 RUN wget -nv https://get.helm.sh/helm-v${HELM_VERSION}-darwin-amd64.tar.gz && \ @@ -113,7 +113,7 @@ ARG KUBECTL_CHECKSUM_DARWIN_ARM64=4166d293b4f58e5293363f1f91a285d929a54557bf0c1a ARG KUBECTL_CHECKSUM_LINUX_ARM64=741e65b681a22074aaf9459b57dbcef6a9e993472b3019a87f57c191bc68575f # https://github.com/epinio/epinio/releases -ARG EPINIO_VERSION=1.10.0 +ARG EPINIO_VERSION=1.11.0 # /darwin arm64 RUN wget -nv https://get.helm.sh/helm-v${HELM_VERSION}-darwin-arm64.tar.gz && \ diff --git a/ui/src/App.js b/ui/src/App.js index 8bfc39e..e17e9c5 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -93,7 +93,12 @@ function App() { - + @@ -133,7 +138,7 @@ function App() { } onClick={openURL} url="https://epinio.io" /> - } onClick={openURL} url="https://github.com/epinio/epinio/releases/tag/v1.10.0" /> + } onClick={openURL} url="https://github.com/epinio/epinio/releases/tag/v1.11.0" /> diff --git a/ui/src/epinio/API.js b/ui/src/epinio/API.js index 4405d0e..8512d5f 100644 --- a/ui/src/epinio/API.js +++ b/ui/src/epinio/API.js @@ -1,48 +1,55 @@ -import { Buffer } from 'buffer' - export default function EpinioClient({ - apiDomain, - credentials: { - username, - password - } + apiDomain }) { + const login = async (username, password) => { + console.info('EpinioClient.login') + + await epinio([ + 'login', '-u', username, '-p', password, '--trust-ca', `epinio.${apiDomain}` + ]) + } + + const logout = async () => { + console.info('EpinioClient.logout') + + await epinio(['logout']) + } + const info = async () => { console.log('EpinioClient.info') - return doFetch(`http://${apiDomain}/api/v1/info`) + + const result = await epinio([ + 'info', '--output', 'json' + ]) + + return JSON.parse(result) } const listApplications = async (namespace) => { console.log('EpinioClient.listApplications') - return doFetch(`http://${apiDomain}/api/v1/namespaces/${namespace}/applications`) - } - const authHeaders = () => { - const encodedUserPass = Buffer.from(`${username}:${password}`).toString('base64') - const authHeader = `Basic ${encodedUserPass}` - const headers = new Headers() - headers.set('Authorization', authHeader) - return headers - } + const result = await epinio([ + 'app', 'list', '--output', 'json' + ]) - const doFetch = async (url) => { - console.debug('EpinioClient.call', 'executing fetch', url) + return JSON.parse(result) + } + const epinio = async (args) => { try { - const resp = await fetch(url, { headers: authHeaders() }) - console.debug('EpinioClient.call', 'response', resp) - - const json = await resp.json() - console.debug('EpinioClient.call', 'response JSON', json) - - return json + const result = await window.ddClient.extension.host.cli.exec('epinio', args) + return result.stdout } catch (error) { - console.error('EpinioClient.call', error) - return Error(error) + if (error.stderr) { + throw Error(error.stderr) + } + throw error } } return { + login, + logout, info, listApplications } diff --git a/ui/src/epinio/Credentials.js b/ui/src/epinio/Credentials.js index 8e7c345..bb68c52 100644 --- a/ui/src/epinio/Credentials.js +++ b/ui/src/epinio/Credentials.js @@ -1,4 +1,5 @@ import React from 'react' +import EpinioClient from './API' function credsChanged(creds, update) { return creds.username !== update.username || creds.password !== update.password @@ -11,35 +12,36 @@ export function credentialsOK(creds) { // Credentials will fetch the default user, when props.enabled is true function Credentials(props) { React.useEffect(() => { - const getCredentials = async () => { + const epinioClient = EpinioClient({ apiDomain: props.domain }) + + const login = async () => { + let u = { username: '-', password: '-' } + try { - // note: `-l` returns a list, hence the `.items...`, even if only a single secret matches - const result = await window.ddClient.extension.host.cli.exec( - 'kubectl', - ['get', 'secret', '-n', 'epinio', '-l', 'epinio.io/role=admin', '-o', 'jsonpath={.items[0].data}'] - ) - result.parseJsonObject() - // Retrieval above as check that epinio is present. - // Creds hardwired, unchanged from defaults - const u = { username: 'admin', password: 'password' } - if (credsChanged(props.credentials, u)) { - props.onCredentialsChanged(u) - } + await epinioClient.login('admin', 'password') + u = { username: 'admin', password: 'password' } } catch (error) { - // for debugging: - // if (error instanceof Error) { - // console.error(error); - // } else { - // console.log(JSON.stringify(error)); - // } - const u = { username: '-', password: '-' } - if (credsChanged(props.credentials, u)) { - props.onCredentialsChanged(u) - } + console.error(error) + } + + if (credsChanged(props.credentials, u)) { + props.onCredentialsChanged(u) } } + + const logout = async () => { + await epinioClient.logout() + + const u = { username: '-', password: '-' } + if (credsChanged(props.credentials, u)) { + props.onCredentialsChanged(u) + } + } + if (props.enabled) { - getCredentials() + login() + } else { + logout() } }, [props]) diff --git a/ui/src/epinio/Installer.js b/ui/src/epinio/Installer.js index 560f634..db6f96b 100644 --- a/ui/src/epinio/Installer.js +++ b/ui/src/epinio/Installer.js @@ -23,6 +23,17 @@ export default function EpinioInstaller({ return result?.stdout } + const kubectl = async (args) => { + const result = await window.ddClient.extension.host.cli.exec('kubectl', args) + console.debug(JSON.stringify(result)) + + if (result.stderr) { + throw Error(result?.stderr) + } + + return result.parseJsonObject() + } + const isEpinioInstalled = async () => { console.debug('check Epinio installation') @@ -52,10 +63,13 @@ export default function EpinioInstaller({ async function install() { try { setProgress(10) - await installNginx() - setProgress(25) - + const isInstalled = await checkTraefik() + if (!isInstalled) { + await installTraefik() + } setProgress(30) + + setProgress(40) await installCertManager() setProgress(50) @@ -69,8 +83,12 @@ export default function EpinioInstaller({ setInstalled(false) onInstallationChanged(false) + let message = 'Error installing Epinio' + if (error.stderr) { + message = error.stderr + } console.error(error) - const message = `If the nginx service is stuck in pending state, you might need to restart docker desktop. \n ${JSON.stringify(error)}` + onError(message) } finally { setProgress(0) @@ -87,8 +105,8 @@ export default function EpinioInstaller({ await uninstallCertManager() setProgress(50) - setProgress(75) - await uninstallNginx() + setProgress(60) + await uninstallTraefik() setProgress(100) onInstallationChanged(true) @@ -101,18 +119,31 @@ export default function EpinioInstaller({ } } - const installNginx = async () => { - console.log('installing nginx chart') + const checkTraefik = async () => { + console.log('checking traefik installation') + + const result = await kubectl([ + 'get', 'svc', '-A', + '-l', 'app.kubernetes.io/name=traefik', + '-o', 'json' + ]) + + const isInstalled = result.items.length > 0 + console.log(`traefik already installed: ${isInstalled}`) + + return isInstalled + } + + const installTraefik = async () => { + console.log('installing traefik chart') await helm([ - 'upgrade', '--install', '--atomic', 'ingress-nginx', - '--create-namespace', '--namespace', 'ingress-nginx', - 'https://github.com/kubernetes/ingress-nginx/releases/download/helm-chart-4.7.1/ingress-nginx-4.7.1.tgz' + 'upgrade', '--install', '--atomic', 'traefik', + '--create-namespace', '--namespace', 'ingress-traefik', + 'https://traefik.github.io/charts/traefik/traefik-19.0.3.tgz' ]) - // https://github.com/docker/for-mac/issues/4903 - console.log('installed: nginx') - console.log("you might need to restart docker-desktop if localhost:443 doesn't forward to nginx") + console.log('installed: traefik') } const installCertManager = async () => { @@ -137,14 +168,23 @@ export default function EpinioInstaller({ '--create-namespace', '--namespace', 'epinio', '--atomic', '--set', 'global.domain=' + domain, - '--set', 'ingress.ingressClassName=nginx', - '--set', 'ingress.nginxSSLRedirect=false', - 'https://github.com/epinio/helm-charts/releases/download/epinio-1.10.0/epinio-1.10.0.tgz' + 'https://github.com/epinio/helm-charts/releases/download/epinio-1.11.0/epinio-1.11.0.tgz' ]) console.log('installed: epinio') } + const uninstallTraefik = async () => { + console.log('uninstalling traefik chart') + + await helm([ + 'uninstall', '--namespace', 'ingress-traefik', + '--wait', 'traefik' + ]) + + console.log('uninstalled: traefik') + } + const uninstallEpinio = async () => { console.log('uninstalling epinio chart') @@ -167,17 +207,6 @@ export default function EpinioInstaller({ console.log('uninstalled: cert-manager') } - const uninstallNginx = async () => { - console.log('uninstalling nginx chart') - - await helm([ - 'uninstall', '--namespace', 'ingress-nginx', - '--wait', 'ingress-nginx' - ]) - - console.log('uninstalled: nginx') - } - // spawn epinio status check only once useEffect(() => { checkEpinioStatus()