mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 22:05:23 +02:00
refactor(app): migrate configmap and secret form sections [EE-6233] (#10528)
* refactor(app): migrate configmap and secret form sections [EE-6233]
This commit is contained in:
parent
391b85da41
commit
7a2412b1be
18 changed files with 631 additions and 447 deletions
|
@ -14,6 +14,7 @@ class KubernetesConfigurationConverter {
|
|||
_.forEach(secret.Data, (entry) => {
|
||||
res.Data[entry.Key] = entry.Value;
|
||||
});
|
||||
res.data = res.Data;
|
||||
res.ConfigurationOwner = secret.ConfigurationOwner;
|
||||
res.IsRegistrySecret = secret.IsRegistrySecret;
|
||||
res.SecretType = secret.SecretType;
|
||||
|
@ -34,6 +35,7 @@ class KubernetesConfigurationConverter {
|
|||
_.forEach(configMap.Data, (entry) => {
|
||||
res.Data[entry.Key] = entry.Value;
|
||||
});
|
||||
res.data = res.Data;
|
||||
res.ConfigurationOwner = configMap.ConfigurationOwner;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ class KubernetesSecretConverter {
|
|||
}
|
||||
return entry;
|
||||
});
|
||||
res.data = res.Data;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
KubernetesApplicationAutoScalerFormValue,
|
||||
KubernetesApplicationConfigurationFormValue,
|
||||
KubernetesApplicationConfigurationFormValueOverridenKey,
|
||||
KubernetesApplicationConfigurationFormValueOverridenKeyTypes,
|
||||
KubernetesApplicationEnvironmentVariableFormValue,
|
||||
KubernetesApplicationPersistedFolderFormValue,
|
||||
KubernetesApplicationPlacementFormValue,
|
||||
|
@ -169,21 +168,25 @@ class KubernetesApplicationHelper {
|
|||
const overrideThreshold = max - _.max(_.map(keys, 'VolCount'));
|
||||
const res = _.map(new Array(max), () => new KubernetesApplicationConfigurationFormValue());
|
||||
_.forEach(res, (item, index) => {
|
||||
item.SelectedConfiguration = cfg;
|
||||
item.selectedConfiguration = cfg;
|
||||
// workaround to load configurations in the app in the select inputs
|
||||
// this should be removed when the edit parent view is migrated to react
|
||||
item.selectedConfiguration.metadata = {};
|
||||
item.selectedConfiguration.metadata.name = cfg.Name;
|
||||
const overriden = index >= overrideThreshold;
|
||||
if (overriden) {
|
||||
item.Overriden = true;
|
||||
item.OverridenKeys = _.map(keys, (k) => {
|
||||
item.overriden = true;
|
||||
item.overridenKeys = _.map(keys, (k) => {
|
||||
const fvKey = new KubernetesApplicationConfigurationFormValueOverridenKey();
|
||||
fvKey.Key = k.Key;
|
||||
fvKey.key = k.Key;
|
||||
if (!k.Count) {
|
||||
// !k.Count indicates k.Key is new added to the configuration and has not been loaded to the application yet
|
||||
fvKey.Type = KubernetesApplicationConfigurationFormValueOverridenKeyTypes.NONE;
|
||||
// !k.Count indicates k.key is new added to the configuration and has not been loaded to the application yet
|
||||
fvKey.type = 'NONE';
|
||||
} else if (index < k.EnvCount) {
|
||||
fvKey.Type = KubernetesApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT;
|
||||
fvKey.type = 'ENVIRONMENT';
|
||||
} else {
|
||||
fvKey.Type = KubernetesApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM;
|
||||
fvKey.Path = k.Sum[index].rootMountPath;
|
||||
fvKey.type = 'FILESYSTEM';
|
||||
fvKey.path = k.Sum[index].rootMountPath;
|
||||
}
|
||||
return fvKey;
|
||||
});
|
||||
|
@ -201,46 +204,46 @@ class KubernetesApplicationHelper {
|
|||
let finalMounts = [];
|
||||
|
||||
_.forEach(configurations, (config) => {
|
||||
const isBasic = config.SelectedConfiguration.Kind === KubernetesConfigurationKinds.CONFIGMAP;
|
||||
const isBasic = config.selectedConfiguration.kind === 'ConfigMap';
|
||||
|
||||
if (!config.Overriden) {
|
||||
const envKeys = _.keys(config.SelectedConfiguration.Data);
|
||||
if (!config.overriden) {
|
||||
const envKeys = _.keys(config.selectedConfiguration.data);
|
||||
_.forEach(envKeys, (item) => {
|
||||
const res = isBasic ? new KubernetesApplicationEnvConfigMapPayload() : new KubernetesApplicationEnvSecretPayload();
|
||||
res.name = item;
|
||||
if (isBasic) {
|
||||
res.valueFrom.configMapKeyRef.name = config.SelectedConfiguration.Name;
|
||||
res.valueFrom.configMapKeyRef.name = config.selectedConfiguration.metadata.name;
|
||||
res.valueFrom.configMapKeyRef.key = item;
|
||||
} else {
|
||||
res.valueFrom.secretKeyRef.name = config.SelectedConfiguration.Name;
|
||||
res.valueFrom.secretKeyRef.name = config.selectedConfiguration.metadata.name;
|
||||
res.valueFrom.secretKeyRef.key = item;
|
||||
}
|
||||
finalEnv.push(res);
|
||||
});
|
||||
} else {
|
||||
const envKeys = _.filter(config.OverridenKeys, (item) => item.Type === KubernetesApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT);
|
||||
const envKeys = _.filter(config.overridenKeys, (item) => item.type === 'ENVIRONMENT');
|
||||
_.forEach(envKeys, (item) => {
|
||||
const res = isBasic ? new KubernetesApplicationEnvConfigMapPayload() : new KubernetesApplicationEnvSecretPayload();
|
||||
res.name = item.Key;
|
||||
res.name = item.key;
|
||||
if (isBasic) {
|
||||
res.valueFrom.configMapKeyRef.name = config.SelectedConfiguration.Name;
|
||||
res.valueFrom.configMapKeyRef.key = item.Key;
|
||||
res.valueFrom.configMapKeyRef.name = config.selectedConfiguration.metadata.name;
|
||||
res.valueFrom.configMapKeyRef.key = item.key;
|
||||
} else {
|
||||
res.valueFrom.secretKeyRef.name = config.SelectedConfiguration.Name;
|
||||
res.valueFrom.secretKeyRef.key = item.Key;
|
||||
res.valueFrom.secretKeyRef.name = config.selectedConfiguration.metadata.name;
|
||||
res.valueFrom.secretKeyRef.key = item.key;
|
||||
}
|
||||
finalEnv.push(res);
|
||||
});
|
||||
|
||||
const volKeys = _.filter(config.OverridenKeys, (item) => item.Type === KubernetesApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM);
|
||||
const groupedVolKeys = _.groupBy(volKeys, 'Path');
|
||||
const volKeys = _.filter(config.overridenKeys, (item) => item.type === 'FILESYSTEM');
|
||||
const groupedVolKeys = _.groupBy(volKeys, 'path');
|
||||
_.forEach(groupedVolKeys, (items, path) => {
|
||||
const volumeName = KubernetesVolumeHelper.generatedApplicationConfigVolumeName(app.Name);
|
||||
const configurationName = config.SelectedConfiguration.Name;
|
||||
const configurationName = config.selectedConfiguration.metadata.name;
|
||||
const itemsMap = _.map(items, (item) => {
|
||||
const entry = new KubernetesApplicationVolumeEntryPayload();
|
||||
entry.key = item.Key;
|
||||
entry.path = item.Key;
|
||||
entry.key = item.key;
|
||||
entry.path = item.key;
|
||||
return entry;
|
||||
});
|
||||
|
||||
|
|
|
@ -30,19 +30,13 @@ export function KubernetesApplicationFormValues() {
|
|||
this.OriginalIngresses = undefined;
|
||||
}
|
||||
|
||||
export const KubernetesApplicationConfigurationFormValueOverridenKeyTypes = Object.freeze({
|
||||
NONE: 0,
|
||||
ENVIRONMENT: 1,
|
||||
FILESYSTEM: 2,
|
||||
});
|
||||
|
||||
/**
|
||||
* KubernetesApplicationConfigurationFormValueOverridenKey Model
|
||||
*/
|
||||
const _KubernetesApplicationConfigurationFormValueOverridenKey = Object.freeze({
|
||||
Key: '',
|
||||
Path: '',
|
||||
Type: KubernetesApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT,
|
||||
key: '',
|
||||
path: '',
|
||||
type: 'ENVIRONMENT',
|
||||
});
|
||||
|
||||
export class KubernetesApplicationConfigurationFormValueOverridenKey {
|
||||
|
@ -55,9 +49,9 @@ export class KubernetesApplicationConfigurationFormValueOverridenKey {
|
|||
* KubernetesApplicationConfigurationFormValue Model
|
||||
*/
|
||||
const _KubernetesApplicationConfigurationFormValue = Object.freeze({
|
||||
SelectedConfiguration: undefined,
|
||||
Overriden: false,
|
||||
OverridenKeys: [], // KubernetesApplicationConfigurationFormValueOverridenKey list
|
||||
selectedConfiguration: undefined,
|
||||
overriden: false,
|
||||
overridenKeys: [],
|
||||
});
|
||||
|
||||
export class KubernetesApplicationConfigurationFormValue {
|
||||
|
|
|
@ -25,6 +25,9 @@ import { ApplicationsStacksDatatable } from '@/react/kubernetes/applications/Lis
|
|||
import { NodesDatatable } from '@/react/kubernetes/cluster/HomeView/NodesDatatable';
|
||||
import { StackName } from '@/react/kubernetes/DeployView/StackName/StackName';
|
||||
import { kubeEnvVarValidationSchema } from '@/react/kubernetes/applications/ApplicationForm/kubeEnvVarValidationSchema';
|
||||
import { SecretsFormSection } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/SecretsFormSection';
|
||||
import { configurationsValidationSchema } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/configurationValidationSchema';
|
||||
import { ConfigMapsFormSection } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/ConfigMapsFormSection';
|
||||
|
||||
import { EnvironmentVariablesFieldset } from '@@/form-components/EnvironmentVariablesFieldset';
|
||||
|
||||
|
@ -186,3 +189,19 @@ withFormValidation(
|
|||
// use kubeEnvVarValidationSchema instead of envVarValidation to add a regex matches rule
|
||||
kubeEnvVarValidationSchema
|
||||
);
|
||||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(ConfigMapsFormSection))),
|
||||
'configMapsFormSection',
|
||||
['values', 'onChange', 'namespace'],
|
||||
configurationsValidationSchema
|
||||
);
|
||||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(SecretsFormSection))),
|
||||
'secretsFormSection',
|
||||
['values', 'onChange', 'namespace'],
|
||||
configurationsValidationSchema
|
||||
);
|
||||
|
|
|
@ -381,7 +381,7 @@
|
|||
<!-- #region ENVIRONMENT VARIABLES -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 vertical-center">
|
||||
<label class="control-label !pt-0 text-left">Environment variables</label>
|
||||
<label class="control-label !pt-0 text-left !text-sm">Environment variables</label>
|
||||
</div>
|
||||
<div class="col-sm-11 col-lg-10 mt-2">
|
||||
<kube-environment-variables-fieldset
|
||||
|
@ -394,313 +394,26 @@
|
|||
<!-- #endregion -->
|
||||
|
||||
<!-- #region CONFIGMAPS -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 vertical-center">
|
||||
<label class="control-label !pt-0 text-left">ConfigMaps</label>
|
||||
</div>
|
||||
<div class="col-sm-12 small text-muted vertical-center" style="margin-top: 15px" ng-if="ctrl.formValues.ConfigMaps.length">
|
||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||
Portainer will automatically expose all the keys of a ConfigMap as environment variables. This behavior can be overridden to filesystem mounts for each key
|
||||
via the override option.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- config-element -->
|
||||
<div class="form-inline clearfix" ng-repeat="(index, config) in ctrl.formValues.ConfigMaps">
|
||||
<div class="col-sm-12 !p-0">
|
||||
<div class="input-group input-group-sm !mr-1">
|
||||
<span class="input-group-addon">name</span>
|
||||
<select
|
||||
class="form-control col-sm-6"
|
||||
ng-model="config.SelectedConfiguration"
|
||||
ng-options="c as c.Name for c in ctrl.configMaps track by c.Name"
|
||||
ng-change="ctrl.resetConfigMap(index)"
|
||||
ng-disabled="ctrl.formValues.Containers.length > 1"
|
||||
data-cy="k8sAppCreate-addConfigSelect_{{ $index }}"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="input-group btn-group btn-group-sm">
|
||||
<label
|
||||
class="btn btn-md btn-light vertical-center !ml-0"
|
||||
type="button"
|
||||
ng-click="ctrl.resetConfigMap(index)"
|
||||
ng-disabled="ctrl.formValues.Containers.length > 1"
|
||||
data-cy="k8sAppCreate-configAutoButton_{{ $index }}"
|
||||
uib-btn-radio="false"
|
||||
ng-model="config.Overriden"
|
||||
>
|
||||
<pr-icon icon="'rotate-cw'" size="'md'"></pr-icon> Auto
|
||||
</label>
|
||||
<label
|
||||
class="btn btn-md btn-light vertical-center !ml-0"
|
||||
ng-click="ctrl.overrideConfigMap(index)"
|
||||
ng-disabled="!config.SelectedConfiguration || ctrl.formValues.Containers.length > 1"
|
||||
data-cy="k8sAppCreate-configOverrideButton_{{ $index }}"
|
||||
uib-btn-radio="true"
|
||||
ng-model="config.Overriden"
|
||||
>
|
||||
<pr-icon icon="'list'" size="'md'"></pr-icon> Override
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-md btn-dangerlight btn-only-icon vertical-center"
|
||||
type="button"
|
||||
ng-click="ctrl.removeConfigMap(index)"
|
||||
ng-if="ctrl.formValues.Containers.length <= 1"
|
||||
data-cy="k8sAppCreate-configRemoveButton"
|
||||
>
|
||||
<pr-icon icon="'trash-2'" size="'md'"></pr-icon>
|
||||
</button>
|
||||
</div>
|
||||
<!-- no-override -->
|
||||
<div class="row clearfix" ng-if="config.SelectedConfiguration && !config.Overriden">
|
||||
<div class="col-sm-9 small text-muted !mt-2 !p-0">
|
||||
The following keys will be loaded from the <code>{{ config.SelectedConfiguration.Name }}</code>
|
||||
ConfigMap as environment variables:
|
||||
<span ng-repeat="(key, _) in config.SelectedConfiguration.Data">
|
||||
<code>{{ key }}</code
|
||||
>{{ $last ? '' : ', ' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !no-override -->
|
||||
|
||||
<!-- has-override -->
|
||||
<div class="col-sm-12 !mt-2 !mb-4 !p-0" ng-if="config.Overriden" ng-repeat="(keyIndex, overridenKey) in config.OverridenKeys" style="margin-top: 2px">
|
||||
<div class="input-group input-group-sm !mr-1">
|
||||
<span class="input-group-addon">key</span>
|
||||
<input type="text" class="form-control" ng-value="overridenKey.Key" disabled />
|
||||
</div>
|
||||
|
||||
<div class="input-group btn-group btn-group-sm !mr-1">
|
||||
<label class="btn btn-light" ng-model="overridenKey.Type" uib-btn-radio="ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT">
|
||||
<pr-icon icon="'list'"></pr-icon> Environment
|
||||
</label>
|
||||
<label class="btn btn-light" ng-model="overridenKey.Type" uib-btn-radio="ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
|
||||
<pr-icon icon="'file-text'"></pr-icon> Filesystem
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group !ml-0 !mr-0 !align-top" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon required">path on disk</span>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
ng-model="overridenKey.Path"
|
||||
placeholder="/etc/myapp/conf.d"
|
||||
name="overriden_key_configmap_path_{{ index }}_{{ keyIndex }}"
|
||||
ng-disabled="ctrl.formValues.Containers.length > 1"
|
||||
required
|
||||
ng-change="ctrl.onChangeConfigMapPath()"
|
||||
data-cy="k8sAppCreate-pathOnDiskInput"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="small"
|
||||
ng-show="
|
||||
kubernetesApplicationCreationForm['overriden_key_configmap_path_' + index + '_' + keyIndex].$invalid ||
|
||||
ctrl.state.duplicates.configMapPaths.refs[index + '_' + keyIndex] !== undefined
|
||||
"
|
||||
>
|
||||
<div class="text-warning" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
|
||||
<div
|
||||
ng-show="
|
||||
kubernetesApplicationCreationForm['overriden_key_configmap_path_' + index + '_' + keyIndex].$invalid ||
|
||||
ctrl.state.duplicates.configMapPaths.refs[index + '_' + keyIndex] !== undefined
|
||||
"
|
||||
>
|
||||
<ng-messages for="kubernetesApplicationCreationForm['overriden_key_configmap_path_' + index + '_' + keyIndex].$error">
|
||||
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> Path is required.</p>
|
||||
</ng-messages>
|
||||
<p class="vertical-center" ng-if="ctrl.state.duplicates.configMapPaths.refs[index + '_' + keyIndex] !== undefined">
|
||||
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> This path is already used.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !has-override -->
|
||||
</div>
|
||||
<!-- !config-element -->
|
||||
<div class="col-sm-12 !p-0">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm btn btn-sm btn-light mb-2 !ml-0"
|
||||
ng-disabled="ctrl.configMaps.length === 0"
|
||||
ng-click="ctrl.addConfigMap()"
|
||||
ng-if="ctrl.formValues.Containers.length <= 1"
|
||||
data-cy="k8sAppCreate-addConfigButton"
|
||||
>
|
||||
<pr-icon icon="'plus'" size="'sm'"></pr-icon> Add ConfigMap
|
||||
</button>
|
||||
</div>
|
||||
<div class="my-2 w-full">
|
||||
<p class="vertical-center text-warning text-xs" ng-if="ctrl.configMaps.length === 0"
|
||||
><pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> There are no ConfigMaps available in this namespace.</p
|
||||
>
|
||||
</div>
|
||||
<config-maps-form-section
|
||||
values="ctrl.formValues.ConfigMaps"
|
||||
on-change="(ctrl.onConfigMapsChange)"
|
||||
namespace="ctrl.formValues.ResourcePool.Namespace.Name"
|
||||
validation-data="ctrl.formValues.ConfigMaps"
|
||||
></config-maps-form-section>
|
||||
|
||||
<!-- #region SECRETS -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 vertical-center pt-2.5">
|
||||
<label class="control-label !pt-0 text-left">Secrets</label>
|
||||
</div>
|
||||
<div class="col-sm-12 small text-muted vertical-center" style="margin-top: 15px" ng-if="ctrl.formValues.Secrets.length">
|
||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||
Portainer will automatically expose all the keys of a Secret as environment variables. This behavior can be overridden to filesystem mounts for each key via
|
||||
the override option.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- config-element -->
|
||||
<div class="form-inline clearfix" ng-repeat="(index, config) in ctrl.formValues.Secrets">
|
||||
<div class="col-sm-12 !p-0">
|
||||
<div class="input-group input-group-sm !mr-1">
|
||||
<span class="input-group-addon">name</span>
|
||||
<select
|
||||
class="form-control col-sm-6"
|
||||
ng-model="config.SelectedConfiguration"
|
||||
ng-options="c as c.Name for c in ctrl.secrets track by c.Name"
|
||||
ng-change="ctrl.resetSecret(index)"
|
||||
ng-disabled="ctrl.formValues.Containers.length > 1"
|
||||
data-cy="k8sAppCreate-addSecretSelect_{{ $index }}"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="input-group btn-group btn-group-sm">
|
||||
<label
|
||||
class="btn btn-md btn-light vertical-center !ml-0"
|
||||
type="button"
|
||||
ng-click="ctrl.resetSecret(index)"
|
||||
ng-disabled="ctrl.formValues.Containers.length > 1"
|
||||
data-cy="k8sAppCreate-secretAutoButton_{{ $index }}"
|
||||
uib-btn-radio="false"
|
||||
ng-model="config.Overriden"
|
||||
>
|
||||
<pr-icon icon="'rotate-cw'" size="'md'"></pr-icon> Auto
|
||||
</label>
|
||||
<label
|
||||
class="btn btn-md btn-light vertical-center !ml-0"
|
||||
ng-click="ctrl.overrideSecret(index)"
|
||||
ng-disabled="!config.SelectedConfiguration || ctrl.formValues.Containers.length > 1"
|
||||
data-cy="k8sAppCreate-secretOverrideButton_{{ $index }}"
|
||||
uib-btn-radio="true"
|
||||
ng-model="config.Overriden"
|
||||
>
|
||||
<pr-icon icon="'list'" size="'md'"></pr-icon> Override
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-md btn-dangerlight btn-only-icon vertical-center"
|
||||
type="button"
|
||||
ng-click="ctrl.removeSecret(index)"
|
||||
ng-if="ctrl.formValues.Containers.length <= 1"
|
||||
data-cy="k8sAppCreate-secretRemoveButton"
|
||||
>
|
||||
<pr-icon icon="'trash-2'" size="'md'"></pr-icon>
|
||||
</button>
|
||||
</div>
|
||||
<!-- no-override -->
|
||||
<div class="row clearfix" ng-if="config.SelectedConfiguration && !config.Overriden">
|
||||
<div class="col-sm-9 small text-muted !mt-2 !p-0">
|
||||
The following keys will be loaded from the <code>{{ config.SelectedConfiguration.Name }}</code> Secret as environment variables:
|
||||
<span ng-repeat="(key, _) in config.SelectedConfiguration.Data">
|
||||
<code>{{ key }}</code
|
||||
>{{ $last ? '' : ', ' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !no-override -->
|
||||
|
||||
<!-- has-override -->
|
||||
<div class="col-sm-12 !mt-2 !mb-4 !p-0" ng-if="config.Overriden" ng-repeat="(keyIndex, overridenKey) in config.OverridenKeys" style="margin-top: 2px">
|
||||
<div class="input-group input-group-sm !mr-1">
|
||||
<span class="input-group-addon">key</span>
|
||||
<input type="text" class="form-control" ng-value="overridenKey.Key" disabled />
|
||||
</div>
|
||||
|
||||
<div class="input-group btn-group btn-group-sm !mr-1">
|
||||
<label class="btn btn-light" ng-model="overridenKey.Type" uib-btn-radio="ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT">
|
||||
<pr-icon icon="'list'"></pr-icon> Environment
|
||||
</label>
|
||||
<label class="btn btn-light" ng-model="overridenKey.Type" uib-btn-radio="ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
|
||||
<pr-icon icon="'file-text'"></pr-icon> Filesystem
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group !ml-0 !mr-0 !align-top" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon required">path on disk</span>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
ng-model="overridenKey.Path"
|
||||
placeholder="/etc/myapp/conf.d"
|
||||
name="overriden_key_secret_path_{{ index }}_{{ keyIndex }}"
|
||||
ng-disabled="ctrl.formValues.Containers.length > 1"
|
||||
required
|
||||
ng-change="ctrl.onChangeSecretPath()"
|
||||
data-cy="k8sAppCreate-secretPathOnDiskInput"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="small"
|
||||
ng-show="
|
||||
kubernetesApplicationCreationForm['overriden_key_secret_path_' + index + '_' + keyIndex].$invalid ||
|
||||
ctrl.state.duplicates.secretPaths.refs[index + '_' + keyIndex] !== undefined
|
||||
"
|
||||
>
|
||||
<div class="text-warning" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
|
||||
<div
|
||||
ng-show="
|
||||
kubernetesApplicationCreationForm['overriden_key_secret_path_' + index + '_' + keyIndex].$invalid ||
|
||||
ctrl.state.duplicates.secretPaths.refs[index + '_' + keyIndex] !== undefined
|
||||
"
|
||||
>
|
||||
<ng-messages for="kubernetesApplicationCreationForm['overriden_key_secret_path_' + index + '_' + keyIndex].$error">
|
||||
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> Path is required.</p>
|
||||
</ng-messages>
|
||||
<p class="vertical-center" ng-if="ctrl.state.duplicates.secretPaths.refs[index + '_' + keyIndex] !== undefined"
|
||||
><pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> This path is already used.</p
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !has-override -->
|
||||
</div>
|
||||
|
||||
<div class="my-2 w-full">
|
||||
<p class="vertical-center text-muted text-xs" ng-if="ctrl.secrets.length === 0">
|
||||
<pr-icon icon="'info'" mode="'primary'"></pr-icon>
|
||||
There are no secrets available in this namespace.
|
||||
</p>
|
||||
</div>
|
||||
<!-- !config-element -->
|
||||
<div class="col-sm-12 !p-0">
|
||||
<button
|
||||
type="button"
|
||||
ng-disabled="ctrl.secrets.length === 0"
|
||||
class="btn btn-primary btn-sm btn btn-sm btn-light mb-2 !ml-0"
|
||||
ng-click="ctrl.addSecret()"
|
||||
ng-if="ctrl.formValues.Containers.length <= 1"
|
||||
data-cy="k8sAppCreate-addSecretButton"
|
||||
>
|
||||
<pr-icon icon="'plus'" size="'sm'"></pr-icon> Add Secret
|
||||
</button>
|
||||
</div>
|
||||
<secrets-form-section
|
||||
values="ctrl.formValues.Secrets"
|
||||
on-change="(ctrl.onSecretsChange)"
|
||||
namespace="ctrl.formValues.ResourcePool.Namespace.Name"
|
||||
validation-data="ctrl.formValues.Secrets"
|
||||
></secrets-form-section>
|
||||
<!-- #endregion -->
|
||||
|
||||
<!-- #region PERSISTED FOLDERS -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 vertical-center mb-2 pt-2.5" style="margin-top: 5px">
|
||||
<label class="control-label !pt-0 text-left">Persisted folders</label>
|
||||
<label class="control-label !pt-0 text-left !text-sm">Persisted folders</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 small text-muted vertical-center mt-1" ng-if="!ctrl.storageClassAvailable()">
|
||||
|
|
|
@ -17,9 +17,6 @@ import {
|
|||
KubernetesDeploymentTypes,
|
||||
} from 'Kubernetes/models/application/models';
|
||||
import {
|
||||
KubernetesApplicationConfigurationFormValue,
|
||||
KubernetesApplicationConfigurationFormValueOverridenKey,
|
||||
KubernetesApplicationConfigurationFormValueOverridenKeyTypes,
|
||||
KubernetesApplicationEnvironmentVariableFormValue,
|
||||
KubernetesApplicationFormValues,
|
||||
KubernetesApplicationPersistedFolderFormValue,
|
||||
|
@ -85,7 +82,6 @@ class KubernetesCreateApplicationController {
|
|||
this.ApplicationPublishingTypes = KubernetesApplicationPublishingTypes;
|
||||
this.ApplicationPlacementTypes = KubernetesApplicationPlacementTypes;
|
||||
this.ApplicationTypes = KubernetesApplicationTypes;
|
||||
this.ApplicationConfigurationFormValueOverridenKeyTypes = KubernetesApplicationConfigurationFormValueOverridenKeyTypes;
|
||||
this.ServiceTypes = KubernetesServiceTypes;
|
||||
this.KubernetesDeploymentTypes = KubernetesDeploymentTypes;
|
||||
|
||||
|
@ -155,6 +151,8 @@ class KubernetesCreateApplicationController {
|
|||
this.onChangePlacementType = this.onChangePlacementType.bind(this);
|
||||
this.onServicesChange = this.onServicesChange.bind(this);
|
||||
this.onEnvironmentVariableChange = this.onEnvironmentVariableChange.bind(this);
|
||||
this.onConfigMapsChange = this.onConfigMapsChange.bind(this);
|
||||
this.onSecretsChange = this.onSecretsChange.bind(this);
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
|
@ -240,34 +238,12 @@ class KubernetesCreateApplicationController {
|
|||
/* #endregion */
|
||||
|
||||
/* #region CONFIGMAP UI MANAGEMENT */
|
||||
addConfigMap() {
|
||||
let config = new KubernetesApplicationConfigurationFormValue();
|
||||
config.SelectedConfiguration = this.configMaps[0];
|
||||
this.formValues.ConfigMaps.push(config);
|
||||
}
|
||||
|
||||
removeConfigMap(index) {
|
||||
this.formValues.ConfigMaps.splice(index, 1);
|
||||
this.onChangeConfigMapPath();
|
||||
}
|
||||
|
||||
overrideConfigMap(index) {
|
||||
const config = this.formValues.ConfigMaps[index];
|
||||
config.Overriden = true;
|
||||
config.OverridenKeys = _.map(_.keys(config.SelectedConfiguration.Data), (key) => {
|
||||
const res = new KubernetesApplicationConfigurationFormValueOverridenKey();
|
||||
res.Key = key;
|
||||
return res;
|
||||
onConfigMapsChange(configMaps) {
|
||||
return this.$async(async () => {
|
||||
this.formValues.ConfigMaps = configMaps;
|
||||
});
|
||||
}
|
||||
|
||||
resetConfigMap(index) {
|
||||
const config = this.formValues.ConfigMaps[index];
|
||||
config.Overriden = false;
|
||||
config.OverridenKeys = [];
|
||||
this.onChangeConfigMapPath();
|
||||
}
|
||||
|
||||
clearConfigMaps() {
|
||||
this.formValues.ConfigMaps = [];
|
||||
}
|
||||
|
@ -278,7 +254,7 @@ class KubernetesCreateApplicationController {
|
|||
const paths = _.reduce(
|
||||
this.formValues.ConfigMaps,
|
||||
(result, config) => {
|
||||
const uniqOverridenKeysPath = _.uniq(_.map(config.OverridenKeys, 'Path'));
|
||||
const uniqOverridenKeysPath = _.uniq(_.map(config.overridenKeys, 'path'));
|
||||
return _.concat(result, uniqOverridenKeysPath);
|
||||
},
|
||||
[]
|
||||
|
@ -287,8 +263,8 @@ class KubernetesCreateApplicationController {
|
|||
const duplicatePaths = KubernetesFormValidationHelper.getDuplicates(paths);
|
||||
|
||||
_.forEach(this.formValues.ConfigMaps, (config, index) => {
|
||||
_.forEach(config.OverridenKeys, (overridenKey, keyIndex) => {
|
||||
const findPath = _.find(duplicatePaths, (path) => path === overridenKey.Path);
|
||||
_.forEach(config.overridenKeys, (overridenKey, keyIndex) => {
|
||||
const findPath = _.find(duplicatePaths, (path) => path === overridenKey.path);
|
||||
if (findPath) {
|
||||
this.state.duplicates.configMapPaths.refs[index + '_' + keyIndex] = findPath;
|
||||
}
|
||||
|
@ -300,63 +276,15 @@ class KubernetesCreateApplicationController {
|
|||
/* #endregion */
|
||||
|
||||
/* #region SECRET UI MANAGEMENT */
|
||||
addSecret() {
|
||||
let secret = new KubernetesApplicationConfigurationFormValue();
|
||||
secret.SelectedConfiguration = this.secrets[0];
|
||||
this.formValues.Secrets.push(secret);
|
||||
}
|
||||
|
||||
removeSecret(index) {
|
||||
this.formValues.Secrets.splice(index, 1);
|
||||
this.onChangeSecretPath();
|
||||
}
|
||||
|
||||
overrideSecret(index) {
|
||||
const secret = this.formValues.Secrets[index];
|
||||
secret.Overriden = true;
|
||||
secret.OverridenKeys = _.map(_.keys(secret.SelectedConfiguration.Data), (key) => {
|
||||
const res = new KubernetesApplicationConfigurationFormValueOverridenKey();
|
||||
res.Key = key;
|
||||
return res;
|
||||
onSecretsChange(secrets) {
|
||||
return this.$async(async () => {
|
||||
this.formValues.Secrets = secrets;
|
||||
});
|
||||
}
|
||||
|
||||
resetSecret(index) {
|
||||
const secret = this.formValues.Secrets[index];
|
||||
secret.Overriden = false;
|
||||
secret.OverridenKeys = [];
|
||||
this.onChangeSecretPath();
|
||||
}
|
||||
|
||||
clearSecrets() {
|
||||
this.formValues.Secrets = [];
|
||||
}
|
||||
|
||||
onChangeSecretPath() {
|
||||
this.state.duplicates.secretPaths.refs = [];
|
||||
|
||||
const paths = _.reduce(
|
||||
this.formValues.Secrets,
|
||||
(result, secret) => {
|
||||
const uniqOverridenKeysPath = _.uniq(_.map(secret.OverridenKeys, 'Path'));
|
||||
return _.concat(result, uniqOverridenKeysPath);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const duplicatePaths = KubernetesFormValidationHelper.getDuplicates(paths);
|
||||
|
||||
_.forEach(this.formValues.Secrets, (secret, index) => {
|
||||
_.forEach(secret.OverridenKeys, (overridenKey, keyIndex) => {
|
||||
const findPath = _.find(duplicatePaths, (path) => path === overridenKey.Path);
|
||||
if (findPath) {
|
||||
this.state.duplicates.secretPaths.refs[index + '_' + keyIndex] = findPath;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.state.duplicates.secretPaths.hasRefs = Object.keys(this.state.duplicates.secretPaths.refs).length > 0;
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
/* #region ENVIRONMENT UI MANAGEMENT */
|
||||
|
@ -920,7 +848,7 @@ class KubernetesCreateApplicationController {
|
|||
try {
|
||||
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);
|
||||
_.remove(this.formValues.Configurations, (item) => item.selectedConfiguration === undefined);
|
||||
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');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue