mirror of
https://github.com/portainer/portainer.git
synced 2025-08-04 13:25:26 +02:00
feature(kubernetes): stack name made optional & add toggle to disable stack in kubernetes [EE-6170] (#10436)
This commit is contained in:
parent
44d66cc633
commit
7840e0bfe1
29 changed files with 305 additions and 47 deletions
|
@ -25,6 +25,7 @@
|
|||
is-apps-loading="ctrl.state.isAppsLoading"
|
||||
is-system-resources="ctrl.state.isSystemResources"
|
||||
set-system-resources="(ctrl.setSystemResources)"
|
||||
hide-stacks-functionality="ctrl.deploymentOptions.hideStacksFunctionality"
|
||||
>
|
||||
</kubernetes-applications-datatable>
|
||||
</uib-tab>
|
||||
|
|
|
@ -6,6 +6,7 @@ import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelpe
|
|||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesPortainerApplicationStackNameLabel } from 'Kubernetes/models/application/models';
|
||||
import { confirmDelete } from '@@/modals/confirm';
|
||||
import { getDeploymentOptions } from '@/react/portainer/environments/environment.service';
|
||||
|
||||
class KubernetesApplicationsController {
|
||||
/* @ngInject */
|
||||
|
@ -196,6 +197,8 @@ class KubernetesApplicationsController {
|
|||
isSystemResources: undefined,
|
||||
};
|
||||
|
||||
this.deploymentOptions = await getDeploymentOptions();
|
||||
|
||||
this.user = this.Authentication.getUserDetails();
|
||||
this.state.namespaces = await this.KubernetesNamespaceService.get();
|
||||
|
||||
|
|
|
@ -99,6 +99,54 @@
|
|||
</div>
|
||||
<!-- #endregion -->
|
||||
|
||||
<!-- #region STACK -->
|
||||
<div class="form-group" ng-if="!ctrl.deploymentOptions.hideStacksFunctionality && ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.APPLICATION_FORM">
|
||||
<div class="col-sm-12 small text-muted vertical-center">
|
||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||
Portainer can automatically bundle multiple applications inside a stack. Enter a name of a new stack or select an existing stack in the list. Leave empty to use
|
||||
the application name.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-if="!ctrl.deploymentOptions.hideStacksFunctionality && ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.APPLICATION_FORM">
|
||||
<label for="stack_name" class="col-sm-3 col-lg-2 control-label text-left">
|
||||
Stack
|
||||
<portainer-tooltip
|
||||
ng-if="!ctrl.isAdmin"
|
||||
message="'The stack field below was previously labelled \'Name\' but, in
|
||||
fact, it\'s always been the stack name (hence the relabelling).'"
|
||||
class-name="'[&>span]:!text-left'"
|
||||
set-html-message="true"
|
||||
>
|
||||
</portainer-tooltip>
|
||||
<portainer-tooltip
|
||||
ng-if="ctrl.isAdmin"
|
||||
message="'The stack field below was previously labelled \'Name\' but, in
|
||||
fact, it\'s always been the stack name (hence the relabelling).<br/>
|
||||
Kubernetes Stacks functionality can be turned off entirely via
|
||||
<a href=\'/#!/settings\' target=\'_blank\'>
|
||||
Kubernetes Settings
|
||||
</a>.'"
|
||||
class-name="'[&>span]:!text-left'"
|
||||
set-html-message="true"
|
||||
>
|
||||
</portainer-tooltip>
|
||||
</label>
|
||||
<div class="col-sm-8">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="myStack"
|
||||
ng-model="ctrl.formValues.StackName"
|
||||
name="stack_name"
|
||||
uib-typeahead="stack for stack in ctrl.stacks | filter:$viewValue | limitTo:7"
|
||||
typeahead-min-length="0"
|
||||
data-cy="k8sAppCreate-stackName"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
|
||||
<!-- #region Git repository -->
|
||||
<kubernetes-redeploy-app-git-form
|
||||
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.GIT"
|
||||
|
@ -218,7 +266,7 @@
|
|||
|
||||
<div ng-if="ctrl.formValues.ResourcePool">
|
||||
<!-- #region STACK -->
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="!ctrl.deploymentOptions.hideStacksFunctionality">
|
||||
<div class="col-sm-12 small text-muted vertical-center">
|
||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||
Portainer can automatically bundle multiple applications inside a stack. Enter a name of a new stack or select an existing stack in the list. Leave empty to
|
||||
|
@ -226,7 +274,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" ng-if="!ctrl.deploymentOptions.hideStacksFunctionality">
|
||||
<label for="stack_name" class="col-sm-3 col-lg-2 control-label text-left">Stack</label>
|
||||
<div class="col-sm-8">
|
||||
<input
|
||||
|
@ -1401,7 +1449,7 @@
|
|||
class="btn btn-sm btn-primary"
|
||||
ng-click="ctrl.updateApplicationViaWebEditor()"
|
||||
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.CONTENT || ctrl.state.updateWebEditorInProgress"
|
||||
ng-disabled="!kubernetesApplicationCreationForm.$valid || !ctrl.state.isEditorDirty || ctrl.state.updateWebEditorInProgress"
|
||||
ng-disabled="kubernetesApplicationCreationForm.$valid && !ctrl.state.isEditorDirty && ctrl.savedFormValues.StackName === ctrl.formValues.StackName || ctrl.state.updateWebEditorInProgress"
|
||||
style="margin-top: 7px; margin-left: 0"
|
||||
button-spinner="ctrl.state.updateWebEditorInProgress"
|
||||
>
|
||||
|
|
|
@ -5,6 +5,7 @@ import * as JsonPatch from 'fast-json-patch';
|
|||
import { RegistryTypes } from '@/portainer/models/registryTypes';
|
||||
import { getServices } from '@/react/kubernetes/networks/services/service';
|
||||
import { KubernetesConfigurationKinds } from 'Kubernetes/models/configuration/models';
|
||||
import { getGlobalDeploymentOptions } from '@/react/portainer/settings/settings.service';
|
||||
|
||||
import {
|
||||
KubernetesApplicationDataAccessPolicies,
|
||||
|
@ -196,7 +197,10 @@ class KubernetesCreateApplicationController {
|
|||
}
|
||||
|
||||
this.state.updateWebEditorInProgress = true;
|
||||
await this.StackService.updateKubeStack({ EndpointId: this.endpoint.Id, Id: this.application.StackId }, { stackFile: this.stackFileContent });
|
||||
await this.StackService.updateKubeStack(
|
||||
{ EndpointId: this.endpoint.Id, Id: this.application.StackId },
|
||||
{ stackFile: this.stackFileContent, stackName: this.formValues.StackName }
|
||||
);
|
||||
this.state.isEditorDirty = false;
|
||||
await this.$state.reload(this.$state.current);
|
||||
} catch (err) {
|
||||
|
@ -932,7 +936,7 @@ class KubernetesCreateApplicationController {
|
|||
this.formValues.ApplicationOwner = this.Authentication.getUserDetails().username;
|
||||
// combine the secrets and configmap form values when submitting the form
|
||||
_.remove(this.formValues.Configurations, (item) => item.SelectedConfiguration === undefined);
|
||||
await this.KubernetesApplicationService.create(this.formValues, this.originalServicePorts);
|
||||
await this.KubernetesApplicationService.create(this.formValues, this.originalServicePorts, this.deploymentOptions.hideStacksFunctionality);
|
||||
this.Notifications.success('Request to deploy application successfully submitted', this.formValues.Name);
|
||||
this.$state.go('kubernetes.applications');
|
||||
} catch (err) {
|
||||
|
@ -1092,6 +1096,8 @@ class KubernetesCreateApplicationController {
|
|||
this.state.useLoadBalancer = this.endpoint.Kubernetes.Configuration.UseLoadBalancer;
|
||||
this.state.useServerMetrics = this.endpoint.Kubernetes.Configuration.UseServerMetrics;
|
||||
|
||||
this.deploymentOptions = await getGlobalDeploymentOptions();
|
||||
|
||||
const [resourcePools, nodes, nodesLimits] = await Promise.all([
|
||||
this.KubernetesResourcePoolService.get(),
|
||||
this.KubernetesNodeService.get(),
|
||||
|
@ -1140,6 +1146,8 @@ class KubernetesCreateApplicationController {
|
|||
this.nodesLabels,
|
||||
this.ingresses
|
||||
);
|
||||
|
||||
this.formValues.Services = this.formValues.Services || [];
|
||||
this.originalServicePorts = structuredClone(this.formValues.Services.flatMap((service) => service.Ports));
|
||||
this.originalIngressPaths = structuredClone(this.originalServicePorts.flatMap((port) => port.ingressPaths).filter((ingressPath) => ingressPath.Host));
|
||||
|
||||
|
|
|
@ -32,11 +32,13 @@
|
|||
<label for="target_node" class="col-lg-2 col-sm-3 control-label text-left">Namespace</label>
|
||||
<div class="col-sm-8">
|
||||
<select
|
||||
ng-if="!ctrl.formValues.namespace_toggle"
|
||||
ng-disabled="ctrl.formValues.namespace_toggle"
|
||||
class="form-control"
|
||||
ng-model="ctrl.formValues.Namespace"
|
||||
ng-options="namespace.Name as namespace.Name for namespace in ctrl.namespaces"
|
||||
></select>
|
||||
<span ng-if="ctrl.formValues.namespace_toggle">Namespaces specified in the manifest will be used</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -48,12 +50,17 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stack_name" class="col-lg-2 col-sm-3 control-label required text-left">Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" ng-model="ctrl.formValues.StackName" id="stack_name" placeholder="my-app" auto-focus />
|
||||
</div>
|
||||
<label for="stack_name" class="col-lg-2 col-sm-3 control-label text-left">Name</label>
|
||||
<div class="col-sm-8"> Resource names specified in the manifest will be used </div>
|
||||
</div>
|
||||
|
||||
<kube-stack-name
|
||||
ng-if="!ctrl.deploymentOptions.hideStacksFunctionality"
|
||||
stack-name="ctrl.formValues.StackName"
|
||||
set-stack-name="(ctrl.setStackName)"
|
||||
is-admin="ctrl.currentUser.isAdmin"
|
||||
></kube-stack-name>
|
||||
|
||||
<div class="col-sm-12 form-section-title"> Deploy from </div>
|
||||
<box-selector
|
||||
slim="true"
|
||||
|
|
|
@ -5,6 +5,7 @@ import stripAnsi from 'strip-ansi';
|
|||
import PortainerError from '@/portainer/error';
|
||||
import { KubernetesDeployManifestTypes, KubernetesDeployBuildMethods, KubernetesDeployRequestMethods, RepositoryMechanismTypes } from 'Kubernetes/models/deploy';
|
||||
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
|
||||
import { getDeploymentOptions } from '@/react/portainer/environments/environment.service';
|
||||
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
||||
import { kubernetes } from '@@/BoxSelector/common-options/deployment-methods';
|
||||
import { editor, git, customTemplate, url, helm } from '@@/BoxSelector/common-options/build-methods';
|
||||
|
@ -89,6 +90,7 @@ class KubernetesDeployController {
|
|||
this.onChangeMethod = this.onChangeMethod.bind(this);
|
||||
this.onChangeDeployType = this.onChangeDeployType.bind(this);
|
||||
this.onChangeTemplateVariables = this.onChangeTemplateVariables.bind(this);
|
||||
this.setStackName = this.setStackName.bind(this);
|
||||
}
|
||||
|
||||
onSelectHelmChart(chart) {
|
||||
|
@ -101,6 +103,10 @@ class KubernetesDeployController {
|
|||
this.renderTemplate();
|
||||
}
|
||||
|
||||
setStackName(name) {
|
||||
this.formValues.StackName = name;
|
||||
}
|
||||
|
||||
renderTemplate() {
|
||||
if (!this.isTemplateVariablesEnabled) {
|
||||
return;
|
||||
|
@ -180,7 +186,7 @@ class KubernetesDeployController {
|
|||
const isURLFormInvalid = this.state.BuildMethod == KubernetesDeployBuildMethods.WEB_EDITOR.URL && _.isEmpty(this.formValues.ManifestURL);
|
||||
|
||||
const isNamespaceInvalid = _.isEmpty(this.formValues.Namespace);
|
||||
return !this.formValues.StackName || isWebEditorInvalid || isURLFormInvalid || this.state.actionInProgress || isNamespaceInvalid;
|
||||
return isWebEditorInvalid || isURLFormInvalid || this.state.actionInProgress || isNamespaceInvalid;
|
||||
}
|
||||
|
||||
onChangeFormValues(newValues) {
|
||||
|
@ -360,6 +366,8 @@ class KubernetesDeployController {
|
|||
this.formValues.namespace_toggle = false;
|
||||
await this.getNamespaces();
|
||||
|
||||
this.deploymentOptions = await getDeploymentOptions(this.endpoint.Id);
|
||||
|
||||
if (this.$state.params.templateId) {
|
||||
const templateId = parseInt(this.$state.params.templateId, 10);
|
||||
if (templateId && !Number.isNaN(templateId)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue