Merge pull request #747 from davidcassany/integration_and_packaging

Linux: Integration and packaging
This commit is contained in:
Matt Farina
2021-10-08 22:22:23 -04:00
committed by GitHub
22 changed files with 96 additions and 65 deletions

View File

@@ -87,8 +87,8 @@ jobs:
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
if: startsWith(matrix.os, 'ubuntu-') if: startsWith(matrix.os, 'ubuntu-')
with: with:
name: Rancher Desktop-linux.zip name: Rancher Desktop-linux.tar.gz
path: dist/rancher-desktop*.zip path: dist/rancher-desktop*.tar.gz
if-no-files-found: error if-no-files-found: error
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
if: startsWith(matrix.os, 'ubuntu-') if: startsWith(matrix.os, 'ubuntu-')
@@ -96,3 +96,15 @@ jobs:
name: Rancher Desktop.flatpak name: Rancher Desktop.flatpak
path: dist/Rancher Desktop*.flatpak path: dist/Rancher Desktop*.flatpak
if-no-files-found: error if-no-files-found: error
- uses: actions/upload-artifact@v2
if: startsWith(matrix.os, 'ubuntu-')
with:
name: Rancher Desktop.rpm
path: dist/rancher-desktop*.rpm
if-no-files-found: error
- uses: actions/upload-artifact@v2
if: startsWith(matrix.os, 'ubuntu-')
with:
name: Rancher Desktop.deb
path: dist/rancher-desktop*.deb
if-no-files-found: error

View File

@@ -124,7 +124,7 @@ async function doFirstRun() {
return; return;
} }
await window.openFirstRun(); await window.openFirstRun();
if (os.platform() === 'darwin') { if (os.platform() === 'darwin' || os.platform() === 'linux') {
await Promise.all([ await Promise.all([
linkResource('helm', true), linkResource('helm', true),
linkResource('kim', true), // TODO: Remove when we stop shipping kim linkResource('kim', true), // TODO: Remove when we stop shipping kim
@@ -509,10 +509,20 @@ async function getVersion() {
* @param state -- true to symlink, false to delete * @param state -- true to symlink, false to delete
*/ */
async function linkResource(name: string, state: boolean): Promise<Error | null> { async function linkResource(name: string, state: boolean): Promise<Error | null> {
const linkPath = path.join('/usr/local/bin', name); const linkPath = path.join(paths.integration, name);
let err: Error | null = await new Promise((resolve) => {
fs.mkdir(paths.integration, { recursive: true }, resolve);
});
if (err) {
console.error(`Error creating the directory ${ paths.integration }: ${ err.message }`);
return err;
}
if (state) { if (state) {
const err: Error | null = await new Promise((resolve) => { err = await new Promise((resolve) => {
fs.symlink(resources.executable(name), linkPath, 'file', resolve); fs.symlink(resources.executable(name), linkPath, 'file', resolve);
}); });
@@ -522,7 +532,7 @@ async function linkResource(name: string, state: boolean): Promise<Error | null>
return err; return err;
} }
} else { } else {
const err: Error | null = await new Promise((resolve) => { err = await new Promise((resolve) => {
fs.unlink(linkPath, resolve); fs.unlink(linkPath, resolve);
}); });

View File

@@ -29,7 +29,10 @@ win:
linux: linux:
category: Utility category: Utility
executableName: rancher-desktop executableName: rancher-desktop
target: [ flatpak, zip ] icon: ./resources/icons/linux
synopsis: Kubernetes and container management on the desktop
description: Rancher Desktop is an open-source project to bring Kubernetes and container management to the desktop
target: [ flatpak, tar.gz, rpm, deb ]
nsis: nsis:
license: LICENSE license: LICENSE
include: build/installer.nsh include: build/installer.nsh
@@ -53,6 +56,7 @@ flatpak:
- --filesystem=xdg-data/rancher-desktop:create - --filesystem=xdg-data/rancher-desktop:create
- --filesystem=~/.kube:create - --filesystem=~/.kube:create
- --filesystem=~/.kuberlr:create - --filesystem=~/.kuberlr:create
- --filesystem=~/.local/bin:create
- --device=kvm - --device=kvm
- --device=dri - --device=dri
- --share=ipc - --share=ipc
@@ -63,30 +67,24 @@ flatpak:
- --own-name=org.kde.* # Fixes Tray in KDE (https://github.com/flathub/im.riot.Riot/issues/100) - --own-name=org.kde.* # Fixes Tray in KDE (https://github.com/flathub/im.riot.Riot/issues/100)
files: files:
- ["dist/linux-unpacked/resources/resources/linux/misc/io.rancherdesktop.app.appdata.xml", "/share/metainfo/io.rancherdesktop.app.appdata.xml"] - ["dist/linux-unpacked/resources/resources/linux/misc/io.rancherdesktop.app.appdata.xml", "/share/metainfo/io.rancherdesktop.app.appdata.xml"]
- ["dist/linux-unpacked/resources/resources/linux/misc/io.rancherdesktop.app.desktop", "/share/applications/io.rancherdesktop.app.desktop"]
- ["dist/linux-unpacked/resources/resources/icons/linux", "/share/icons/hicolor"]
modules: modules:
- name: qemu - name: qemu
config-opts: config-opts:
- "--disable-user" - "--disable-user"
- "--enable-kvm" - "--enable-kvm"
#- "--enable-vde"
- "--target-list=x86_64-softmmu" - "--target-list=x86_64-softmmu"
sources: sources:
- type: archive - type: archive
url: https://download.qemu.org/qemu-6.1.0.tar.xz url: https://download.qemu.org/qemu-6.1.0.tar.xz
sha256: eebc089db3414bbeedf1e464beda0a7515aad30f73261abc246c9b27503a3c96 sha256: eebc089db3414bbeedf1e464beda0a7515aad30f73261abc246c9b27503a3c96
# We do not need vde under linux rpm:
#modules: depends:
#- name: vde-2 - qemu
# sources: fpm:
# - type: git # Make sure not /usr/lib/.build-id artifacts are created
# url: https://github.com/virtualsquare/vde-2 # This config is likely to be missing in non RPM based hosts
# tag: vde-2 - --rpm-rpmbuild-define=_build_id_links none
# buildsystem: simple deb:
# build-commands: depends:
# - | - qemu-utils
# cd 2.3.2 - qemu-system-x86
# autoreconf --install
# ./configure --prefix=/app --disable-python --disable-cryptcab
# make install

View File

@@ -22,6 +22,7 @@ finish-args:
- --filesystem=xdg-data/rancher-desktop:create - --filesystem=xdg-data/rancher-desktop:create
- --filesystem=~/.kube:create - --filesystem=~/.kube:create
- --filesystem=~/.kuberlr:create - --filesystem=~/.kuberlr:create
- --filesystem=~/.local/bin:create
- --talk-name=org.freedesktop.Notifications - --talk-name=org.freedesktop.Notifications
- --own-name=org.kde.* - --own-name=org.kde.*
modules: modules:
@@ -32,26 +33,32 @@ modules:
- type: dir - type: dir
path: .. path: ..
dest: lib dest: lib
- type: file
path: io.rancherdesktop.app.desktop
dest: lib
- type: script - type: script
dest-filename: electron-wrapper dest-filename: electron-wrapper
commands: commands:
- | - |
export TMPDIR="$XDG_RUNTIME_DIR/app/$FLATPAK_ID" export TMPDIR="$XDG_RUNTIME_DIR/app/$FLATPAK_ID"
if [ "${XDG_SESSION_TYPE}" == "wayland" ]; then zypak-wrapper /app/lib/io.rancherdesktop.app/rancher-desktop "$@"
zypak-wrapper /app/lib/io.rancherdesktop.app/rancher-desktop --enable-features=UseOzonePlatform --ozone-platform=wayland "$@"
else
zypak-wrapper /app/lib/io.rancherdesktop.app/rancher-desktop "$@"
fi
build-commands: build-commands:
# Bundle electron build after npm run build -- --linux --publish=never # Bundle electron build after npm run build -- --linux --publish=never
- cp -a dist/linux*unpacked /app/lib/io.rancherdesktop.app - cp -a dist/linux*unpacked /app/lib/io.rancherdesktop.app
# Include FreeDesktop integration files at expected locations # Include FreeDesktop integration files at expected locations
- rm -rf /app/share/metainfo /app/share/icons /app/share/applications - rm -rf /app/share/metainfo /app/share/icons /app/share/applications
- mkdir -p /app/share/metainfo /app/share/icons /app/share/applications - mkdir -p /app/share/metainfo /app/share/applications
- |
icons=/app/lib/io.rancherdesktop.app/resources/resources/icons/linux
for img in $(ls "${icons}"); do
size="${img//rancher-desktop./}"
size="${size%%.png}"
mkdir "/app/share/icons/hicolor/${size}/apps" -p
cp "${icons}/${img}" "/app/share/icons/hicolor/${size}/apps/io.rancherdesktop.app.png"
done
- cp /app/lib/io.rancherdesktop.app/resources/resources/linux/misc/io.rancherdesktop.app.appdata.xml /app/share/metainfo - cp /app/lib/io.rancherdesktop.app/resources/resources/linux/misc/io.rancherdesktop.app.appdata.xml /app/share/metainfo
- cp /app/lib/io.rancherdesktop.app/resources/resources/linux/misc/io.rancherdesktop.app.desktop /app/share/applications - mv io.rancherdesktop.app.desktop /app/share/applications
- cp -r /app/lib/io.rancherdesktop.app/resources/resources/icons/linux /app/share/icons/hicolor
# Install app wrapper # Install app wrapper
- install -Dm755 -t /app/bin/ ../electron-wrapper - install -Dm755 -t /app/bin/ ../electron-wrapper
modules: modules:
@@ -59,22 +66,8 @@ modules:
config-opts: config-opts:
- "--disable-user" - "--disable-user"
- "--enable-kvm" - "--enable-kvm"
#- "--enable-vde"
- "--target-list=x86_64-softmmu" - "--target-list=x86_64-softmmu"
sources: sources:
- type: archive - type: archive
url: https://download.qemu.org/qemu-6.1.0.tar.xz url: https://download.qemu.org/qemu-6.1.0.tar.xz
sha256: eebc089db3414bbeedf1e464beda0a7515aad30f73261abc246c9b27503a3c96 sha256: eebc089db3414bbeedf1e464beda0a7515aad30f73261abc246c9b27503a3c96
#modules:
#- name: vde-2
# sources:
# - type: git
# url: https://github.com/virtualsquare/vde-2
# tag: vde-2
# buildsystem: simple
# build-commands:
# - |
# cd 2.3.2
# autoreconf --install
# ./configure --prefix=/app --disable-python --disable-cryptcab
# make install

View File

@@ -2,6 +2,10 @@
"name": "rancher-desktop", "name": "rancher-desktop",
"license": "Apache-2.0", "license": "Apache-2.0",
"version": "0.6.0", "version": "0.6.0",
"author": {
"name": "SUSE",
"email": "containers@suse.com"
},
"engines": { "engines": {
"node": ">=14.14" "node": ">=14.14"
}, },

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -4515,7 +4515,7 @@ troubleshooting:
integrations: integrations:
darwin: darwin:
title: Supporting Utilities title: Supporting Utilities
description: Create symbolic links to tools in /usr/local/bin description: Create symbolic links to tools in
windows: windows:
title: WSL Integration title: WSL Integration
description: "Expose Rancher Desktop's Kubernetes configuration to Windows Subsystem for Linux (WSL) distros" description: "Expose Rancher Desktop's Kubernetes configuration to Windows Subsystem for Linux (WSL) distros"

View File

@@ -26,6 +26,7 @@ import Component from 'vue-class-component';
import Banner from '@/components/Banner.vue'; import Banner from '@/components/Banner.vue';
import Card from '@/components/Card.vue'; import Card from '@/components/Card.vue';
import Checkbox from '@/components/form/Checkbox.vue'; import Checkbox from '@/components/form/Checkbox.vue';
import paths from '@/utils/paths';
const IntegrationProps = Vue.extend({ const IntegrationProps = Vue.extend({
props: { props: {
@@ -59,7 +60,7 @@ class Integration extends IntegrationProps {
* asynchronously, to prevent the user from retrying to toggle too quickly. * asynchronously, to prevent the user from retrying to toggle too quickly.
*/ */
protected busy: Record<string, boolean> = {}; protected busy: Record<string, boolean> = {};
protected GlobalFailureIntegrationName = '/usr/local/bin'; protected GlobalFailureIntegrationName = paths.integration;
get globalError() { get globalError() {
return this.integrations[this.GlobalFailureIntegrationName]; return this.integrations[this.GlobalFailureIntegrationName];

View File

@@ -2,6 +2,7 @@ import path from 'path';
import fs from 'fs'; import fs from 'fs';
import Logging from '@/utils/logging'; import Logging from '@/utils/logging';
import paths from '@/utils/paths';
import resources from '@/resources'; import resources from '@/resources';
import PathConflictManager from '@/main/pathConflictManager'; import PathConflictManager from '@/main/pathConflictManager';
import * as window from '@/window'; import * as window from '@/window';
@@ -9,7 +10,7 @@ import * as window from '@/window';
// TODO: Remove 'kim' when we stop shipping kim // TODO: Remove 'kim' when we stop shipping kim
const INTEGRATIONS = ['helm', 'kim', 'kubectl', 'nerdctl']; const INTEGRATIONS = ['helm', 'kim', 'kubectl', 'nerdctl'];
const console = Logging.background; const console = Logging.background;
const PUBLIC_LINK_DIR = '/usr/local/bin'; const PUBLIC_LINK_DIR = paths.integration;
/* /*
* There are probably going to be only two kinds of integrations: WSL for Windows, * There are probably going to be only two kinds of integrations: WSL for Windows,

View File

@@ -41,12 +41,7 @@ export default {
}, },
data() { data() {
// Linux integration are not yet available return { routes: ['/General', '/K8s', '/Integrations', '/Images', '/Troubleshooting'] };
if (os.platform() === 'linux') {
return { routes: ['/General', '/K8s', '/Images', '/Troubleshooting'] };
} else {
return { routes: ['/General', '/K8s', '/Integrations', '/Images', '/Troubleshooting'] };
}
}, },
head() { head() {
@@ -68,12 +63,7 @@ export default {
mounted() { mounted() {
ipcRenderer.invoke('k8s-supports-port-forwarding').then((supported) => { ipcRenderer.invoke('k8s-supports-port-forwarding').then((supported) => {
if (supported) { if (supported) {
// Linux integrations are not yet available this.$data.routes = ['/General', '/K8s', '/Integrations', '/PortForwarding', '/Images', '/Troubleshooting'];
if (os.platform() === 'linux') {
this.$data.routes = ['/General', '/K8s', '/PortForwarding', '/Images', '/Troubleshooting'];
} else {
this.$data.routes = ['/General', '/K8s', '/Integrations', '/PortForwarding', '/Images', '/Troubleshooting'];
}
} }
}); });
}, },

View File

@@ -5,6 +5,7 @@ import timers from 'timers';
import * as window from '@/window'; import * as window from '@/window';
import pathConflict from '@/utils/pathConflict'; import pathConflict from '@/utils/pathConflict';
import Logging from '@/utils/logging'; import Logging from '@/utils/logging';
import paths from '@/utils/paths';
const console = Logging.background; const console = Logging.background;
const DebounceInterval = 500; // msec const DebounceInterval = 500; // msec
@@ -40,7 +41,7 @@ export default class PathConflictManager {
let results: Array<string> = []; let results: Array<string> = [];
try { try {
results = this.pathConflicts[binaryName] = await pathConflict('/usr/local/bin', binaryName); results = this.pathConflicts[binaryName] = await pathConflict(paths.integration, binaryName);
} catch (err) { } catch (err) {
console.log(`Error gathering conflicts for file ${ binaryName }`, err); console.log(`Error gathering conflicts for file ${ binaryName }`, err);
// And leave results as an empty array, to clear the current warnings // And leave results as an empty array, to clear the current warnings
@@ -60,7 +61,7 @@ export default class PathConflictManager {
return; return;
} }
const currentPathDirectories = currentPathAsString.split(path.delimiter) const currentPathDirectories = currentPathAsString.split(path.delimiter)
.filter(dir => path.resolve(dir) !== '/usr/local/bin'); .filter(dir => path.resolve(dir) !== paths.integration);
const namesOfInterest = ['helm', 'kim', 'kubectl', 'nerdctl']; const namesOfInterest = ['helm', 'kim', 'kubectl', 'nerdctl'];
for (const dirName of currentPathDirectories) { for (const dirName of currentPathDirectories) {

View File

@@ -25,6 +25,7 @@ class DarwinObsoletePaths implements Paths {
cache = path.join(os.homedir(), 'Library', 'Caches', APP_NAME); cache = path.join(os.homedir(), 'Library', 'Caches', APP_NAME);
lima = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'lima'); lima = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'lima');
hyperkit = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'driver'); hyperkit = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'driver');
integration = '/usr/local/bin';
get wslDistro(): string { get wslDistro(): string {
throw new Error('wslDistro not available for darwin'); throw new Error('wslDistro not available for darwin');
} }
@@ -67,6 +68,10 @@ class Win32ObsoletePaths implements Paths {
get hyperkit(): string { get hyperkit(): string {
throw new Error('hyperkit not available for win32'); throw new Error('hyperkit not available for win32');
} }
get integration(): string {
throw new Error('integration path not available for win32');
}
} }
/** /**
* Remove the given directory if it is empty, and also any parent directories * Remove the given directory if it is empty, and also any parent directories

View File

@@ -7,6 +7,7 @@ import os from 'os';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import Vue from 'vue'; import Vue from 'vue';
import Integration from '@/components/Integration.vue'; import Integration from '@/components/Integration.vue';
import paths from '@/utils/paths';
declare module 'vue/types/vue' { declare module 'vue/types/vue' {
interface t { interface t {
@@ -30,7 +31,7 @@ export default Vue.extend({
}, },
computed: { computed: {
hasIntegration() { hasIntegration() {
return /^win|^darwin$/.test(os.platform()); return /^win|^darwin|^linux$/.test(os.platform());
}, },
integrationTitle(): string { integrationTitle(): string {
if (os.platform() !== 'win32') { if (os.platform() !== 'win32') {
@@ -41,7 +42,7 @@ export default Vue.extend({
}, },
integrationDescription(): string { integrationDescription(): string {
if (os.platform() !== 'win32') { if (os.platform() !== 'win32') {
return this.t('integrations.darwin.description'); return `${ this.t('integrations.darwin.description') } ${ paths.integration }`;
} }
return this.t('integrations.windows.description', { }, true); return this.t('integrations.windows.description', { }, true);

View File

@@ -37,6 +37,10 @@ describe('paths', () => {
win32: Error(), win32: Error(),
darwin: '%HOME%/Library/State/rancher-desktop/driver/', darwin: '%HOME%/Library/State/rancher-desktop/driver/',
}, },
integration: {
win32: Error(),
darwin: '/usr/local/bin',
},
}; };
const table = Object.entries(cases).flatMap( const table = Object.entries(cases).flatMap(

View File

@@ -20,6 +20,8 @@ export interface Paths {
wslDistroData: string; wslDistroData: string;
/** Directory holding Lima state (macOS-specific). */ /** Directory holding Lima state (macOS-specific). */
lima: string; lima: string;
/** Directory holding provided binary resources */
integration: string;
/** @deprecated Directory holding hyperkit state (macOS-specific) */ /** @deprecated Directory holding hyperkit state (macOS-specific) */
hyperkit: string; hyperkit: string;
} }
@@ -33,6 +35,7 @@ export class DarwinPaths implements Paths {
cache = path.join(os.homedir(), 'Library', 'Caches', APP_NAME); cache = path.join(os.homedir(), 'Library', 'Caches', APP_NAME);
lima = path.join(os.homedir(), 'Library', 'Application Support', APP_NAME, 'lima'); lima = path.join(os.homedir(), 'Library', 'Application Support', APP_NAME, 'lima');
hyperkit = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'driver'); hyperkit = path.join(os.homedir(), 'Library', 'State', APP_NAME, 'driver');
integration = '/usr/local/bin';
get wslDistro(): string { get wslDistro(): string {
throw new Error('wslDistro not available for darwin'); throw new Error('wslDistro not available for darwin');
} }
@@ -75,6 +78,10 @@ export class Win32Paths implements Paths {
get hyperkit(): string { get hyperkit(): string {
throw new Error('hyperkit not available for Windows'); throw new Error('hyperkit not available for Windows');
} }
get integration(): string {
throw new Error('integration path not available for Windows');
}
} }
/** /**
@@ -108,6 +115,10 @@ export class LinuxPaths implements Paths {
return path.join(this.dataHome, APP_NAME, 'lima'); return path.join(this.dataHome, APP_NAME, 'lima');
} }
get integration(): string {
return path.join(os.homedir(), '.local', 'bin');
}
get hyperkit(): string { get hyperkit(): string {
throw new Error('hyperkit not available for Linux'); throw new Error('hyperkit not available for Linux');
} }