1
0
Fork 0
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:
congs 2022-07-18 11:02:14 +12:00 committed by GitHub
parent f0456cbf5f
commit 4997e9c7be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 758 additions and 10 deletions

View file

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

View file

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

View file

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

View file

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

View file

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