mirror of
https://github.com/portainer/portainer.git
synced 2025-07-23 07:19:41 +02:00
feat(app): limit the docker API version supported by the frontend (#12295)
Some checks failed
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled
Some checks failed
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled
This commit is contained in:
parent
8cbd23c059
commit
ac5491e864
227 changed files with 4702 additions and 3411 deletions
|
@ -3,13 +3,13 @@ import { ResourceControlOwnership } from '@/react/portainer/access-control/types
|
|||
import { UserId } from '@/portainer/users/types';
|
||||
import { getDefaultImageConfig } from '@/react/portainer/registries/utils/getImageConfig';
|
||||
|
||||
import { ContainerResponse } from '../../queries/container';
|
||||
import { ContainerDetailsResponse } from '../../queries/useContainer';
|
||||
|
||||
import { toViewModel as toPortsMappingViewModel } from './PortsMappingField.viewModel';
|
||||
import { Values } from './BaseForm';
|
||||
|
||||
export function toViewModel(
|
||||
config: ContainerResponse,
|
||||
config: ContainerDetailsResponse,
|
||||
isPureAdmin: boolean,
|
||||
currentUserId: UserId,
|
||||
nodeName: string,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { ContainerJSON } from '@/react/docker/containers/queries/container';
|
||||
import { ContainerDetailsJSON } from '@/react/docker/containers/queries/useContainer';
|
||||
|
||||
import { capabilities } from './types';
|
||||
import { Values } from './CapabilitiesTab';
|
||||
|
||||
export function toViewModel(config: ContainerJSON): Values {
|
||||
export function toViewModel(config: ContainerDetailsJSON): Values {
|
||||
const { CapAdd, CapDrop } = getDefaults(config);
|
||||
|
||||
const missingCaps = capabilities
|
||||
|
@ -15,7 +15,7 @@ export function toViewModel(config: ContainerJSON): Values {
|
|||
|
||||
return [...CapAdd, ...missingCaps];
|
||||
|
||||
function getDefaults(config: ContainerJSON) {
|
||||
function getDefaults(config: ContainerDetailsJSON) {
|
||||
return {
|
||||
CapAdd: config.HostConfig?.CapAdd || [],
|
||||
CapDrop: config.HostConfig?.CapDrop || [],
|
||||
|
|
|
@ -2,7 +2,7 @@ import { HostConfig } from 'docker-types/generated/1.41';
|
|||
|
||||
import { commandArrayToString } from '@/docker/helpers/containers';
|
||||
|
||||
import { ContainerJSON } from '../../queries/container';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
import { ConsoleConfig, ConsoleSetting } from './ConsoleSettings';
|
||||
import { LogConfig } from './LoggerConfig';
|
||||
|
@ -19,7 +19,7 @@ export function getDefaultViewModel(): Values {
|
|||
};
|
||||
}
|
||||
|
||||
export function toViewModel(config: ContainerJSON): Values {
|
||||
export function toViewModel(config: ContainerDetailsJSON): Values {
|
||||
if (!config.Config) {
|
||||
return getDefaultViewModel();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import { InformationPanel } from '@@/InformationPanel';
|
|||
import { TextTip } from '@@/Tip/TextTip';
|
||||
import { HelpLink } from '@@/HelpLink';
|
||||
|
||||
import { useContainers } from '../queries/containers';
|
||||
import { useContainers } from '../queries/useContainers';
|
||||
import { useSystemLimits, useIsWindows } from '../../proxy/queries/useInfo';
|
||||
|
||||
import { useCreateOrReplaceMutation } from './useCreateMutation';
|
||||
|
@ -149,7 +149,21 @@ function CreateForm() {
|
|||
const config = toRequest(values, registry, hideCapabilities);
|
||||
|
||||
return mutation.mutate(
|
||||
{ config, environment, values, registry, oldContainer, extraNetworks },
|
||||
{
|
||||
config,
|
||||
environment,
|
||||
values: {
|
||||
accessControl: values.accessControl,
|
||||
imageName: values.image.image,
|
||||
name: values.name,
|
||||
alwaysPull: values.alwaysPull,
|
||||
enableWebhook: values.enableWebhook,
|
||||
nodeName: values.nodeName,
|
||||
},
|
||||
registry,
|
||||
oldContainer,
|
||||
extraNetworks,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
sendAnalytics(values, registry);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { parseArrayOfStrings } from '@@/form-components/EnvironmentVariablesFieldset/utils';
|
||||
|
||||
import { ContainerJSON } from '../../queries/container';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
export function getDefaultViewModel() {
|
||||
return [];
|
||||
}
|
||||
|
||||
export function toViewModel(container: ContainerJSON) {
|
||||
export function toViewModel(container: ContainerDetailsJSON) {
|
||||
return parseArrayOfStrings(container.Config?.Env);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { ContainerJSON } from '../../queries/container';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
import { Values } from './types';
|
||||
|
||||
export function toViewModel(config: ContainerJSON): Values {
|
||||
export function toViewModel(config: ContainerDetailsJSON): Values {
|
||||
if (!config || !config.Config || !config.Config.Labels) {
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
|||
|
||||
import { Option, PortainerSelect } from '@@/form-components/PortainerSelect';
|
||||
|
||||
import { useContainers } from '../../queries/containers';
|
||||
import { useContainers } from '../../queries/useContainers';
|
||||
import { ContainerStatus } from '../../types';
|
||||
|
||||
export function ContainerSelector({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { DockerNetwork } from '@/react/docker/networks/types';
|
||||
|
||||
import { ContainerJSON } from '../../queries/container';
|
||||
import { DockerContainer } from '../../types';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
import { ContainerListViewModel } from '../../types';
|
||||
|
||||
import { CONTAINER_MODE, Values } from './types';
|
||||
|
||||
|
@ -22,9 +22,9 @@ export function getDefaultViewModel(isWindows: boolean) {
|
|||
}
|
||||
|
||||
export function toViewModel(
|
||||
config: ContainerJSON,
|
||||
config: ContainerDetailsJSON,
|
||||
networks: Array<DockerNetwork>,
|
||||
runningContainers: Array<DockerContainer> = []
|
||||
runningContainers: Array<ContainerListViewModel> = []
|
||||
): Values {
|
||||
const dns = config.HostConfig?.Dns;
|
||||
const [primaryDns = '', secondaryDns = ''] = dns || [];
|
||||
|
@ -62,9 +62,9 @@ export function toViewModel(
|
|||
}
|
||||
|
||||
function getNetworkMode(
|
||||
config: ContainerJSON,
|
||||
config: ContainerDetailsJSON,
|
||||
networks: Array<DockerNetwork>,
|
||||
runningContainers: Array<DockerContainer> = []
|
||||
runningContainers: Array<ContainerListViewModel> = []
|
||||
) {
|
||||
let networkMode = config.HostConfig?.NetworkMode || '';
|
||||
if (!networkMode) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useCurrentStateAndParams } from '@uirouter/react';
|
|||
import { useState } from 'react';
|
||||
import { FormikHelpers } from 'formik/dist/types';
|
||||
|
||||
import { invalidateContainer } from '@/react/docker/containers/queries/container';
|
||||
import { invalidateContainer } from '@/react/docker/containers/queries/useContainer';
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
import { mutationOptions, withError } from '@/react-tools/react-query';
|
||||
import { useSystemLimits } from '@/react/docker/proxy/queries/useInfo';
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ContainerJSON } from '../../queries/container';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
import { toDevicesViewModel } from './DevicesField';
|
||||
import { gpuFieldsetUtils } from './GpuFieldset';
|
||||
import { toViewModelCpu, toViewModelMemory } from './memory-utils';
|
||||
import { Values } from './ResourcesTab';
|
||||
|
||||
export function toViewModel(config: ContainerJSON): Values {
|
||||
export function toViewModel(config: ContainerDetailsJSON): Values {
|
||||
return {
|
||||
runtime: {
|
||||
privileged: config.HostConfig?.Privileged || false,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { ContainerJSON } from '../../queries/container';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
import { RestartPolicy } from './types';
|
||||
|
||||
export function toViewModel(config: ContainerJSON): RestartPolicy {
|
||||
export function toViewModel(config: ContainerDetailsJSON): RestartPolicy {
|
||||
switch (config.HostConfig?.RestartPolicy?.Name) {
|
||||
case 'always':
|
||||
return RestartPolicy.Always;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { ContainerJSON } from '../../queries/container';
|
||||
import { ContainerDetailsJSON } from '../../queries/useContainer';
|
||||
|
||||
import { VolumeType, Values } from './types';
|
||||
|
||||
export function toViewModel(config: ContainerJSON): Values {
|
||||
export function toViewModel(config: ContainerDetailsJSON): Values {
|
||||
return Object.values(config.Mounts || {}).map((mount) => ({
|
||||
type: (mount.Type || 'volume') as VolumeType,
|
||||
name: mount.Name || mount.Source || '',
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { RawAxiosRequestHeaders } from 'axios';
|
||||
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
import {
|
||||
|
@ -32,12 +31,13 @@ import {
|
|||
renameContainer,
|
||||
startContainer,
|
||||
stopContainer,
|
||||
urlBuilder,
|
||||
} from '../containers.service';
|
||||
import { PortainerResponse } from '../../types';
|
||||
import { connectContainer } from '../../networks/queries/useConnectContainer';
|
||||
import { DockerContainer } from '../types';
|
||||
import { connectContainer } from '../../networks/queries/useConnectContainerMutation';
|
||||
import { ContainerListViewModel } from '../types';
|
||||
import { queryKeys } from '../queries/query-keys';
|
||||
import { withAgentTargetHeader } from '../../proxy/queries/utils';
|
||||
import { buildDockerProxyUrl } from '../../proxy/queries/buildDockerProxyUrl';
|
||||
|
||||
import { CreateContainerRequest } from './types';
|
||||
import { Values } from './useInitialValues';
|
||||
|
@ -62,13 +62,20 @@ export function useCreateOrReplaceMutation() {
|
|||
|
||||
interface CreateOptions {
|
||||
config: CreateContainerRequest;
|
||||
values: Values;
|
||||
values: {
|
||||
name: Values['name'];
|
||||
imageName: string;
|
||||
accessControl: Values['accessControl'];
|
||||
nodeName?: Values['nodeName'];
|
||||
alwaysPull?: Values['alwaysPull'];
|
||||
enableWebhook?: Values['enableWebhook'];
|
||||
};
|
||||
registry?: Registry;
|
||||
environment: Environment;
|
||||
}
|
||||
|
||||
interface ReplaceOptions extends CreateOptions {
|
||||
oldContainer: DockerContainer;
|
||||
oldContainer: ContainerListViewModel;
|
||||
extraNetworks: Array<ExtraNetwork>;
|
||||
}
|
||||
|
||||
|
@ -90,14 +97,14 @@ async function create({
|
|||
}: CreateOptions) {
|
||||
await pullImageIfNeeded(
|
||||
environment.Id,
|
||||
values.alwaysPull || false,
|
||||
values.imageName,
|
||||
values.nodeName,
|
||||
values.alwaysPull,
|
||||
values.image.image,
|
||||
registry
|
||||
);
|
||||
|
||||
const containerResponse = await createAndStart(
|
||||
environment,
|
||||
environment.Id,
|
||||
config,
|
||||
values.name,
|
||||
values.nodeName
|
||||
|
@ -106,8 +113,8 @@ async function create({
|
|||
await applyContainerSettings(
|
||||
containerResponse.Id,
|
||||
environment,
|
||||
values.enableWebhook,
|
||||
values.accessControl,
|
||||
values.enableWebhook,
|
||||
containerResponse.Portainer?.ResourceControl,
|
||||
registry
|
||||
);
|
||||
|
@ -123,37 +130,38 @@ async function replace({
|
|||
}: ReplaceOptions) {
|
||||
await pullImageIfNeeded(
|
||||
environment.Id,
|
||||
values.alwaysPull || false,
|
||||
values.imageName,
|
||||
values.nodeName,
|
||||
values.alwaysPull,
|
||||
values.image.image,
|
||||
registry
|
||||
);
|
||||
|
||||
const containerResponse = await renameAndCreate(
|
||||
environment,
|
||||
values,
|
||||
environment.Id,
|
||||
values.name,
|
||||
oldContainer,
|
||||
config
|
||||
config,
|
||||
values.nodeName
|
||||
);
|
||||
|
||||
await applyContainerSettings(
|
||||
containerResponse.Id,
|
||||
environment,
|
||||
values.enableWebhook,
|
||||
values.accessControl,
|
||||
values.enableWebhook,
|
||||
containerResponse.Portainer?.ResourceControl,
|
||||
registry
|
||||
);
|
||||
|
||||
await connectToExtraNetworks(
|
||||
environment.Id,
|
||||
values.nodeName,
|
||||
containerResponse.Id,
|
||||
extraNetworks
|
||||
extraNetworks,
|
||||
values.nodeName
|
||||
);
|
||||
|
||||
await removeContainer(environment.Id, oldContainer.Id, {
|
||||
nodeName: values.nodeName,
|
||||
nodeName: oldContainer.NodeName,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -162,33 +170,33 @@ async function replace({
|
|||
* on any failure, it will rename the old container to its original name
|
||||
*/
|
||||
async function renameAndCreate(
|
||||
environment: Environment,
|
||||
values: Values,
|
||||
oldContainer: DockerContainer,
|
||||
config: CreateContainerRequest
|
||||
environmentId: EnvironmentId,
|
||||
name: string,
|
||||
oldContainer: ContainerListViewModel,
|
||||
config: CreateContainerRequest,
|
||||
nodeName?: string
|
||||
) {
|
||||
let renamed = false;
|
||||
try {
|
||||
await stopContainerIfNeeded(environment.Id, values.nodeName, oldContainer);
|
||||
await stopContainerIfNeeded(
|
||||
environmentId,
|
||||
oldContainer,
|
||||
oldContainer.NodeName
|
||||
);
|
||||
|
||||
await renameContainer(
|
||||
environment.Id,
|
||||
environmentId,
|
||||
oldContainer.Id,
|
||||
`${oldContainer.Names[0]}-old`,
|
||||
{ nodeName: values.nodeName }
|
||||
{ nodeName: oldContainer.NodeName }
|
||||
);
|
||||
renamed = true;
|
||||
|
||||
return await createAndStart(
|
||||
environment,
|
||||
config,
|
||||
values.name,
|
||||
values.nodeName
|
||||
);
|
||||
return await createAndStart(environmentId, config, name, nodeName);
|
||||
} catch (e) {
|
||||
if (renamed) {
|
||||
await renameContainer(environment.Id, oldContainer.Id, values.name, {
|
||||
nodeName: values.nodeName,
|
||||
await renameContainer(environmentId, oldContainer.Id, name, {
|
||||
nodeName: oldContainer.NodeName,
|
||||
});
|
||||
}
|
||||
throw e;
|
||||
|
@ -201,8 +209,8 @@ async function renameAndCreate(
|
|||
async function applyContainerSettings(
|
||||
containerId: string,
|
||||
environment: Environment,
|
||||
enableWebhook: boolean,
|
||||
accessControl: AccessControlFormData,
|
||||
enableWebhook?: boolean,
|
||||
resourceControl?: ResourceControlResponse,
|
||||
registry?: Registry
|
||||
) {
|
||||
|
@ -224,15 +232,15 @@ async function applyContainerSettings(
|
|||
* on failure, it will remove the new container
|
||||
*/
|
||||
async function createAndStart(
|
||||
environment: Environment,
|
||||
environmentId: EnvironmentId,
|
||||
config: CreateContainerRequest,
|
||||
name: string,
|
||||
nodeName: string
|
||||
name?: string,
|
||||
nodeName?: string
|
||||
) {
|
||||
let containerId = '';
|
||||
try {
|
||||
const containerResponse = await createContainer(
|
||||
environment.Id,
|
||||
environmentId,
|
||||
config,
|
||||
name,
|
||||
{
|
||||
|
@ -242,11 +250,11 @@ async function createAndStart(
|
|||
|
||||
containerId = containerResponse.Id;
|
||||
|
||||
await startContainer(environment.Id, containerResponse.Id, { nodeName });
|
||||
await startContainer(environmentId, containerResponse.Id, { nodeName });
|
||||
return containerResponse;
|
||||
} catch (e) {
|
||||
if (containerId) {
|
||||
await removeContainer(environment.Id, containerId, {
|
||||
await removeContainer(environmentId, containerId, {
|
||||
nodeName,
|
||||
});
|
||||
}
|
||||
|
@ -257,9 +265,9 @@ async function createAndStart(
|
|||
|
||||
async function pullImageIfNeeded(
|
||||
environmentId: EnvironmentId,
|
||||
nodeName: string,
|
||||
pull: boolean,
|
||||
image: string,
|
||||
nodeName?: string,
|
||||
registry?: Registry
|
||||
) {
|
||||
if (!pull) {
|
||||
|
@ -282,16 +290,10 @@ async function createContainer(
|
|||
{ nodeName }: { nodeName?: string } = {}
|
||||
) {
|
||||
try {
|
||||
const headers: RawAxiosRequestHeaders = {};
|
||||
|
||||
if (nodeName) {
|
||||
headers['X-PortainerAgent-Target'] = nodeName;
|
||||
}
|
||||
|
||||
const { data } = await axios.post<
|
||||
PortainerResponse<{ Id: string; Warnings: Array<string> }>
|
||||
>(urlBuilder(environmentId, undefined, 'create'), config, {
|
||||
headers,
|
||||
>(buildDockerProxyUrl(environmentId, 'containers', 'create'), config, {
|
||||
headers: { ...withAgentTargetHeader(nodeName) },
|
||||
params: { name },
|
||||
});
|
||||
|
||||
|
@ -322,9 +324,9 @@ async function createContainerWebhook(
|
|||
|
||||
function connectToExtraNetworks(
|
||||
environmentId: EnvironmentId,
|
||||
nodeName: string,
|
||||
containerId: string,
|
||||
extraNetworks: Array<ExtraNetwork>
|
||||
extraNetworks: Array<ExtraNetwork>,
|
||||
nodeName?: string
|
||||
) {
|
||||
if (!extraNetworks) {
|
||||
return null;
|
||||
|
@ -345,8 +347,8 @@ function connectToExtraNetworks(
|
|||
|
||||
function stopContainerIfNeeded(
|
||||
environmentId: EnvironmentId,
|
||||
nodeName: string,
|
||||
container: DockerContainer
|
||||
container: ContainerListViewModel,
|
||||
nodeName?: string
|
||||
) {
|
||||
if (container.State !== 'running' || !container.Id) {
|
||||
return null;
|
||||
|
|
|
@ -43,8 +43,8 @@ import { useEnvironmentRegistries } from '@/react/portainer/environments/queries
|
|||
import { EnvVarValues } from '@@/form-components/EnvironmentVariablesFieldset';
|
||||
|
||||
import { useNetworksForSelector } from '../components/NetworkSelector';
|
||||
import { useContainers } from '../queries/containers';
|
||||
import { useContainer } from '../queries/container';
|
||||
import { useContainers } from '../queries/useContainers';
|
||||
import { useContainer } from '../queries/useContainer';
|
||||
|
||||
export interface Values extends BaseFormValues {
|
||||
commands: CommandsTabValues;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue