1
0
Fork 0
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:
Chaim Lev-Ari 2023-11-15 14:43:18 +02:00 committed by GitHub
parent 68950fbb24
commit e43d076269
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 885 additions and 319 deletions

View file

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

View file

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

View file

@ -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={[

View 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 '';
}

View file

@ -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(''),
});
}

View file

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

View file

@ -41,7 +41,7 @@ export interface LDAPSettings {
export interface Pair {
name: string;
value: string;
value?: string;
}
export interface OpenAMTConfiguration {

View file

@ -46,7 +46,7 @@ export function CustomTemplatesListItem({
props={{
to: '.edit',
params: {
templateId: template.Id,
id: template.Id,
},
}}
icon={Edit}

View file

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

View file

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

View file

@ -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(),
};
}