mirror of
https://github.com/portainer/portainer.git
synced 2025-08-07 14:55:27 +02:00
feat(app): limit the docker API version supported by the frontend (#11855)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
This commit is contained in:
parent
4ba16f1b04
commit
6a8e6734f3
212 changed files with 4439 additions and 3281 deletions
116
app/portainer/services/angularToReact.ts
Normal file
116
app/portainer/services/angularToReact.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
import { EndpointProviderInterface } from './endpointProvider';
|
||||
|
||||
// see async.js
|
||||
type AsyncInterface = (
|
||||
asyncFunc: AsyncFunction,
|
||||
...args: unknown[]
|
||||
) => Promise<unknown>;
|
||||
|
||||
type AsyncFunction = (...params: unknown[]) => Promise<unknown>;
|
||||
type AxiosFunction = (
|
||||
environmentId: EnvironmentId | undefined,
|
||||
...params: unknown[]
|
||||
) => Promise<unknown>;
|
||||
|
||||
/* @ngInject */
|
||||
export function AngularToReact(
|
||||
EndpointProvider: EndpointProviderInterface,
|
||||
$async: AsyncInterface
|
||||
) {
|
||||
return { useAxios, injectEnvironmentId };
|
||||
|
||||
/**
|
||||
* Wraps the async axios function with `$async` to ensures the request runs inside the AngularJS digest cycle
|
||||
*
|
||||
* See `$async` (async.js) implementation and notes
|
||||
*
|
||||
* See `AngularToReact.injectEnvironmentId` to solve `environmentId` injection for services functions relying
|
||||
* on `EndpointProvider.endpointID()` in their `$resource()` definition
|
||||
*
|
||||
* @example
|
||||
* **Old AngularJS service**
|
||||
* ```
|
||||
* // file:: AngularJS service.js
|
||||
*
|
||||
* // ngInject
|
||||
* function ServiceServiceFactory($q, Service) {
|
||||
* return { getService };
|
||||
*
|
||||
* // the original signature doesn't have environmentId passed to it
|
||||
* // it relies on EndpointProvider in $resource() definition
|
||||
* // we will inject it on refactor
|
||||
* // the function uses $q, which internally triggers a redraw of the UI when it resolves/rejects
|
||||
* function getService(serviceId) {
|
||||
* var deferred = $q.defer();
|
||||
* [...]
|
||||
* return deferred.promise;
|
||||
* };
|
||||
*
|
||||
* // the original signature has environmentId passed to it
|
||||
* // it doesn't rely on EndpointProvider in $resource() definition
|
||||
* // we won't inject environmentId on refactor
|
||||
* // the function uses $q, which internally triggers a redraw of the UI when it resolves/rejects
|
||||
* function listServices(environmentId) {
|
||||
* var deferred = $q.defer();
|
||||
* [...]
|
||||
* return deferred.promise;
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **New format**
|
||||
* ```
|
||||
* // file:: '@/react/.../useService.ts'
|
||||
* // this function has `environmentId` as first parameter, which doesn't match the old AngularJS service signature
|
||||
* export async function getService(environmentId: EnvironmentId, serviceId: ServiceId) {
|
||||
* // axios.get()
|
||||
* }
|
||||
* // file:: '@/react/.../useServices.ts'
|
||||
* // this function has `environmentId` as first parameter, which matches the old AngularJS service signature
|
||||
* export async function listServices(environmentId: EnvironmentId, serviceId: ServiceId) {
|
||||
* // axios.get()
|
||||
* }
|
||||
* // file:: AngularJS service.js
|
||||
* import { getService } from '@/react/.../useService.ts';
|
||||
* import { listServices } from '@/react/.../useServices.ts';
|
||||
*
|
||||
* // ngInject
|
||||
* function ServiceServiceFactory(AngularToReact) {
|
||||
* const { useAxios, injectEnvironmentId } = AngularToReact;
|
||||
* return {
|
||||
* // ask to inject environmentId to maintain the old signature
|
||||
* getService: useAxios(injectEnvironmentId(getService)),
|
||||
* // do not ask to inject environmentId as it was already in the old signature
|
||||
* // and is already passed by the caller
|
||||
* listServices: useAxios(listServices),
|
||||
* };
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
function useAxios(axiosFunc: AxiosFunction) {
|
||||
return (...params: unknown[]) =>
|
||||
$async(axiosFunc as AsyncFunction, ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Axios function taking `endpointId` as first param to expose the old service format.
|
||||
*
|
||||
* Leverage injected `EndpointProvider` that was used in the rest file - `$resource()` definition.
|
||||
*
|
||||
* The axios function params **MUST** match the old AngularJS-service ones to use this helper without changing the service calls
|
||||
*
|
||||
* Should be used in conjunction with `AngularToReact.useAxios`
|
||||
*
|
||||
* @example
|
||||
* See `AngularToReact.useAxios`
|
||||
*
|
||||
* @param {(environmentId: EnvironmentId, ...params: unknown[]) => Promise<unknown>} axiosFunc Axios function taking `environmentId` as first param
|
||||
* @returns a function with the old AngularJS signature
|
||||
*/
|
||||
function injectEnvironmentId(axiosFunc: AxiosFunction) {
|
||||
return async (...params: unknown[]) =>
|
||||
axiosFunc(EndpointProvider.endpointID(), ...params);
|
||||
}
|
||||
}
|
|
@ -54,11 +54,11 @@ angular.module('portainer.app').factory('StackService', [
|
|||
SwarmService.swarm(targetEndpointId)
|
||||
.then(function success(data) {
|
||||
var swarm = data;
|
||||
if (swarm.Id === stack.SwarmId) {
|
||||
if (swarm.ID === stack.SwarmId) {
|
||||
deferred.reject({ msg: 'Target environment is located in the same Swarm cluster as the current environment', err: null });
|
||||
return;
|
||||
}
|
||||
return Stack.migrate({ id: stack.Id, endpointId: stack.EndpointId }, { EndpointID: targetEndpointId, SwarmID: swarm.Id, Name: newName }).$promise;
|
||||
return Stack.migrate({ id: stack.Id, endpointId: stack.EndpointId }, { EndpointID: targetEndpointId, SwarmID: swarm.ID, Name: newName }).$promise;
|
||||
})
|
||||
.then(function success() {
|
||||
deferred.resolve();
|
||||
|
@ -182,10 +182,10 @@ angular.module('portainer.app').factory('StackService', [
|
|||
service.swarmStacks = function (endpointId, includeExternalStacks, filters = {}) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
SwarmService.swarm()
|
||||
SwarmService.swarm(endpointId)
|
||||
.then(function success(data) {
|
||||
var swarm = data;
|
||||
filters = { SwarmID: swarm.Id, ...filters };
|
||||
filters = { SwarmID: swarm.ID, ...filters };
|
||||
|
||||
return $q.all({
|
||||
stacks: Stack.query({ filters: filters }).$promise,
|
||||
|
@ -239,10 +239,10 @@ angular.module('portainer.app').factory('StackService', [
|
|||
var deferred = $q.defer();
|
||||
|
||||
if (stack.Type == 1) {
|
||||
SwarmService.swarm()
|
||||
SwarmService.swarm(endpointId)
|
||||
.then(function success(data) {
|
||||
const swarm = data;
|
||||
return Stack.associate({ id: stack.Id, endpointId: endpointId, swarmId: swarm.Id, orphanedRunning }).$promise;
|
||||
return Stack.associate({ id: stack.Id, endpointId: endpointId, swarmId: swarm.ID, orphanedRunning }).$promise;
|
||||
})
|
||||
.then(function success(data) {
|
||||
deferred.resolve(data);
|
||||
|
@ -305,10 +305,10 @@ angular.module('portainer.app').factory('StackService', [
|
|||
service.createSwarmStackFromFileUpload = function (name, stackFile, env, endpointId) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
SwarmService.swarm()
|
||||
SwarmService.swarm(endpointId)
|
||||
.then(function success(data) {
|
||||
var swarm = data;
|
||||
return FileUploadService.createSwarmStack(name, swarm.Id, stackFile, env, endpointId);
|
||||
return FileUploadService.createSwarmStack(name, swarm.ID, stackFile, env, endpointId);
|
||||
})
|
||||
.then(function success(data) {
|
||||
deferred.resolve(data.data);
|
||||
|
@ -335,7 +335,7 @@ angular.module('portainer.app').factory('StackService', [
|
|||
.then(function success(swarm) {
|
||||
var payload = {
|
||||
Name: name,
|
||||
SwarmID: swarm.Id,
|
||||
SwarmID: swarm.ID,
|
||||
StackFileContent: stackFileContent,
|
||||
Env: env,
|
||||
};
|
||||
|
@ -376,12 +376,12 @@ angular.module('portainer.app').factory('StackService', [
|
|||
service.createSwarmStackFromGitRepository = function (name, repositoryOptions, env, endpointId) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
SwarmService.swarm()
|
||||
SwarmService.swarm(endpointId)
|
||||
.then(function success(data) {
|
||||
var swarm = data;
|
||||
var payload = {
|
||||
Name: name,
|
||||
SwarmID: swarm.Id,
|
||||
SwarmID: swarm.ID,
|
||||
RepositoryURL: repositoryOptions.RepositoryURL,
|
||||
RepositoryReferenceName: repositoryOptions.RepositoryReferenceName,
|
||||
ComposeFile: repositoryOptions.ComposeFilePathInRepository,
|
||||
|
|
|
@ -21,6 +21,8 @@ import {
|
|||
portainerAgentManagerOperation,
|
||||
portainerAgentTargetHeader,
|
||||
} from './http-request.helper';
|
||||
import { dockerMaxAPIVersionInterceptor } from './dockerMaxApiVersionInterceptor';
|
||||
import { MAX_DOCKER_API_VERSION } from './dockerMaxApiVersion';
|
||||
|
||||
const portainerCacheHeader = 'X-Portainer-Cache';
|
||||
|
||||
|
@ -48,7 +50,10 @@ function headerInterpreter(
|
|||
return 'not enough headers';
|
||||
}
|
||||
|
||||
const axios = Axios.create({ baseURL: 'api' });
|
||||
const axios = Axios.create({
|
||||
baseURL: 'api',
|
||||
maxDockerAPIVersion: MAX_DOCKER_API_VERSION,
|
||||
});
|
||||
axios.interceptors.request.use((req) => {
|
||||
dispatchCacheRefreshEventIfNeeded(req);
|
||||
return req;
|
||||
|
@ -118,13 +123,14 @@ export function agentInterceptor(config: InternalAxiosRequestConfig) {
|
|||
return newConfig;
|
||||
}
|
||||
|
||||
axios.interceptors.request.use(dockerMaxAPIVersionInterceptor);
|
||||
axios.interceptors.request.use(agentInterceptor);
|
||||
|
||||
axios.interceptors.response.use(undefined, (error) => {
|
||||
if (
|
||||
error.response?.status === 401 &&
|
||||
!error.config.url.includes('/v2/') &&
|
||||
!error.config.url.includes('/api/v4/') &&
|
||||
!error.config.url.includes('/v2/') && // docker proxy through agent
|
||||
!error.config.url.includes('/api/v4/') && // gitlab proxy
|
||||
isTransitionRequiresAuthentication()
|
||||
) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -188,6 +194,12 @@ export function defaultErrorParser(axiosError: AxiosError<unknown>) {
|
|||
const error = new Error(message);
|
||||
return { error, details };
|
||||
}
|
||||
if (isArrayResponse(axiosError.response?.data)) {
|
||||
const message = axiosError.response?.data[0].message || '';
|
||||
const details = axiosError.response?.data[0].details || message;
|
||||
const error = new Error(message);
|
||||
return { error, details };
|
||||
}
|
||||
|
||||
const details = axiosError.response?.data
|
||||
? axiosError.response?.data.toString()
|
||||
|
@ -196,6 +208,16 @@ export function defaultErrorParser(axiosError: AxiosError<unknown>) {
|
|||
return { error, details };
|
||||
}
|
||||
|
||||
// handle jsonObjectsToArrayHandler transformation
|
||||
function isArrayResponse(data: unknown): data is DefaultAxiosErrorType[] {
|
||||
return (
|
||||
!!data &&
|
||||
Array.isArray(data) &&
|
||||
'message' in data[0] &&
|
||||
typeof data[0].message === 'string'
|
||||
);
|
||||
}
|
||||
|
||||
export function isDefaultResponse(
|
||||
data: unknown
|
||||
): data is DefaultAxiosErrorType {
|
||||
|
@ -249,3 +271,18 @@ export function json2formData(json: Record<string, unknown>) {
|
|||
|
||||
return formData;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Docker API often returns a list of JSON object.
|
||||
* This handler wrap the JSON objects in an array.
|
||||
* @param data Raw docker API response (stream of objects in a single string)
|
||||
* @returns An array of parsed objects
|
||||
*/
|
||||
export function jsonObjectsToArrayHandler(data: string): unknown[] {
|
||||
// catching empty data helps the function not to fail and prevents unwanted error message to user.
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
const str = `[${data.replace(/\n/g, ' ').replace(/\}\s*\{/g, '}, {')}]`;
|
||||
return JSON.parse(str);
|
||||
}
|
||||
|
|
11
app/portainer/services/dockerMaxApiVersion.ts
Normal file
11
app/portainer/services/dockerMaxApiVersion.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Key used in axios types definitions
|
||||
export const MaxDockerAPIVersionKey = 'maxDockerAPIVersion' as const;
|
||||
|
||||
export type DockerAPIVersionType = number;
|
||||
|
||||
// this is the version we are using with the generated API types
|
||||
export const MAX_DOCKER_API_VERSION: DockerAPIVersionType = 1.41;
|
||||
|
||||
// https://docs.docker.com/engine/api/#api-version-matrix
|
||||
// Docker 26 = API 1.45
|
||||
export const LATEST_DOCKER_API_VERSION: DockerAPIVersionType = 1.45;
|
64
app/portainer/services/dockerMaxApiVersionInterceptor.ts
Normal file
64
app/portainer/services/dockerMaxApiVersionInterceptor.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { SystemVersion } from 'docker-types/generated/1.41';
|
||||
import Axios, { InternalAxiosRequestConfig } from 'axios';
|
||||
import { setupCache, buildMemoryStorage } from 'axios-cache-interceptor';
|
||||
|
||||
import { buildDockerProxyUrl } from '@/react/docker/proxy/queries/buildDockerProxyUrl';
|
||||
|
||||
import PortainerError from '../error';
|
||||
|
||||
import { MAX_DOCKER_API_VERSION } from './dockerMaxApiVersion';
|
||||
|
||||
const envVersionAxios = Axios.create({
|
||||
baseURL: 'api',
|
||||
maxDockerAPIVersion: MAX_DOCKER_API_VERSION,
|
||||
});
|
||||
|
||||
// setup a cache for the intermediary request sent by the interceptor
|
||||
const envVersionCache = buildMemoryStorage();
|
||||
setupCache(envVersionAxios, {
|
||||
storage: envVersionCache,
|
||||
ttl: 5 * 60 * 1000,
|
||||
methods: ['get'],
|
||||
});
|
||||
|
||||
export async function dockerMaxAPIVersionInterceptor(
|
||||
rawConfig: InternalAxiosRequestConfig
|
||||
) {
|
||||
try {
|
||||
const config = rawConfig;
|
||||
const found = config.url?.match(
|
||||
/endpoints\/(?<environmentId>\d+)\/docker\//
|
||||
);
|
||||
|
||||
if (found && found.groups) {
|
||||
const { environmentId } = found.groups;
|
||||
const envId = parseInt(environmentId, 10);
|
||||
|
||||
// if we cannot parse the env ID, don't send a request that will fail,
|
||||
// exit the interceptor and let the original request config pass through
|
||||
if (Number.isNaN(envId)) {
|
||||
return config;
|
||||
}
|
||||
|
||||
const { data } = await envVersionAxios.get<SystemVersion>(
|
||||
buildDockerProxyUrl(envId, 'version')
|
||||
);
|
||||
|
||||
const apiVersion = parseFloat(data.ApiVersion ?? '0');
|
||||
const { maxDockerAPIVersion } = config;
|
||||
|
||||
if (apiVersion > maxDockerAPIVersion) {
|
||||
config.url = config.url?.replace(
|
||||
/docker/,
|
||||
`docker/v${maxDockerAPIVersion}`
|
||||
);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
} catch (err) {
|
||||
throw new PortainerError(
|
||||
'An error occurred while trying to limit request to the maximum supported Docker API version',
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { ping } from '@/docker/services/ping';
|
||||
import { ping } from '@/react/docker/proxy/queries/usePing';
|
||||
import { environmentStore } from '@/react/hooks/current-environment-store';
|
||||
import {
|
||||
Environment,
|
||||
|
|
|
@ -1,238 +1,209 @@
|
|||
import { PortainerEndpointCreationTypes } from 'Portainer/models/endpoint/models';
|
||||
import { genericHandler, jsonObjectsToArrayHandler } from '../../docker/rest/response/handlers';
|
||||
|
||||
angular.module('portainer.app').factory('FileUploadService', [
|
||||
'$q',
|
||||
'Upload',
|
||||
'EndpointProvider',
|
||||
function FileUploadFactory($q, Upload, EndpointProvider) {
|
||||
'use strict';
|
||||
angular.module('portainer.app').factory('FileUploadService', FileUploadFactory);
|
||||
|
||||
var service = {};
|
||||
/* @ngInject */
|
||||
function FileUploadFactory($q, Upload) {
|
||||
var service = {
|
||||
// createSchedule, // edge jobs service
|
||||
// uploadBackup, // backup service
|
||||
// createSwarmStack, // stack service
|
||||
// createComposeStack, // stack service
|
||||
// createEdgeStack, // edge stack service
|
||||
// createCustomTemplate, // custom template service
|
||||
// configureRegistry, // registry service
|
||||
// createEndpoint, // endpoint service
|
||||
// createAzureEndpoint, // endpoint service
|
||||
// uploadLDAPTLSFiles, // auth settings controller
|
||||
// uploadTLSFilesForEndpoint, // endpoint service
|
||||
// uploadOwnershipVoucher, // import device controller
|
||||
};
|
||||
|
||||
function uploadFile(url, file) {
|
||||
return Upload.upload({ url: url, data: { file: file } });
|
||||
function uploadFile(url, file) {
|
||||
return Upload.upload({ url: url, data: { file: file } });
|
||||
}
|
||||
|
||||
service.createSchedule = function (payload) {
|
||||
return Upload.upload({
|
||||
url: 'api/edge_jobs/create/file',
|
||||
data: {
|
||||
file: payload.File,
|
||||
Name: payload.Name,
|
||||
CronExpression: payload.CronExpression,
|
||||
Image: payload.Image,
|
||||
Endpoints: Upload.json(payload.Endpoints),
|
||||
RetryCount: payload.RetryCount,
|
||||
RetryInterval: payload.RetryInterval,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
service.uploadBackup = function (file, password) {
|
||||
return Upload.upload({
|
||||
url: 'api/restore',
|
||||
data: {
|
||||
file,
|
||||
password,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
service.createSwarmStack = function (stackName, swarmId, file, env, endpointId, webhook) {
|
||||
return Upload.upload({
|
||||
url: `api/stacks/create/swarm/file?endpointId=${endpointId}`,
|
||||
data: {
|
||||
file: file,
|
||||
Name: stackName,
|
||||
SwarmID: swarmId,
|
||||
Env: Upload.json(env),
|
||||
Webhook: webhook,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createComposeStack = function (stackName, file, env, endpointId, webhook) {
|
||||
return Upload.upload({
|
||||
url: `api/stacks/create/standalone/file?endpointId=${endpointId}`,
|
||||
data: {
|
||||
file: file,
|
||||
Name: stackName,
|
||||
Env: Upload.json(env),
|
||||
Webhook: webhook,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createEdgeStack = function createEdgeStack({ EdgeGroups, Registries, envVars, staggerConfig, ...payload }, file, dryrun) {
|
||||
return Upload.upload({
|
||||
url: `api/edge_stacks/create/file?dryrun=${dryrun}`,
|
||||
data: {
|
||||
file,
|
||||
EdgeGroups: Upload.json(EdgeGroups),
|
||||
Registries: Upload.json(Registries),
|
||||
EnvVars: Upload.json(envVars),
|
||||
StaggerConfig: Upload.json(staggerConfig),
|
||||
...payload,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createCustomTemplate = function createCustomTemplate(data) {
|
||||
return Upload.upload({
|
||||
url: 'api/custom_templates/create/file',
|
||||
data,
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.configureRegistry = function (registryId, registryManagementConfigurationModel) {
|
||||
return Upload.upload({
|
||||
url: 'api/registries/' + registryId + '/configure',
|
||||
data: registryManagementConfigurationModel,
|
||||
});
|
||||
};
|
||||
|
||||
service.createEndpoint = function (
|
||||
name,
|
||||
creationType,
|
||||
URL,
|
||||
PublicURL,
|
||||
groupID,
|
||||
tagIds,
|
||||
TLS,
|
||||
TLSSkipVerify,
|
||||
TLSSkipClientVerify,
|
||||
TLSCAFile,
|
||||
TLSCertFile,
|
||||
TLSKeyFile,
|
||||
checkinInterval,
|
||||
EdgePingInterval,
|
||||
EdgeSnapshotInterval,
|
||||
EdgeCommandInterval
|
||||
) {
|
||||
return Upload.upload({
|
||||
url: 'api/endpoints',
|
||||
data: {
|
||||
Name: name,
|
||||
EndpointCreationType: creationType,
|
||||
URL: URL,
|
||||
PublicURL: PublicURL,
|
||||
GroupID: groupID,
|
||||
TagIds: Upload.json(tagIds),
|
||||
TLS: TLS,
|
||||
TLSSkipVerify: TLSSkipVerify,
|
||||
TLSSkipClientVerify: TLSSkipClientVerify,
|
||||
TLSCACertFile: TLSCAFile,
|
||||
TLSCertFile: TLSCertFile,
|
||||
TLSKeyFile: TLSKeyFile,
|
||||
CheckinInterval: checkinInterval,
|
||||
EdgePingInterval: EdgePingInterval,
|
||||
EdgeSnapshotInterval: EdgeSnapshotInterval,
|
||||
EdgeCommandInterval: EdgeCommandInterval,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createAzureEndpoint = function (name, applicationId, tenantId, authenticationKey, groupId, tagIds) {
|
||||
return Upload.upload({
|
||||
url: 'api/endpoints',
|
||||
data: {
|
||||
Name: name,
|
||||
EndpointCreationType: PortainerEndpointCreationTypes.AzureEnvironment,
|
||||
GroupID: groupId,
|
||||
TagIds: Upload.json(tagIds),
|
||||
AzureApplicationID: applicationId,
|
||||
AzureTenantID: tenantId,
|
||||
AzureAuthenticationKey: authenticationKey,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.uploadLDAPTLSFiles = function (TLSCAFile, TLSCertFile, TLSKeyFile) {
|
||||
var queue = [];
|
||||
|
||||
if (TLSCAFile) {
|
||||
queue.push(uploadFile('api/upload/tls/ca?folder=ldap', TLSCAFile));
|
||||
}
|
||||
if (TLSCertFile) {
|
||||
queue.push(uploadFile('api/upload/tls/cert?folder=ldap', TLSCertFile));
|
||||
}
|
||||
if (TLSKeyFile) {
|
||||
queue.push(uploadFile('api/upload/tls/key?folder=ldap', TLSKeyFile));
|
||||
}
|
||||
|
||||
service.buildImage = function (endpointID, names, file, path) {
|
||||
return Upload.http({
|
||||
url: `api/endpoints/${endpointID}/docker/build`,
|
||||
headers: {
|
||||
'Content-Type': file.type,
|
||||
},
|
||||
data: file,
|
||||
params: {
|
||||
t: names,
|
||||
dockerfile: path,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
transformResponse: function (data) {
|
||||
return jsonObjectsToArrayHandler(data);
|
||||
},
|
||||
});
|
||||
};
|
||||
return $q.all(queue);
|
||||
};
|
||||
|
||||
service.buildImageFromFiles = function (endpointID, names, files) {
|
||||
return Upload.upload({
|
||||
url: `api/endpoints/${endpointID}/docker/build`,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
data: { file: files },
|
||||
params: {
|
||||
t: names,
|
||||
},
|
||||
transformResponse: function (data) {
|
||||
return jsonObjectsToArrayHandler(data);
|
||||
},
|
||||
});
|
||||
};
|
||||
service.uploadTLSFilesForEndpoint = function (endpointID, TLSCAFile, TLSCertFile, TLSKeyFile) {
|
||||
var queue = [];
|
||||
|
||||
service.loadImages = function (file) {
|
||||
var endpointID = EndpointProvider.endpointID();
|
||||
return Upload.http({
|
||||
url: 'api/endpoints/' + endpointID + '/docker/images/load',
|
||||
headers: {
|
||||
'Content-Type': file.type,
|
||||
},
|
||||
data: file,
|
||||
ignoreLoadingBar: true,
|
||||
transformResponse: genericHandler,
|
||||
});
|
||||
};
|
||||
if (TLSCAFile) {
|
||||
queue.push(uploadFile('api/upload/tls/ca?folder=' + endpointID, TLSCAFile));
|
||||
}
|
||||
if (TLSCertFile) {
|
||||
queue.push(uploadFile('api/upload/tls/cert?folder=' + endpointID, TLSCertFile));
|
||||
}
|
||||
if (TLSKeyFile) {
|
||||
queue.push(uploadFile('api/upload/tls/key?folder=' + endpointID, TLSKeyFile));
|
||||
}
|
||||
|
||||
service.createSchedule = function (payload) {
|
||||
return Upload.upload({
|
||||
url: 'api/edge_jobs/create/file',
|
||||
data: {
|
||||
file: payload.File,
|
||||
Name: payload.Name,
|
||||
CronExpression: payload.CronExpression,
|
||||
Image: payload.Image,
|
||||
Endpoints: Upload.json(payload.Endpoints),
|
||||
RetryCount: payload.RetryCount,
|
||||
RetryInterval: payload.RetryInterval,
|
||||
},
|
||||
});
|
||||
};
|
||||
return $q.all(queue);
|
||||
};
|
||||
|
||||
service.uploadBackup = function (file, password) {
|
||||
return Upload.upload({
|
||||
url: 'api/restore',
|
||||
data: {
|
||||
file,
|
||||
password,
|
||||
},
|
||||
});
|
||||
};
|
||||
service.uploadOwnershipVoucher = function (voucherFile) {
|
||||
return Upload.upload({
|
||||
url: 'api/fdo/register',
|
||||
data: {
|
||||
voucher: voucherFile,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createSwarmStack = function (stackName, swarmId, file, env, endpointId) {
|
||||
return Upload.upload({
|
||||
url: `api/stacks/create/swarm/file?endpointId=${endpointId}`,
|
||||
data: {
|
||||
file: file,
|
||||
Name: stackName,
|
||||
SwarmID: swarmId,
|
||||
Env: Upload.json(env),
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createComposeStack = function (stackName, file, env, endpointId) {
|
||||
return Upload.upload({
|
||||
url: `api/stacks/create/standalone/file?endpointId=${endpointId}`,
|
||||
data: {
|
||||
file: file,
|
||||
Name: stackName,
|
||||
Env: Upload.json(env),
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createEdgeStack = function createEdgeStack({ EdgeGroups, envVars, ...payload }, file) {
|
||||
return Upload.upload({
|
||||
url: `api/edge_stacks/create/file`,
|
||||
data: {
|
||||
file,
|
||||
EdgeGroups: Upload.json(EdgeGroups),
|
||||
EnvVars: Upload.json(envVars),
|
||||
...payload,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createCustomTemplate = function createCustomTemplate(data) {
|
||||
return Upload.upload({
|
||||
url: 'api/custom_templates/create/file',
|
||||
data,
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.configureRegistry = function (registryId, registryManagementConfigurationModel) {
|
||||
return Upload.upload({
|
||||
url: 'api/registries/' + registryId + '/configure',
|
||||
data: registryManagementConfigurationModel,
|
||||
});
|
||||
};
|
||||
|
||||
service.createEndpoint = function (
|
||||
name,
|
||||
creationType,
|
||||
URL,
|
||||
PublicURL,
|
||||
groupID,
|
||||
tagIds,
|
||||
TLS,
|
||||
TLSSkipVerify,
|
||||
TLSSkipClientVerify,
|
||||
TLSCAFile,
|
||||
TLSCertFile,
|
||||
TLSKeyFile,
|
||||
checkinInterval
|
||||
) {
|
||||
return Upload.upload({
|
||||
url: 'api/endpoints',
|
||||
data: {
|
||||
Name: name,
|
||||
EndpointCreationType: creationType,
|
||||
URL: URL,
|
||||
PublicURL: PublicURL,
|
||||
GroupID: groupID,
|
||||
TagIds: Upload.json(tagIds),
|
||||
TLS: TLS,
|
||||
TLSSkipVerify: TLSSkipVerify,
|
||||
TLSSkipClientVerify: TLSSkipClientVerify,
|
||||
TLSCACertFile: TLSCAFile,
|
||||
TLSCertFile: TLSCertFile,
|
||||
TLSKeyFile: TLSKeyFile,
|
||||
CheckinInterval: checkinInterval,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.createAzureEndpoint = function (name, applicationId, tenantId, authenticationKey, groupId, tagIds) {
|
||||
return Upload.upload({
|
||||
url: 'api/endpoints',
|
||||
data: {
|
||||
Name: name,
|
||||
EndpointCreationType: PortainerEndpointCreationTypes.AzureEnvironment,
|
||||
GroupID: groupId,
|
||||
TagIds: Upload.json(tagIds),
|
||||
AzureApplicationID: applicationId,
|
||||
AzureTenantID: tenantId,
|
||||
AzureAuthenticationKey: authenticationKey,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
service.uploadLDAPTLSFiles = function (TLSCAFile, TLSCertFile, TLSKeyFile) {
|
||||
var queue = [];
|
||||
|
||||
if (TLSCAFile) {
|
||||
queue.push(uploadFile('api/upload/tls/ca?folder=ldap', TLSCAFile));
|
||||
}
|
||||
if (TLSCertFile) {
|
||||
queue.push(uploadFile('api/upload/tls/cert?folder=ldap', TLSCertFile));
|
||||
}
|
||||
if (TLSKeyFile) {
|
||||
queue.push(uploadFile('api/upload/tls/key?folder=ldap', TLSKeyFile));
|
||||
}
|
||||
|
||||
return $q.all(queue);
|
||||
};
|
||||
|
||||
service.uploadTLSFilesForEndpoint = function (endpointID, TLSCAFile, TLSCertFile, TLSKeyFile) {
|
||||
var queue = [];
|
||||
|
||||
if (TLSCAFile) {
|
||||
queue.push(uploadFile('api/upload/tls/ca?folder=' + endpointID, TLSCAFile));
|
||||
}
|
||||
if (TLSCertFile) {
|
||||
queue.push(uploadFile('api/upload/tls/cert?folder=' + endpointID, TLSCertFile));
|
||||
}
|
||||
if (TLSKeyFile) {
|
||||
queue.push(uploadFile('api/upload/tls/key?folder=' + endpointID, TLSKeyFile));
|
||||
}
|
||||
|
||||
return $q.all(queue);
|
||||
};
|
||||
|
||||
service.uploadOwnershipVoucher = function (voucherFile) {
|
||||
return Upload.upload({
|
||||
url: 'api/fdo/register',
|
||||
data: {
|
||||
voucher: voucherFile,
|
||||
},
|
||||
ignoreLoadingBar: true,
|
||||
});
|
||||
};
|
||||
|
||||
return service;
|
||||
},
|
||||
]);
|
||||
return service;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ import { apiServicesModule } from './api';
|
|||
import { Notifications } from './notifications';
|
||||
import { HttpRequestHelperAngular } from './http-request.helper';
|
||||
import { EndpointProvider } from './endpointProvider';
|
||||
import { AngularToReact } from './angularToReact';
|
||||
|
||||
export default angular
|
||||
.module('portainer.app.services', [apiServicesModule])
|
||||
.factory('Notifications', Notifications)
|
||||
.factory('EndpointProvider', EndpointProvider)
|
||||
.factory('HttpRequestHelper', HttpRequestHelperAngular).name;
|
||||
.factory('HttpRequestHelper', HttpRequestHelperAngular)
|
||||
.factory('AngularToReact', AngularToReact).name;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue