mirror of
https://github.com/portainer/portainer.git
synced 2025-08-08 15:25:22 +02:00
feat(gpu) EE-3191 Add GPU support for containers (#7146)
This commit is contained in:
parent
f0456cbf5f
commit
4997e9c7be
43 changed files with 758 additions and 10 deletions
|
@ -1,3 +1,4 @@
|
|||
import { Gpu } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import { type EnvironmentGroupId } from '@/portainer/environment-groups/types';
|
||||
import { type TagId } from '@/portainer/tags/types';
|
||||
|
@ -16,6 +17,7 @@ interface CreateLocalDockerEnvironment {
|
|||
socketPath?: string;
|
||||
publicUrl?: string;
|
||||
meta?: EnvironmentMetadata;
|
||||
gpus?: Gpu[];
|
||||
}
|
||||
|
||||
export async function createLocalDockerEnvironment({
|
||||
|
@ -23,6 +25,7 @@ export async function createLocalDockerEnvironment({
|
|||
socketPath = '',
|
||||
publicUrl = '',
|
||||
meta = { tagIds: [] },
|
||||
gpus = [],
|
||||
}: CreateLocalDockerEnvironment) {
|
||||
const url = prefixPath(socketPath);
|
||||
|
||||
|
@ -33,6 +36,7 @@ export async function createLocalDockerEnvironment({
|
|||
url,
|
||||
publicUrl,
|
||||
meta,
|
||||
gpus,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -105,6 +109,7 @@ export interface EnvironmentOptions {
|
|||
azure?: AzureSettings;
|
||||
tls?: TLSSettings;
|
||||
isEdgeDevice?: boolean;
|
||||
gpus?: Gpu[];
|
||||
}
|
||||
|
||||
interface CreateRemoteEnvironment {
|
||||
|
@ -133,6 +138,7 @@ export interface CreateAgentEnvironmentValues {
|
|||
name: string;
|
||||
environmentUrl: string;
|
||||
meta: EnvironmentMetadata;
|
||||
gpus: Gpu[];
|
||||
}
|
||||
|
||||
export function createAgentEnvironment({
|
||||
|
@ -159,12 +165,14 @@ interface CreateEdgeAgentEnvironment {
|
|||
portainerUrl: string;
|
||||
meta?: EnvironmentMetadata;
|
||||
pollFrequency: number;
|
||||
gpus?: Gpu[];
|
||||
}
|
||||
|
||||
export function createEdgeAgentEnvironment({
|
||||
name,
|
||||
portainerUrl,
|
||||
meta = { tagIds: [] },
|
||||
gpus = [],
|
||||
}: CreateEdgeAgentEnvironment) {
|
||||
return createEnvironment(
|
||||
name,
|
||||
|
@ -176,6 +184,7 @@ export function createEdgeAgentEnvironment({
|
|||
skipVerify: true,
|
||||
skipClientVerify: true,
|
||||
},
|
||||
gpus,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -201,6 +210,7 @@ async function createEnvironment(
|
|||
TagIds: arrayToJson(tagIds),
|
||||
CheckinInterval: options.checkinInterval,
|
||||
IsEdgeDevice: options.isEdgeDevice,
|
||||
Gpus: arrayToJson(options.gpus),
|
||||
};
|
||||
|
||||
const { tls, azure } = options;
|
||||
|
|
|
@ -40,6 +40,8 @@ export interface DockerSnapshot {
|
|||
ServiceCount: number;
|
||||
Swarm: boolean;
|
||||
DockerVersion: string;
|
||||
GpuUseAll: boolean;
|
||||
GpuUseList: string[];
|
||||
}
|
||||
|
||||
export interface KubernetesSnapshot {
|
||||
|
@ -103,6 +105,7 @@ export type Environment = {
|
|||
AMTDeviceGUID?: string;
|
||||
Edge: EnvironmentEdge;
|
||||
SecuritySettings: EnvironmentSecuritySettings;
|
||||
Gpus: { name: string; value: string }[];
|
||||
};
|
||||
/**
|
||||
* TS reference of endpoint_create.go#EndpointCreationType iota
|
||||
|
|
|
@ -100,6 +100,8 @@ export function EnvironmentItem({ environment, onClick, groupName }: Props) {
|
|||
{environment.Snapshots[0].TotalCPU}
|
||||
<i className="fa fa-memory space-left space-right" />
|
||||
{humanize(environment.Snapshots[0].TotalMemory)}
|
||||
<i className="fa fa-digital-tachograph space-left space-right" />
|
||||
{environment.Gpus.length}
|
||||
</span>
|
||||
)}
|
||||
<span className="space-left space-right">-</span>
|
||||
|
|
|
@ -222,6 +222,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- !open-amt info -->
|
||||
<!-- gpus info -->
|
||||
<div class="col-sm-12 form-section-title">Hardware acceleration</div>
|
||||
<gpus-list value="endpoint.Gpus || []" on-change="(onGpusChange)"></gpus-list>
|
||||
<!-- gpus info -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button
|
||||
|
|
|
@ -9,8 +9,9 @@ import { confirmAsync } from '@/portainer/services/modal.service/confirm';
|
|||
import { isEdgeEnvironment } from '@/portainer/environments/utils';
|
||||
|
||||
import { commandsTabs } from '@/react/edge/components/EdgeScriptForm/scripts';
|
||||
import { GpusListAngular } from '@/react/portainer/environments/wizard/EnvironmentsCreationView/shared/Hardware/GpusList';
|
||||
|
||||
angular.module('portainer.app').controller('EndpointController', EndpointController);
|
||||
angular.module('portainer.app').component('gpusList', GpusListAngular).controller('EndpointController', EndpointController);
|
||||
|
||||
/* @ngInject */
|
||||
function EndpointController(
|
||||
|
@ -34,6 +35,12 @@ function EndpointController(
|
|||
const isBE = process.env.PORTAINER_EDITION === 'BE';
|
||||
|
||||
$scope.state = {
|
||||
selectAll: false,
|
||||
// displayTextFilter: false,
|
||||
get selectedItemCount() {
|
||||
return $scope.state.selectedItems.length || 0;
|
||||
},
|
||||
selectedItems: [],
|
||||
uploadInProgress: false,
|
||||
actionInProgress: false,
|
||||
azureEndpoint: false,
|
||||
|
@ -51,6 +58,46 @@ function EndpointController(
|
|||
},
|
||||
};
|
||||
|
||||
$scope.selectAll = function () {
|
||||
$scope.state.firstClickedItem = null;
|
||||
for (var i = 0; i < $scope.state.filteredDataSet.length; i++) {
|
||||
var item = $scope.state.filteredDataSet[i];
|
||||
if (item.Checked !== $scope.state.selectAll) {
|
||||
// if ($scope.allowSelection(item) && item.Checked !== $scope.state.selectAll) {
|
||||
item.Checked = $scope.state.selectAll;
|
||||
$scope.selectItem(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function isBetween(value, a, b) {
|
||||
return (value >= a && value <= b) || (value >= b && value <= a);
|
||||
}
|
||||
|
||||
$scope.selectItem = function (item, event) {
|
||||
// Handle range select using shift
|
||||
if (event && event.originalEvent.shiftKey && $scope.state.firstClickedItem) {
|
||||
const firstItemIndex = $scope.state.filteredDataSet.indexOf($scope.state.firstClickedItem);
|
||||
const lastItemIndex = $scope.state.filteredDataSet.indexOf(item);
|
||||
const itemsInRange = _.filter($scope.state.filteredDataSet, (item, index) => {
|
||||
return isBetween(index, firstItemIndex, lastItemIndex);
|
||||
});
|
||||
const value = $scope.state.firstClickedItem.Checked;
|
||||
|
||||
_.forEach(itemsInRange, (i) => {
|
||||
i.Checked = value;
|
||||
});
|
||||
$scope.state.firstClickedItem = item;
|
||||
} else if (event) {
|
||||
item.Checked = !item.Checked;
|
||||
$scope.state.firstClickedItem = item;
|
||||
}
|
||||
$scope.state.selectedItems = _.uniq(_.concat($scope.state.selectedItems, $scope.state.filteredDataSet)).filter((i) => i.Checked);
|
||||
if (event && $scope.state.selectAll && $scope.state.selectedItems.length !== $scope.state.filteredDataSet.length) {
|
||||
$scope.state.selectAll = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
SecurityFormData: new EndpointSecurityFormData(),
|
||||
};
|
||||
|
@ -106,6 +153,36 @@ function EndpointController(
|
|||
});
|
||||
}
|
||||
|
||||
$scope.onGpusChange = onGpusChange;
|
||||
|
||||
Array.prototype.indexOf = function (val) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] == val) return i;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
Array.prototype.remove = function (val) {
|
||||
var index = this.indexOf(val);
|
||||
if (index > -1) {
|
||||
this.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
function onGpusChange(value) {
|
||||
return $async(async () => {
|
||||
$scope.endpoint.Gpus = value;
|
||||
});
|
||||
}
|
||||
|
||||
function verifyGpus() {
|
||||
var i = $scope.endpoint.Gpus.length;
|
||||
while (i--) {
|
||||
if ($scope.endpoint.Gpus[i].name === '' || $scope.endpoint.Gpus[i].name === null) {
|
||||
$scope.endpoint.Gpus.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.updateEndpoint = async function () {
|
||||
var endpoint = $scope.endpoint;
|
||||
var securityData = $scope.formValues.SecurityFormData;
|
||||
|
@ -135,9 +212,11 @@ function EndpointController(
|
|||
}
|
||||
}
|
||||
|
||||
verifyGpus();
|
||||
var payload = {
|
||||
Name: endpoint.Name,
|
||||
PublicURL: endpoint.PublicURL,
|
||||
Gpus: endpoint.Gpus,
|
||||
GroupID: endpoint.GroupId,
|
||||
TagIds: endpoint.TagIds,
|
||||
TLS: TLS,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue