diff --git a/CHANGELOG.md b/CHANGELOG.md index d12b23d5..da3486d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2.5.0 - 2024-04-xx] + +### Added + +- Different compute device configuration for Daemon (NVIDIA, AMD, CPU) + ## [2.4.0 - 2024-04-04] ### Added diff --git a/appinfo/info.xml b/appinfo/info.xml index 6fd8ea55..87583065 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -43,7 +43,7 @@ to join us in shaping a more versatile, stable, and secure app landscape. *Your insights, suggestions, and contributions are invaluable to us.* ]]> - 2.4.0 + 2.5.0 agpl Andrey Borysenko Alexander Piskun @@ -72,6 +72,7 @@ to join us in shaping a more versatile, stable, and secure app landscape. OCA\AppAPI\Migration\DataInitializationStep OCA\AppAPI\Migration\DaemonUpdateV2RepairStep + OCA\AppAPI\Migration\DaemonUpdateGPUSRepairStep diff --git a/docs/CreationOfDeployDaemon.rst b/docs/CreationOfDeployDaemon.rst index a211d411..14540086 100644 --- a/docs/CreationOfDeployDaemon.rst +++ b/docs/CreationOfDeployDaemon.rst @@ -32,7 +32,7 @@ Register Register Deploy Daemon (DaemonConfig). -Command: ``app_api:daemon:register [--net NET] [--gpu] [--] `` +Command: ``app_api:daemon:register [--net NET] [--haproxy_password HAPROXY_PASSWORD] [--compute_device COMPUTE_DEVICE] [--set-default] [--] `` Arguments ********* @@ -49,7 +49,7 @@ Options * ``--net [network-name]`` - ``[required]`` network name to bind docker container to (default: ``host``) * ``--haproxy_password HAPROXY_PASSWORD`` - ``[optional]`` password for AppAPI Docker Socket Proxy - * ``--gpu GPU`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``/dev/dri``) + * ``--compute_device GPU`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``cpu|cuda|rocm``, default: ``cpu``) * ``--set-default`` - ``[optional]`` set created daemon as default for ExApps installation DeployConfig @@ -64,7 +64,10 @@ ExApp container. "net": "host", "nextcloud_url": "https://nextcloud.local", "haproxy_password": "some_secure_password", - "gpus": true, + "computeDevice": { + "id": "cuda", + "name": "CUDA (NVIDIA)", + }, } DeployConfig options @@ -73,7 +76,7 @@ DeployConfig options * ``net`` **[required]** - network name to bind docker container to (default: ``host``) * ``nextcloud_url`` **[required]** - Nextcloud URL (e.g. ``https://nextcloud.local``) * ``haproxy_password`` *[optional]* - password for AppAPI Docker Socket Proxy - * ``gpus`` *[optional]* - GPU device to attach to the daemon (e.g. ``/dev/dri``) + * ``computeDevice`` *[optional]* - Compute device to attach to the daemon (e.g. ``{ "id": "cuda", "label": "CUDA (NVIDIA)" }``) Unregister ---------- diff --git a/lib/Command/Daemon/RegisterDaemon.php b/lib/Command/Daemon/RegisterDaemon.php index 079227e6..42c69583 100644 --- a/lib/Command/Daemon/RegisterDaemon.php +++ b/lib/Command/Daemon/RegisterDaemon.php @@ -38,11 +38,12 @@ protected function configure(): void { $this->addOption('net', null, InputOption::VALUE_REQUIRED, 'DeployConfig, the name of the docker network to attach App to'); $this->addOption('haproxy_password', null, InputOption::VALUE_REQUIRED, 'AppAPI Docker Socket Proxy password for HAProxy Basic auth'); - $this->addOption('gpu', null, InputOption::VALUE_NONE, 'Enable support of GPUs for containers'); + $this->addOption('compute_device', null, InputOption::VALUE_REQUIRED, 'Compute device for GPU support (cpu|cuda|rocm)'); $this->addOption('set-default', null, InputOption::VALUE_NONE, 'Set DaemonConfig as default'); $this->addUsage('local_docker "Docker local" "docker-install" "http" "/var/run/docker.sock" "http://nextcloud.local" --net=nextcloud'); + $this->addUsage('local_docker "Docker local" "docker-install" "http" "/var/run/docker.sock" "http://nextcloud.local" --net=nextcloud --set-default --compute_device=cuda'); } protected function execute(InputInterface $input, OutputInterface $output): int { @@ -57,7 +58,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'net' => $input->getOption('net') ?? 'host', 'nextcloud_url' => $nextcloudUrl, 'haproxy_password' => $input->getOption('haproxy_password') ?? '', - 'gpu' => $input->getOption('gpu') ?? false, + 'computeDevice' => $this->buildComputeDevice($input->getOption('compute_device') ?? 'cpu'), ]; if (($protocol !== 'http') && ($protocol !== 'https')) { @@ -95,4 +96,26 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('Daemon successfully registered.'); return 0; } + + private function buildComputeDevice(string $computeDevice): array { + switch ($computeDevice) { + case 'cpu': + return [ + 'id' => 'cpu', + 'label' => 'CPU', + ]; + case 'cuda': + return [ + 'id' => 'cuda', + 'label' => 'CUDA (NVIDIA)', + ]; + case 'rocm': + return [ + 'id' => 'rocm', + 'label' => 'ROCm (AMD)', + ]; + default: + throw new \InvalidArgumentException('Invalid compute device value.'); + } + } } diff --git a/lib/DeployActions/AIODockerActions.php b/lib/DeployActions/AIODockerActions.php index 3cc6c0e0..47e18f4b 100644 --- a/lib/DeployActions/AIODockerActions.php +++ b/lib/DeployActions/AIODockerActions.php @@ -14,7 +14,6 @@ */ class AIODockerActions { public const AIO_DAEMON_CONFIG_NAME = 'docker_aio'; - public const AIO_DAEMON_CONFIG_NAME_GPU = 'docker_aio_gpu'; public const AIO_DOCKER_SOCKET_PROXY_HOST = 'nextcloud-aio-docker-socket-proxy:2375'; public function __construct( @@ -46,13 +45,12 @@ public function registerAIODaemonConfig(): ?DaemonConfig { 'net' => 'nextcloud-aio', // using the same host as default network for Nextcloud AIO containers 'nextcloud_url' => 'https://' . getenv('NC_DOMAIN'), 'haproxy_password' => null, - 'gpu' => false, + 'computeDevice' => [ + 'id' => 'cpu', + 'label' => 'CPU', + ], ]; - if ($this->isGPUsEnabled()) { - $this->registerAIODaemonConfigWithGPU(); - } - $daemonConfigParams = [ 'name' => self::AIO_DAEMON_CONFIG_NAME, 'display_name' => 'AIO Docker Socket Proxy', @@ -68,44 +66,4 @@ public function registerAIODaemonConfig(): ?DaemonConfig { } return $daemonConfig; } - - /** - * Registers DaemonConfig with default params to use AIO Docker Socket Proxy with GPU - */ - private function registerAIODaemonConfigWithGPU(): ?DaemonConfig { - $daemonConfigWithGPU = $this->daemonConfigService->getDaemonConfigByName(self::AIO_DAEMON_CONFIG_NAME_GPU); - if ($daemonConfigWithGPU !== null) { - return $daemonConfigWithGPU; - } - - $deployConfig = [ - 'net' => 'nextcloud-aio', // using the same host as default network for Nextcloud AIO containers - 'nextcloud_url' => 'https://' . getenv('NC_DOMAIN'), - 'haproxy_password' => null, - 'gpu' => true, - ]; - - $daemonConfigParams = [ - 'name' => self::AIO_DAEMON_CONFIG_NAME_GPU, - 'display_name' => 'AIO Docker Socket Proxy with GPU', - 'accepts_deploy_id' => 'docker-install', - 'protocol' => 'http', - 'host' => self::AIO_DOCKER_SOCKET_PROXY_HOST, - 'deploy_config' => $deployConfig, - ]; - - return $this->daemonConfigService->registerDaemonConfig($daemonConfigParams); - } - - /** - * Check if /dev/dri folder mounted to the container. - * In AIO this means that NEXTCLOUD_ENABLE_DRI_DEVICE=true - */ - private function isGPUsEnabled(): bool { - $devDri = '/dev/dri'; - if (is_dir($devDri)) { - return true; - } - return false; - } } diff --git a/lib/DeployActions/DockerActions.php b/lib/DeployActions/DockerActions.php index abc9e641..7ec34d1a 100644 --- a/lib/DeployActions/DockerActions.php +++ b/lib/DeployActions/DockerActions.php @@ -125,11 +125,20 @@ public function createContainer(string $dockerUrl, array $imageParams, array $pa $containerParams['NetworkingConfig'] = $networkingConfig; } - if (isset($params['gpu']) && filter_var($params['gpu'], FILTER_VALIDATE_BOOLEAN)) { - if (isset($params['deviceRequests'])) { - $containerParams['HostConfig']['DeviceRequests'] = $params['deviceRequests']; - } else { - $containerParams['HostConfig']['DeviceRequests'] = $this->buildDefaultGPUDeviceRequests(); + if (isset($params['computeDevice'])) { + if ($params['computeDevice']['id'] === 'cuda') { + if (isset($params['deviceRequests'])) { + $containerParams['HostConfig']['DeviceRequests'] = $params['deviceRequests']; + } else { + $containerParams['HostConfig']['DeviceRequests'] = $this->buildDefaultGPUDeviceRequests(); + } + } + if ($params['computeDevice']['id'] === 'rocm') { + if (isset($params['devices'])) { + $containerParams['HostConfig']['Devices'] = $params['devices']; + } else { + $containerParams['HostConfig']['Devices'] = $this->buildDevicesParams(['/dev/kfd', '/dev/dri']); + } } } @@ -346,10 +355,15 @@ public function buildDeployParams(DaemonConfig $daemonConfig, array $appInfo): a $externalApp = $appInfo['external-app']; $deployConfig = $daemonConfig->getDeployConfig(); - if (isset($deployConfig['gpu']) && filter_var($deployConfig['gpu'], FILTER_VALIDATE_BOOLEAN)) { - $deviceRequests = $this->buildDefaultGPUDeviceRequests(); + if (isset($deployConfig['computeDevice'])) { + if ($deployConfig['computeDevice']['id'] === 'cuda') { + $deviceRequests = $this->buildDefaultGPUDeviceRequests(); + } elseif ($deployConfig['computeDevice']['id'] === 'rocm') { + $devices = $this->buildDevicesParams(['/dev/kfd', '/dev/dri']); + } } else { $deviceRequests = []; + $devices = []; } $storage = $this->buildDefaultExAppVolume($appId)[0]['Target']; @@ -375,8 +389,9 @@ public function buildDeployParams(DaemonConfig $daemonConfig, array $appInfo): a 'port' => $appInfo['port'], 'net' => $deployConfig['net'] ?? 'host', 'env' => $envs, + 'computeDevice' => $deployConfig['computeDevice'] ?? null, + 'devices' => $devices, 'deviceRequests' => $deviceRequests, - 'gpu' => count($deviceRequests) > 0, ]; return [ @@ -398,10 +413,14 @@ public function buildDeployEnvs(array $params, array $deployConfig): array { sprintf('NEXTCLOUD_URL=%s', $deployConfig['nextcloud_url'] ?? str_replace('https', 'http', $this->urlGenerator->getAbsoluteURL(''))), ]; + // Always set COMPUTE_DEVICE=cpu|cuda|rocm + $autoEnvs[] = sprintf('COMPUTE_DEVICE=%s', $deployConfig['computeDevice']['id']); // Add required GPU runtime envs if daemon configured to use GPU - if (isset($deployConfig['gpu']) && filter_var($deployConfig['gpu'], FILTER_VALIDATE_BOOLEAN)) { - $autoEnvs[] = sprintf('NVIDIA_VISIBLE_DEVICES=%s', 'all'); - $autoEnvs[] = sprintf('NVIDIA_DRIVER_CAPABILITIES=%s', 'compute,utility'); + if (isset($deployConfig['computeDevice'])) { + if ($deployConfig['computeDevice']['id'] === 'cuda') { + $autoEnvs[] = sprintf('NVIDIA_VISIBLE_DEVICES=%s', 'all'); + $autoEnvs[] = sprintf('NVIDIA_DRIVER_CAPABILITIES=%s', 'compute,utility'); + } } return $autoEnvs; } @@ -518,8 +537,6 @@ private function isGPUAvailable(): bool { /** * Return default GPU device requests for container. - * For now only NVIDIA GPUs supported. - * TODO: Add support for other GPU vendors */ private function buildDefaultGPUDeviceRequests(): array { return [ diff --git a/lib/Migration/DaemonUpdateGPUSRepairStep.php b/lib/Migration/DaemonUpdateGPUSRepairStep.php new file mode 100644 index 00000000..3e0fbf5e --- /dev/null +++ b/lib/Migration/DaemonUpdateGPUSRepairStep.php @@ -0,0 +1,72 @@ +daemonConfigMapper->findAll(); + $daemonsUpdated = 0; + // Update manual-install daemons + /** @var DaemonConfig $daemon */ + foreach ($daemons as $daemon) { + $daemonsUpdated += $this->updateDaemonConfiguration($daemon); + } + $output->info(sprintf('Daemons configuration GPU params updated: %s', $daemonsUpdated)); + } + + private function updateDaemonConfiguration(DaemonConfig $daemonConfig): int { + $updated = false; + + $deployConfig = $daemonConfig->getDeployConfig(); + if (isset($deployConfig['gpu'])) { + if (filter_var($deployConfig['gpu'], FILTER_VALIDATE_BOOLEAN)) { + $deployConfig['computeDevice'] = [ + 'id' => 'cuda', + 'label' => 'CUDA (NVIDIA)', + ]; + } else { + $deployConfig['computeDevice'] = [ + 'id' => 'cpu', + 'label' => 'CPU', + ]; + } + unset($deployConfig['gpu']); + $daemonConfig->setDeployConfig($deployConfig); + $updated = true; + } + + if ($updated) { + try { + $this->daemonConfigMapper->update($daemonConfig); + return 1; + } catch (Exception $e) { + $this->logger->error( + sprintf('Failed to update Daemon config (%s: %s)', + $daemonConfig->getAcceptsDeployId(), $daemonConfig->getName()), + ['exception' => $e] + ); + return 0; + } + } + return 0; + } +} diff --git a/package.json b/package.json index 8fdf4784..2f023701 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "lint": "eslint --ext .js,.vue src", "lint:fix": "eslint --ext .js,.vue src --fix", "stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css", - "stylelint:fix": "stylelint src/**/*.vue src/**/*.scss src/**/*.css --fix" + "stylelint:fix": "stylelint src/**/*.vue src/**/*.scss src/**/*.css --fix", + "serve": "NODE_ENV=development webpack serve --allowed-hosts all --config webpack.js" }, "browserslist": [ "extends @nextcloud/browserslist-config" diff --git a/screenshots/app_api_1.png b/screenshots/app_api_1.png index 105a605b..db88faec 100755 Binary files a/screenshots/app_api_1.png and b/screenshots/app_api_1.png differ diff --git a/screenshots/app_api_2.png b/screenshots/app_api_2.png old mode 100755 new mode 100644 index 6e414d4e..70ada7ec Binary files a/screenshots/app_api_2.png and b/screenshots/app_api_2.png differ diff --git a/screenshots/app_api_3.png b/screenshots/app_api_3.png old mode 100755 new mode 100644 index eae7d2bb..aa01934d Binary files a/screenshots/app_api_3.png and b/screenshots/app_api_3.png differ diff --git a/screenshots/app_api_4.png b/screenshots/app_api_4.png old mode 100755 new mode 100644 index eaf2f984..83905880 Binary files a/screenshots/app_api_4.png and b/screenshots/app_api_4.png differ diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue index c1f008d6..940a6f37 100644 --- a/src/components/AdminSettings.vue +++ b/src/components/AdminSettings.vue @@ -39,6 +39,7 @@ :options="['no', 'always', 'unless-stopped']" :placeholder="t('app_api', 'ExApp container restart policy')" :aria-label="t('app_api', 'ExApp container restart policy')" + :aria-label-combobox="t('app_api', 'ExApp container restart policy')" @input="onInput" /> diff --git a/src/components/DaemonConfig/ConfirmDaemonDeleteModal.vue b/src/components/DaemonConfig/ConfirmDaemonDeleteModal.vue new file mode 100644 index 00000000..595f7742 --- /dev/null +++ b/src/components/DaemonConfig/ConfirmDaemonDeleteModal.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/src/components/DaemonConfig/DaemonConfig.vue b/src/components/DaemonConfig/DaemonConfig.vue index 51a06b32..d3a048d9 100644 --- a/src/components/DaemonConfig/DaemonConfig.vue +++ b/src/components/DaemonConfig/DaemonConfig.vue @@ -31,39 +31,12 @@ :show.sync="showDetailsModal" :daemon="daemon" :is-default="isDefault" /> - - - - + :daemon="daemon" + :deleting="deleting" + :delete-daemon-config="_deleteDaemonConfig" + :show.sync="showDeleteDialog" /> @@ -72,31 +45,23 @@ import axios from '@nextcloud/axios' import { generateUrl } from '@nextcloud/router' import { showError } from '@nextcloud/dialogs' import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js' -import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js' -import NcDialogButton from '@nextcloud/vue/dist/Components/NcDialogButton.js' -import Cancel from 'vue-material-design-icons/Cancel.vue' -import Check from 'vue-material-design-icons/Check.vue' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' -import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' -import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' +import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' import CheckBold from 'vue-material-design-icons/CheckBold.vue' import DaemonConfigDetailsModal from './DaemonConfigDetailsModal.vue' +import ConfirmDaemonDeleteModal from './ConfirmDaemonDeleteModal.vue' export default { name: 'DaemonConfig', components: { NcListItem, NcActionButton, - NcLoadingIcon, CheckBold, - NcDialog, - NcDialogButton, - Cancel, - Check, DaemonConfigDetailsModal, - NcCheckboxRadioSwitch, + ConfirmDaemonDeleteModal, + NcLoadingIcon, }, props: { daemon: { @@ -181,12 +146,4 @@ export default { background-color: var(--color-background-dark); border-radius: var(--border-radius-pill); } - -.confirm-delete-dialog { - padding: 20px; - - p { - margin-bottom: 10px; - } -} diff --git a/src/components/DaemonConfig/DaemonConfigDetailsModal.vue b/src/components/DaemonConfig/DaemonConfigDetailsModal.vue index 39034060..f3956e5b 100644 --- a/src/components/DaemonConfig/DaemonConfigDetailsModal.vue +++ b/src/components/DaemonConfig/DaemonConfigDetailsModal.vue @@ -23,7 +23,12 @@ {{ t('app_api', 'HaProxy password') }}: {{ daemon.deploy_config?.haproxy_password }}

-

{{ t('app_api', 'GPUs support') }}: {{ daemon.deploy_config.gpu === true }}

+

+ {{ t('app_api', 'GPUs support') }}: {{ daemon.deploy_config.computeDevice && daemon.deploy_config?.computeDevice?.id !== 'cpu' || false }} +

+

+ {{ t('app_api', 'Compute device') }}: {{ daemon.deploy_config?.computeDevice?.label }} +

diff --git a/src/components/DaemonConfig/RegisterDaemonConfigModal.vue b/src/components/DaemonConfig/RegisterDaemonConfigModal.vue index 10517a9f..5dc1afb7 100644 --- a/src/components/DaemonConfig/RegisterDaemonConfigModal.vue +++ b/src/components/DaemonConfig/RegisterDaemonConfigModal.vue @@ -40,6 +40,7 @@ v-model="acceptsDeployId" :disabled="configurationTab.id === 'manual_install'" :options="deployMethods" + :label-outside="true" :placeholder="t('app_api', 'Select daemon deploy method')" />
@@ -110,19 +111,15 @@ :aria-label="t('app_api', 'AppAPI Docker Socket Proxy authentication password')" :helper-text="haProxyPasswordHelperText" />
- - {{ t('app_api', 'Enable GPUs support') }} - -

+ +

{{ t('app_api', 'All available GPU devices on daemon host will be requested to be enabled in ExApp containers by Docker.') }} - - {{ t('app_api', 'Only NVIDIA GPUs are supported for now.') }} -

@@ -159,7 +156,6 @@ import { generateUrl } from '@nextcloud/router' import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' import NcInputField from '@nextcloud/vue/dist/Components/NcInputField.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' -import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js' import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js' import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' @@ -169,7 +165,7 @@ import Check from 'vue-material-design-icons/Check.vue' import Connection from 'vue-material-design-icons/Connection.vue' import UnfoldLessHorizontal from 'vue-material-design-icons/UnfoldLessHorizontal.vue' import UnfoldMoreHorizontal from 'vue-material-design-icons/UnfoldMoreHorizontal.vue' -import { DAEMON_TEMPLATES } from '../../constants/daemonTemplates.js' +import { DAEMON_TEMPLATES, DAEMON_COMPUTE_DEVICES } from '../../constants/daemonTemplates.js' export default { name: 'RegisterDaemonConfigModal', @@ -180,7 +176,6 @@ export default { UnfoldLessHorizontal, UnfoldMoreHorizontal, NcCheckboxRadioSwitch, - NcNoteCard, NcSelect, NcButton, Check, @@ -216,7 +211,10 @@ export default { deployConfig: { net: 'host', haproxy_password: '', - gpu: false, + computeDevice: { + id: 'cpu', + label: 'CPU', + }, }, defaultDaemon: false, registeringDaemon: false, @@ -225,6 +223,7 @@ export default { ...DAEMON_TEMPLATES.map(template => { return { id: template.name, label: template.displayName } }), ], verifyingDaemonConnection: false, + computeDevices: DAEMON_COMPUTE_DEVICES, } }, computed: { @@ -334,8 +333,8 @@ export default { deploy_config: { net: this.deployConfig.net, nextcloud_url: this.nextcloud_url, - gpu: this.deployConfig.gpu, haproxy_password: this.deployConfig.haproxy_password ?? '', + computeDevice: this.deployConfig.computeDevice, }, } }, @@ -353,7 +352,7 @@ export default { this.deployConfigSettingsOpened = template.deployConfigSettingsOpened this.deployConfig.net = template.deployConfig.net this.deployConfig.haproxy_password = template.deployConfig.haproxy_password - this.deployConfig.gpu = template.deployConfig.gpu + this.deployConfig.computeDevice = template.deployConfig.computeDevice this.defaultDaemon = template.defaultDaemon }, onProtocolChange() { diff --git a/src/constants/daemonTemplates.js b/src/constants/daemonTemplates.js index e76f439d..ac21815c 100644 --- a/src/constants/daemonTemplates.js +++ b/src/constants/daemonTemplates.js @@ -10,6 +10,10 @@ export const DAEMON_TEMPLATES = [ net: 'host', haproxy_password: 'some_secure_password', gpu: false, + computeDevice: { + id: 'cpu', + label: 'CPU', + }, }, deployConfigSettingsOpened: false, defaultDaemon: true, @@ -25,6 +29,10 @@ export const DAEMON_TEMPLATES = [ net: 'host', haproxy_password: 'enter_haproxy_password', gpu: false, + computeDevice: { + id: 'cpu', + label: 'CPU', + }, }, deployConfigSettingsOpened: false, defaultDaemon: true, @@ -40,6 +48,10 @@ export const DAEMON_TEMPLATES = [ net: 'nextcloud-aio', haproxy_password: '', gpu: false, + computeDevice: { + id: 'cpu', + label: 'CPU', + }, }, deployConfigSettingsOpened: false, defaultDaemon: true, @@ -55,8 +67,27 @@ export const DAEMON_TEMPLATES = [ net: 'host', haproxy_password: '', gpu: false, + computeDevice: { + id: 'cpu', + label: 'CPU', + }, }, deployConfigSettingsOpened: false, defaultDaemon: false, }, ] + +export const DAEMON_COMPUTE_DEVICES = [ + { + id: 'cpu', + label: 'CPU', + }, + { + id: 'cuda', + label: 'CUDA (NVIDIA)', + }, + { + id: 'rocm', + label: 'ROCm (AMD)', + }, +]