1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 12:25:22 +02:00

feature(kubernetes): stack name made optional & add toggle to disable stack in kubernetes [EE-6170] (#10436)

This commit is contained in:
Prabhat Khera 2023-10-16 14:08:06 +13:00 committed by GitHub
parent 44d66cc633
commit 7840e0bfe1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 305 additions and 47 deletions

View file

@ -0,0 +1,84 @@
import { InsightsBox } from '@@/InsightsBox';
import { Link } from '@@/Link';
import { TextTip } from '@@/Tip/TextTip';
import { Tooltip } from '@@/Tip/Tooltip';
type Props = {
stackName: string;
setStackName: (name: string) => void;
isAdmin?: boolean;
};
export function StackName({ stackName, setStackName, isAdmin = false }: Props) {
const tooltip = (
<>
You may specify a stack name to label resources that you want to group.
This includes Deployments, DaemonSets, StatefulSets and Pods.
{isAdmin && (
<>
<br />
You can leave the stack name empty, or even turn off Kubernetes Stacks
functionality entirely via{' '}
<Link to="portainer.settings" target="_blank">
Kubernetes Settings
</Link>
.
</>
)}
</>
);
const insightsBoxContent = (
<>
The stack field below was previously labelled &apos;Name&apos; but, in
fact, it&apos;s always been the stack name (hence the relabelling).
{isAdmin && (
<>
<br />
Kubernetes Stacks functionality can be turned off entirely via{' '}
<Link to="portainer.settings" target="_blank">
Kubernetes Settings
</Link>
.
</>
)}
</>
);
return (
<>
<div className="w-fit mb-4">
<InsightsBox
type="slim"
header="Stack"
content={insightsBoxContent}
insightCloseId="k8s-stacks-name"
/>
</div>
<TextTip className="mb-4" color="blue">
Enter or select a &apos;stack&apos; name to group multiple deployments
together, or else leave empty to ignore.
</TextTip>
<div className="form-group">
<label
htmlFor="stack_name"
className="col-lg-2 col-sm-3 control-label text-left"
>
Stack
<Tooltip message={tooltip} setHtmlMessage />
</label>
<div className="col-sm-8">
<input
type="text"
className="form-control"
defaultValue={stackName}
onChange={(e) => setStackName(e.target.value)}
id="stack_name"
placeholder="myStack"
/>
</div>
</div>
</>
);
}

View file

@ -6,6 +6,8 @@ import { useCurrentStateAndParams } from '@uirouter/react';
import { Authorized } from '@/react/hooks/useUser';
import { notifyError, notifySuccess } from '@/portainer/services/notifications';
import { usePublicSettings } from '@/react/portainer/settings/queries';
import { GlobalDeploymentOptions } from '@/react/portainer/settings/types';
import { DetailsTable } from '@@/DetailsTable';
import { Badge } from '@@/Badge';
@ -69,6 +71,11 @@ export function ApplicationSummaryWidget() {
setApplicationNoteFormValues(applicationNote || '');
}, [applicationNote]);
const globalDeploymentOptionsQuery =
usePublicSettings<GlobalDeploymentOptions>({
select: (settings) => settings.GlobalDeploymentOptions,
});
const failedCreateCondition = application?.status?.conditions?.find(
(condition) => condition.reason === 'FailedCreate'
);
@ -117,13 +124,17 @@ export function ApplicationSummaryWidget() {
</div>
</td>
</tr>
<tr>
<td>Stack</td>
<td data-cy="k8sAppDetail-stackName">
{application?.metadata?.labels?.[appStackNameLabel] ||
'-'}
</td>
</tr>
{globalDeploymentOptionsQuery.data &&
!globalDeploymentOptionsQuery.data
.hideStacksFunctionality && (
<tr>
<td>Stack</td>
<td data-cy="k8sAppDetail-stackName">
{application?.metadata?.labels?.[appStackNameLabel] ||
'-'}
</td>
</tr>
)}
<tr>
<td>Namespace</td>
<td>

View file

@ -8,6 +8,7 @@ import {
StatusType as EdgeStackStatusType,
} from '@/react/edge/edge-stacks/types';
import { getPublicSettings } from '../../settings/settings.service';
import type {
Environment,
EnvironmentId,
@ -131,6 +132,20 @@ export async function snapshotEndpoints() {
}
}
export async function getDeploymentOptions(environmentId: EnvironmentId) {
const publicSettings = await getPublicSettings();
const endpoint = await getEndpoint(environmentId);
if (
publicSettings.GlobalDeploymentOptions.perEnvOverride &&
endpoint.DeploymentOptions?.overrideGlobalOptions
) {
return endpoint.DeploymentOptions;
}
return publicSettings.GlobalDeploymentOptions;
}
export async function snapshotEndpoint(id: EnvironmentId) {
try {
await axios.post<void>(buildUrl(id, 'snapshot'));

View file

@ -14,6 +14,7 @@ export function DeploymentOptionsSection() {
values: { globalDeploymentOptions: values },
setFieldValue,
} = useFormikContext<FormValues>();
const limitedFeature = isLimitedToBE(FeatureId.ENFORCE_DEPLOYMENT_OPTIONS);
return (
<FormSection title="Deployment Options">
@ -74,6 +75,24 @@ export function DeploymentOptionsSection() {
)}
<KubeNoteMinimumCharacters />
<div className="form-group">
<div className="col-sm-12">
<SwitchField
label="Allow stacks functionality with Kubernetes environments"
checked={!values.hideStacksFunctionality}
onChange={(value) =>
setFieldValue(
'globalDeploymentOptions.hideStacksFunctionality',
!value
)
}
name="toggle_stacksFunctionality"
labelClass="col-sm-3 col-lg-2"
tooltip="This allows you to group your applications/workloads into a single stack, and then view or delete an entire stack. If disabled, stacks functionality will not show in the UI."
/>
</div>
</div>
</FormSection>
);

View file

@ -29,13 +29,17 @@ export function KubeSettingsPanel() {
const initialValues: FormValues = {
helmRepositoryUrl: settingsQuery.data.HelmRepositoryURL || '',
kubeconfigExpiry: settingsQuery.data.KubeconfigExpiry || '0',
globalDeploymentOptions: settingsQuery.data.GlobalDeploymentOptions || {
requireNoteOnApplications: false,
minApplicationNoteLength: 0,
hideAddWithForm: false,
hideFileUpload: false,
hideWebEditor: false,
perEnvOverride: false,
globalDeploymentOptions: {
...{
requireNoteOnApplications: false,
minApplicationNoteLength: 0,
hideAddWithForm: false,
hideFileUpload: false,
hideWebEditor: false,
perEnvOverride: false,
hideStacksFunctionality: false,
},
...settingsQuery.data.GlobalDeploymentOptions,
},
};

View file

@ -8,5 +8,6 @@ export interface FormValues {
hideFileUpload: boolean;
requireNoteOnApplications: boolean;
minApplicationNoteLength: number;
hideStacksFunctionality: boolean;
};
}

View file

@ -16,6 +16,7 @@ export function validation(): SchemaOf<FormValues> {
hideWebEditor: boolean().required(),
hideFileUpload: boolean().required(),
requireNoteOnApplications: boolean().required(),
hideStacksFunctionality: boolean().required(),
minApplicationNoteLength: number()
.typeError('Must be a number')
.default(0)

View file

@ -145,7 +145,7 @@ export interface Settings {
};
}
interface GlobalDeploymentOptions {
export interface GlobalDeploymentOptions {
/** Hide manual deploy forms in portainer */
hideAddWithForm: boolean;
/** Configure this per environment or globally */
@ -157,6 +157,8 @@ interface GlobalDeploymentOptions {
/** Make note on application add/edit screen required */
requireNoteOnApplications: boolean;
minApplicationNoteLength: number;
hideStacksFunctionality: boolean;
}
export interface PublicSettingsResponse {