mirror of
https://github.com/portainer/portainer.git
synced 2025-08-09 07:45:22 +02:00
feat(edge/templates): introduce edge specific settings [EE-6276] (#10609)
This commit is contained in:
parent
68950fbb24
commit
e43d076269
42 changed files with 885 additions and 319 deletions
|
@ -45,7 +45,7 @@ export function AuthFieldset({
|
|||
label="Authentication"
|
||||
labelClass="col-sm-3 col-lg-2"
|
||||
name="authentication"
|
||||
checked={value.RepositoryAuthentication}
|
||||
checked={value.RepositoryAuthentication || false}
|
||||
onChange={(value) =>
|
||||
handleChange({ RepositoryAuthentication: value })
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ export function GitForm({
|
|||
<div className="col-sm-12">
|
||||
<SwitchField
|
||||
label="Skip TLS Verification"
|
||||
checked={value.TLSSkipVerify}
|
||||
checked={value.TLSSkipVerify || false}
|
||||
onChange={(value) => handleChange({ TLSSkipVerify: value })}
|
||||
name="TLSSkipVerify"
|
||||
tooltip="Enabling this will allow skipping TLS validation for any self-signed certificate."
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
GitFormModel,
|
||||
RelativePathModel,
|
||||
} from '@/react/portainer/gitops/types';
|
||||
import { GitFormModel } from '@/react/portainer/gitops/types';
|
||||
import { PathSelector } from '@/react/portainer/gitops/ComposePathField/PathSelector';
|
||||
import { dummyGitForm } from '@/react/portainer/gitops/RelativePathFieldset/utils';
|
||||
import { useValidation } from '@/react/portainer/gitops/RelativePathFieldset/useValidation';
|
||||
|
@ -13,6 +10,8 @@ import { TextTip } from '@@/Tip/TextTip';
|
|||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { Input, Select } from '@@/form-components/Input';
|
||||
|
||||
import { RelativePathModel, getPerDevConfigsFilterType } from './types';
|
||||
|
||||
interface Props {
|
||||
value: RelativePathModel;
|
||||
gitModel?: GitFormModel;
|
||||
|
@ -156,7 +155,9 @@ export function RelativePathFieldset({
|
|||
value={value.PerDeviceConfigsMatchType}
|
||||
onChange={(e) =>
|
||||
innerOnChange({
|
||||
PerDeviceConfigsMatchType: e.target.value,
|
||||
PerDeviceConfigsMatchType: getPerDevConfigsFilterType(
|
||||
e.target.value
|
||||
),
|
||||
})
|
||||
}
|
||||
options={[
|
||||
|
@ -186,7 +187,8 @@ export function RelativePathFieldset({
|
|||
value={value.PerDeviceConfigsGroupMatchType}
|
||||
onChange={(e) =>
|
||||
innerOnChange({
|
||||
PerDeviceConfigsGroupMatchType: e.target.value,
|
||||
PerDeviceConfigsGroupMatchType:
|
||||
getPerDevConfigsFilterType(e.target.value),
|
||||
})
|
||||
}
|
||||
options={[
|
||||
|
|
37
app/react/portainer/gitops/RelativePathFieldset/types.ts
Normal file
37
app/react/portainer/gitops/RelativePathFieldset/types.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
export function getDefaultRelativePathModel(): RelativePathModel {
|
||||
return {
|
||||
SupportRelativePath: false,
|
||||
FilesystemPath: '',
|
||||
PerDeviceConfigsGroupMatchType: '',
|
||||
PerDeviceConfigsMatchType: '',
|
||||
PerDeviceConfigsPath: '',
|
||||
SupportPerDeviceConfigs: false,
|
||||
};
|
||||
}
|
||||
|
||||
export interface RelativePathModel {
|
||||
SupportRelativePath: boolean;
|
||||
FilesystemPath: string;
|
||||
SupportPerDeviceConfigs: boolean;
|
||||
PerDeviceConfigsPath: string;
|
||||
PerDeviceConfigsMatchType: PerDevConfigsFilterType;
|
||||
PerDeviceConfigsGroupMatchType: PerDevConfigsFilterType;
|
||||
}
|
||||
|
||||
export type PerDevConfigsFilterType = 'file' | 'dir' | '';
|
||||
|
||||
function isPerDevConfigsFilterType(
|
||||
type: string
|
||||
): type is PerDevConfigsFilterType {
|
||||
return ['file', 'dir'].includes(type);
|
||||
}
|
||||
|
||||
export function getPerDevConfigsFilterType(
|
||||
type: string
|
||||
): PerDevConfigsFilterType {
|
||||
if (isPerDevConfigsFilterType(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { boolean, object, SchemaOf, string } from 'yup';
|
||||
import { boolean, mixed, object, SchemaOf, string } from 'yup';
|
||||
|
||||
import { RelativePathModel } from '@/react/portainer/gitops/types';
|
||||
import { PerDevConfigsFilterType, RelativePathModel } from './types';
|
||||
|
||||
export function relativePathValidation(): SchemaOf<RelativePathModel> {
|
||||
return object({
|
||||
|
@ -18,7 +18,11 @@ export function relativePathValidation(): SchemaOf<RelativePathModel> {
|
|||
then: string().required('Directory is required'),
|
||||
})
|
||||
.default(''),
|
||||
PerDeviceConfigsMatchType: string().oneOf(['', 'file', 'dir']),
|
||||
PerDeviceConfigsGroupMatchType: string().oneOf(['', 'file', 'dir']),
|
||||
PerDeviceConfigsMatchType: mixed<PerDevConfigsFilterType>()
|
||||
.oneOf(['', 'file', 'dir'])
|
||||
.default(''),
|
||||
PerDeviceConfigsGroupMatchType: mixed<PerDevConfigsFilterType>()
|
||||
.oneOf(['', 'file', 'dir'])
|
||||
.default(''),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export type AutoUpdateMechanism = 'Webhook' | 'Interval';
|
||||
export { type RelativePathModel } from './RelativePathFieldset/types';
|
||||
|
||||
export interface AutoUpdateResponse {
|
||||
/* Auto update interval */
|
||||
Interval: string;
|
||||
|
@ -37,7 +39,7 @@ export type AutoUpdateModel = {
|
|||
};
|
||||
|
||||
export type GitCredentialsModel = {
|
||||
RepositoryAuthentication: boolean;
|
||||
RepositoryAuthentication?: boolean;
|
||||
RepositoryUsername?: string;
|
||||
RepositoryPassword?: string;
|
||||
RepositoryGitCredentialID?: number;
|
||||
|
@ -54,13 +56,12 @@ export interface GitFormModel extends GitAuthModel {
|
|||
RepositoryURL: string;
|
||||
RepositoryURLValid?: boolean;
|
||||
ComposeFilePathInRepository: string;
|
||||
RepositoryAuthentication: boolean;
|
||||
RepositoryReferenceName?: string;
|
||||
AdditionalFiles?: string[];
|
||||
|
||||
SaveCredential?: boolean;
|
||||
NewCredentialName?: string;
|
||||
TLSSkipVerify: boolean;
|
||||
TLSSkipVerify?: boolean;
|
||||
|
||||
/**
|
||||
* Auto update
|
||||
|
@ -70,15 +71,6 @@ export interface GitFormModel extends GitAuthModel {
|
|||
AutoUpdate?: AutoUpdateModel;
|
||||
}
|
||||
|
||||
export interface RelativePathModel {
|
||||
SupportRelativePath: boolean;
|
||||
FilesystemPath?: string;
|
||||
SupportPerDeviceConfigs?: boolean;
|
||||
PerDeviceConfigsPath?: string;
|
||||
PerDeviceConfigsMatchType?: string;
|
||||
PerDeviceConfigsGroupMatchType?: string;
|
||||
}
|
||||
|
||||
export function toGitFormModel(response?: RepoConfigResponse): GitFormModel {
|
||||
if (!response) {
|
||||
return {
|
||||
|
|
|
@ -41,7 +41,7 @@ export interface LDAPSettings {
|
|||
|
||||
export interface Pair {
|
||||
name: string;
|
||||
value: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface OpenAMTConfiguration {
|
||||
|
|
|
@ -46,7 +46,7 @@ export function CustomTemplatesListItem({
|
|||
props={{
|
||||
to: '.edit',
|
||||
params: {
|
||||
templateId: template.Id,
|
||||
id: template.Id,
|
||||
},
|
||||
}}
|
||||
icon={Edit}
|
||||
|
|
|
@ -12,7 +12,10 @@ import {
|
|||
import { StackType } from '@/react/common/stacks/types';
|
||||
import { FormValues } from '@/react/edge/templates/custom-templates/CreateView/types';
|
||||
import { VariableDefinition } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField/CustomTemplatesVariablesDefinitionField';
|
||||
import { CustomTemplate } from '@/react/portainer/templates/custom-templates/types';
|
||||
import {
|
||||
CustomTemplate,
|
||||
EdgeTemplateSettings,
|
||||
} from '@/react/portainer/templates/custom-templates/types';
|
||||
|
||||
import { Platform } from '../../types';
|
||||
|
||||
|
@ -41,7 +44,18 @@ function createTemplate({
|
|||
case 'upload':
|
||||
return createTemplateFromFile(values);
|
||||
case 'repository':
|
||||
return createTemplateFromGit({ ...values, ...Git });
|
||||
return createTemplateFromGit({
|
||||
...values,
|
||||
...Git,
|
||||
...(values.EdgeSettings
|
||||
? {
|
||||
EdgeSettings: {
|
||||
...values.EdgeSettings,
|
||||
...values.EdgeSettings.RelativePathSettings,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
default:
|
||||
throw new Error('Unknown method');
|
||||
}
|
||||
|
@ -69,6 +83,7 @@ interface CustomTemplateFromFileContentPayload {
|
|||
Variables: VariableDefinition[];
|
||||
/** Indicates if this template is for Edge Stack. */
|
||||
EdgeTemplate?: boolean;
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
}
|
||||
async function createTemplateFromText(
|
||||
values: CustomTemplateFromFileContentPayload
|
||||
|
@ -103,6 +118,7 @@ interface CustomTemplateFromFilePayload {
|
|||
Variables?: VariableDefinition[];
|
||||
/** Indicates if this template is for Edge Stack. */
|
||||
EdgeTemplate?: boolean;
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
}
|
||||
|
||||
async function createTemplateFromFile(values: CustomTemplateFromFilePayload) {
|
||||
|
@ -121,6 +137,7 @@ async function createTemplateFromFile(values: CustomTemplateFromFilePayload) {
|
|||
File: values.File,
|
||||
Variables: values.Variables,
|
||||
EdgeTemplate: values.EdgeTemplate,
|
||||
EdgeSettings: values.EdgeSettings,
|
||||
});
|
||||
|
||||
const { data } = await axios.post<CustomTemplate>(
|
||||
|
@ -157,7 +174,7 @@ interface CustomTemplateFromGitRepositoryPayload {
|
|||
/** Reference name of a Git repository hosting the Stack file. */
|
||||
RepositoryReferenceName?: string;
|
||||
/** Use basic authentication to clone the Git repository. */
|
||||
RepositoryAuthentication: boolean;
|
||||
RepositoryAuthentication?: boolean;
|
||||
/** Username used in basic authentication when RepositoryAuthentication is true. */
|
||||
RepositoryUsername?: string;
|
||||
/** Password used in basic authentication when RepositoryAuthentication is true. */
|
||||
|
@ -167,11 +184,12 @@ interface CustomTemplateFromGitRepositoryPayload {
|
|||
/** Definitions of variables in the stack file. */
|
||||
Variables: VariableDefinition[];
|
||||
/** Indicates whether to skip SSL verification when cloning the Git repository. */
|
||||
TLSSkipVerify: boolean;
|
||||
TLSSkipVerify?: boolean;
|
||||
/** Indicates if the Kubernetes template is created from a Docker Compose file. */
|
||||
IsComposeFormat?: boolean;
|
||||
/** Indicates if this template is for Edge Stack. */
|
||||
EdgeTemplate?: boolean;
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
}
|
||||
async function createTemplateFromGit(
|
||||
values: CustomTemplateFromGitRepositoryPayload
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
import { StackType } from '@/react/common/stacks/types';
|
||||
import { VariableDefinition } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField/CustomTemplatesVariablesDefinitionField';
|
||||
|
||||
import { CustomTemplate } from '../types';
|
||||
import { CustomTemplate, EdgeTemplateSettings } from '../types';
|
||||
import { Platform } from '../../types';
|
||||
|
||||
import { buildUrl } from './build-url';
|
||||
|
@ -75,6 +75,7 @@ interface CustomTemplateUpdatePayload {
|
|||
IsComposeFormat?: boolean;
|
||||
/** EdgeTemplate indicates if this template purpose for Edge Stack */
|
||||
EdgeTemplate?: boolean;
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
}
|
||||
|
||||
async function updateTemplate(
|
||||
|
|
|
@ -2,9 +2,12 @@ import { UserId } from '@/portainer/users/types';
|
|||
import { StackType } from '@/react/common/stacks/types';
|
||||
|
||||
import { ResourceControlResponse } from '../../access-control/types';
|
||||
import { RepoConfigResponse } from '../../gitops/types';
|
||||
import { RelativePathModel, RepoConfigResponse } from '../../gitops/types';
|
||||
import { VariableDefinition } from '../../custom-templates/components/CustomTemplatesVariablesDefinitionField';
|
||||
import { Platform } from '../types';
|
||||
import { RegistryId } from '../../registries/types';
|
||||
import { getDefaultRelativePathModel } from '../../gitops/RelativePathFieldset/types';
|
||||
import { isBE } from '../../feature-flags/feature-flags.service';
|
||||
|
||||
export type CustomTemplate = {
|
||||
Id: number;
|
||||
|
@ -87,16 +90,38 @@ export type CustomTemplate = {
|
|||
|
||||
/** EdgeTemplate indicates if this template purpose for Edge Stack */
|
||||
EdgeTemplate: boolean;
|
||||
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
};
|
||||
|
||||
/**
|
||||
* EdgeTemplateSettings represents the configuration of a custom template for Edge
|
||||
*/
|
||||
export type EdgeTemplateSettings = {
|
||||
PrePullImage: boolean;
|
||||
|
||||
RetryDeploy: boolean;
|
||||
|
||||
PrivateRegistryId: RegistryId | undefined;
|
||||
|
||||
RelativePathSettings: RelativePathModel;
|
||||
};
|
||||
|
||||
export type CustomTemplateFileContent = {
|
||||
FileContent: string;
|
||||
};
|
||||
|
||||
export const CustomTemplateKubernetesType = 3;
|
||||
export const CustomTemplateKubernetesType = StackType.Kubernetes;
|
||||
|
||||
export enum Types {
|
||||
SWARM = 1,
|
||||
STANDALONE,
|
||||
KUBERNETES,
|
||||
export function getDefaultEdgeTemplateSettings() {
|
||||
if (!isBE) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
PrePullImage: false,
|
||||
RetryDeploy: false,
|
||||
PrivateRegistryId: undefined,
|
||||
RelativePathSettings: getDefaultRelativePathModel(),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue