mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 13:55:21 +02:00
refactor(app): migrate app summary section [EE-6239] (#10910)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
This commit is contained in:
parent
7a4314032a
commit
abf517de28
61 changed files with 1461 additions and 661 deletions
|
@ -219,7 +219,7 @@
|
|||
<div class="menuContent">
|
||||
<div class="md-checkbox" ng-repeat="filter in $ctrl.filters.state.values track by $index">
|
||||
<input id="filter_state_{{ $index }}" type="checkbox" ng-model="filter.display" ng-change="$ctrl.onStateFilterChange()" />
|
||||
<label for="filter_state_{{ $index }}">{{ filter.type | kubernetesApplicationTypeText }}</label>
|
||||
<label for="filter_state_{{ $index }}">{{ filter.type }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -282,7 +282,7 @@
|
|||
</a>
|
||||
<a
|
||||
ng-if="!item.KubernetesApplications"
|
||||
ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool, 'resource-type': $ctrl.applicationTypeEnumToParamMap[item.ApplicationType] })"
|
||||
ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool, 'resource-type': item.ApplicationType })"
|
||||
ng-click="$event.stopPropagation()"
|
||||
class="hyperlink"
|
||||
>{{ item.Name }}
|
||||
|
@ -297,17 +297,17 @@
|
|||
<td title="{{ item.Image }}"
|
||||
>{{ item.Image | truncate: 64 }} <span ng-if="item.Containers.length > 1">+ {{ item.Containers.length - 1 }}</span></td
|
||||
>
|
||||
<td>{{ item.ApplicationType | kubernetesApplicationTypeText }}</td>
|
||||
<td ng-if="item.ApplicationType !== $ctrl.KubernetesApplicationTypes.POD">
|
||||
<td>{{ item.ApplicationType }}</td>
|
||||
<td ng-if="item.ApplicationType !== $ctrl.KubernetesApplicationTypes.Pod">
|
||||
<status-indicator ok="(item.TotalPodsCount > 0 && item.TotalPodsCount === item.RunningPodsCount) || item.Status === 'Ready'"></status-indicator>
|
||||
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.REPLICATED">Replicated</span>
|
||||
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.GLOBAL">Global</span>
|
||||
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.Replicated">Replicated</span>
|
||||
<span ng-if="item.DeploymentType === $ctrl.KubernetesApplicationDeploymentTypes.Global">Global</span>
|
||||
<span ng-if="item.RunningPodsCount >= 0 && item.TotalPodsCount >= 0"
|
||||
><code>{{ item.RunningPodsCount }}</code> / <code>{{ item.TotalPodsCount }}</code></span
|
||||
>
|
||||
<span ng-if="item.KubernetesApplications">{{ item.Status }}</span>
|
||||
</td>
|
||||
<td ng-if="item.ApplicationType === $ctrl.KubernetesApplicationTypes.POD">
|
||||
<td ng-if="item.ApplicationType === $ctrl.KubernetesApplicationTypes.Pod">
|
||||
{{ item.Pods[0].Status }}
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import _ from 'lodash-es';
|
||||
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
|
||||
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
|
||||
import { KubernetesConfigurationKinds } from 'Kubernetes/models/configuration/models';
|
||||
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
|
||||
angular.module('portainer.kubernetes').controller('KubernetesApplicationsDatatableController', [
|
||||
'$scope',
|
||||
|
@ -33,13 +33,6 @@ angular.module('portainer.kubernetes').controller('KubernetesApplicationsDatatab
|
|||
},
|
||||
};
|
||||
|
||||
this.applicationTypeEnumToParamMap = {
|
||||
[KubernetesApplicationTypes.DEPLOYMENT]: 'Deployment',
|
||||
[KubernetesApplicationTypes.DAEMONSET]: 'DaemonSet',
|
||||
[KubernetesApplicationTypes.STATEFULSET]: 'StatefulSet',
|
||||
[KubernetesApplicationTypes.POD]: 'Pod',
|
||||
};
|
||||
|
||||
this.expandAll = function () {
|
||||
this.state.expandAll = !this.state.expandAll;
|
||||
this.state.filteredDataSet.forEach((item) => this.expandItem(item, this.state.expandAll));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { KubernetesApplicationDeploymentTypes } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesApplicationDeploymentTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
|
||||
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
|
||||
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import _ from 'lodash-es';
|
||||
import filesizeParser from 'filesize-parser';
|
||||
|
||||
import { KubernetesApplicationDataAccessPolicies, KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
import {
|
||||
KubernetesApplication,
|
||||
KubernetesApplicationConfigurationVolume,
|
||||
KubernetesApplicationDataAccessPolicies,
|
||||
KubernetesApplicationDeploymentTypes,
|
||||
KubernetesApplicationPersistedFolder,
|
||||
KubernetesApplicationPort,
|
||||
KubernetesApplicationPublishingTypes,
|
||||
KubernetesApplicationTypes,
|
||||
KubernetesPortainerApplicationNameLabel,
|
||||
KubernetesPortainerApplicationNote,
|
||||
KubernetesPortainerApplicationOwnerLabel,
|
||||
|
@ -241,16 +238,16 @@ class KubernetesApplicationConverter {
|
|||
static apiPodToApplication(data, pods, service, ingresses) {
|
||||
const res = new KubernetesApplication();
|
||||
KubernetesApplicationConverter.applicationCommon(res, data, pods, service, ingresses);
|
||||
res.ApplicationType = KubernetesApplicationTypes.POD;
|
||||
res.ApplicationType = KubernetesApplicationTypes.Pod;
|
||||
return res;
|
||||
}
|
||||
|
||||
static apiDeploymentToApplication(data, pods, service, ingresses) {
|
||||
const res = new KubernetesApplication();
|
||||
KubernetesApplicationConverter.applicationCommon(res, data, pods, service, ingresses);
|
||||
res.ApplicationType = KubernetesApplicationTypes.DEPLOYMENT;
|
||||
res.DeploymentType = KubernetesApplicationDeploymentTypes.REPLICATED;
|
||||
res.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.SHARED;
|
||||
res.ApplicationType = KubernetesApplicationTypes.Deployment;
|
||||
res.DeploymentType = KubernetesApplicationDeploymentTypes.Replicated;
|
||||
res.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.Shared;
|
||||
res.RunningPodsCount = data.status.availableReplicas || data.status.replicas - data.status.unavailableReplicas || 0;
|
||||
res.TotalPodsCount = data.spec.replicas;
|
||||
return res;
|
||||
|
@ -259,9 +256,9 @@ class KubernetesApplicationConverter {
|
|||
static apiDaemonSetToApplication(data, pods, service, ingresses) {
|
||||
const res = new KubernetesApplication();
|
||||
KubernetesApplicationConverter.applicationCommon(res, data, pods, service, ingresses);
|
||||
res.ApplicationType = KubernetesApplicationTypes.DAEMONSET;
|
||||
res.DeploymentType = KubernetesApplicationDeploymentTypes.GLOBAL;
|
||||
res.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.SHARED;
|
||||
res.ApplicationType = KubernetesApplicationTypes.DaemonSet;
|
||||
res.DeploymentType = KubernetesApplicationDeploymentTypes.Global;
|
||||
res.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.Shared;
|
||||
res.RunningPodsCount = data.status.numberAvailable || data.status.desiredNumberScheduled - data.status.numberUnavailable || 0;
|
||||
res.TotalPodsCount = data.status.desiredNumberScheduled;
|
||||
return res;
|
||||
|
@ -270,9 +267,9 @@ class KubernetesApplicationConverter {
|
|||
static apiStatefulSetToapplication(data, pods, service, ingresses) {
|
||||
const res = new KubernetesApplication();
|
||||
KubernetesApplicationConverter.applicationCommon(res, data, pods, service, ingresses);
|
||||
res.ApplicationType = KubernetesApplicationTypes.STATEFULSET;
|
||||
res.DeploymentType = KubernetesApplicationDeploymentTypes.REPLICATED;
|
||||
res.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.ISOLATED;
|
||||
res.ApplicationType = KubernetesApplicationTypes.StatefulSet;
|
||||
res.DeploymentType = KubernetesApplicationDeploymentTypes.Replicated;
|
||||
res.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.Isolated;
|
||||
res.RunningPodsCount = data.status.readyReplicas || 0;
|
||||
res.TotalPodsCount = data.spec.replicas;
|
||||
res.HeadlessServiceName = data.spec.serviceName;
|
||||
|
@ -313,16 +310,7 @@ class KubernetesApplicationConverter {
|
|||
res.PublishedPorts = KubernetesApplicationHelper.generatePublishedPortsFormValuesFromPublishedPorts(app.ServiceType, app.PublishedPorts, ingresses);
|
||||
res.Containers = app.Containers;
|
||||
|
||||
const isIngress = _.filter(res.PublishedPorts, (p) => p.IngressName).length;
|
||||
if (app.ServiceType === KubernetesServiceTypes.LOAD_BALANCER) {
|
||||
res.PublishingType = KubernetesApplicationPublishingTypes.LOAD_BALANCER;
|
||||
} else if (app.ServiceType === KubernetesServiceTypes.NODE_PORT) {
|
||||
res.PublishingType = KubernetesApplicationPublishingTypes.NODE_PORT;
|
||||
} else if (app.ServiceType === KubernetesServiceTypes.CLUSTER_IP && isIngress) {
|
||||
res.PublishingType = KubernetesApplicationPublishingTypes.INGRESS;
|
||||
} else {
|
||||
res.PublishingType = KubernetesApplicationPublishingTypes.CLUSTER_IP;
|
||||
}
|
||||
res.PublishingType = app.ServiceType;
|
||||
|
||||
if (app.Pods && app.Pods.length) {
|
||||
KubernetesApplicationHelper.generatePlacementsFormValuesFromAffinity(res, app.Pods[0].Affinity);
|
||||
|
@ -338,20 +326,20 @@ class KubernetesApplicationConverter {
|
|||
const rwx = KubernetesApplicationHelper.hasRWX(claims);
|
||||
|
||||
const deployment =
|
||||
(formValues.DeploymentType === KubernetesApplicationDeploymentTypes.REPLICATED &&
|
||||
(claims.length === 0 || (claims.length > 0 && formValues.DataAccessPolicy === KubernetesApplicationDataAccessPolicies.SHARED))) ||
|
||||
formValues.ApplicationType === KubernetesApplicationTypes.DEPLOYMENT;
|
||||
(formValues.DeploymentType === KubernetesApplicationDeploymentTypes.Replicated &&
|
||||
(claims.length === 0 || (claims.length > 0 && formValues.DataAccessPolicy === KubernetesApplicationDataAccessPolicies.Shared))) ||
|
||||
formValues.ApplicationType === KubernetesApplicationTypes.Deployment;
|
||||
|
||||
const statefulSet =
|
||||
(formValues.DeploymentType === KubernetesApplicationDeploymentTypes.REPLICATED &&
|
||||
(formValues.DeploymentType === KubernetesApplicationDeploymentTypes.Replicated &&
|
||||
claims.length > 0 &&
|
||||
formValues.DataAccessPolicy === KubernetesApplicationDataAccessPolicies.ISOLATED) ||
|
||||
formValues.ApplicationType === KubernetesApplicationTypes.STATEFULSET;
|
||||
formValues.DataAccessPolicy === KubernetesApplicationDataAccessPolicies.Isolated) ||
|
||||
formValues.ApplicationType === KubernetesApplicationTypes.StatefulSet;
|
||||
|
||||
const daemonSet =
|
||||
(formValues.DeploymentType === KubernetesApplicationDeploymentTypes.GLOBAL &&
|
||||
(claims.length === 0 || (claims.length > 0 && formValues.DataAccessPolicy === KubernetesApplicationDataAccessPolicies.SHARED && rwx))) ||
|
||||
formValues.ApplicationType === KubernetesApplicationTypes.DAEMONSET;
|
||||
(formValues.DeploymentType === KubernetesApplicationDeploymentTypes.Global &&
|
||||
(claims.length === 0 || (claims.length > 0 && formValues.DataAccessPolicy === KubernetesApplicationDataAccessPolicies.Shared && rwx))) ||
|
||||
formValues.ApplicationType === KubernetesApplicationTypes.DaemonSet;
|
||||
|
||||
let app;
|
||||
if (deployment) {
|
||||
|
@ -363,6 +351,7 @@ class KubernetesApplicationConverter {
|
|||
} else {
|
||||
throw new PortainerError('Unable to determine which association to use to convert form');
|
||||
}
|
||||
app.ApplicationType = formValues.ApplicationType;
|
||||
|
||||
let headlessService;
|
||||
if (statefulSet) {
|
||||
|
|
|
@ -71,7 +71,7 @@ class KubernetesPersistentVolumeClaimConverter {
|
|||
res.metadata.namespace = pvc.Namespace;
|
||||
res.spec.resources.requests.storage = pvc.Storage;
|
||||
res.spec.storageClassName = pvc.storageClass ? pvc.storageClass.Name : '';
|
||||
const accessModes = pvc.StorageClass && pvc.StorageClass.AccessModes ? pvc.StorageClass.AccessModes.map((accessMode) => storageClassToPVCAccessModes[accessMode]) : [];
|
||||
const accessModes = pvc.storageClass && pvc.storageClass.AccessModes ? pvc.storageClass.AccessModes.map((accessMode) => storageClassToPVCAccessModes[accessMode]) : [];
|
||||
res.spec.accessModes = accessModes;
|
||||
res.metadata.labels.app = pvc.ApplicationName;
|
||||
res.metadata.labels[KubernetesPortainerApplicationOwnerLabel] = pvc.ApplicationOwner;
|
||||
|
|
|
@ -3,7 +3,6 @@ import * as JsonPatch from 'fast-json-patch';
|
|||
|
||||
import { KubernetesServiceCreatePayload } from 'Kubernetes/models/service/payloads';
|
||||
import {
|
||||
KubernetesApplicationPublishingTypes,
|
||||
KubernetesPortainerApplicationNameLabel,
|
||||
KubernetesPortainerApplicationOwnerLabel,
|
||||
KubernetesPortainerApplicationStackNameLabel,
|
||||
|
@ -42,11 +41,7 @@ class KubernetesServiceConverter {
|
|||
res.StackName = formValues.StackName ? formValues.StackName : formValues.Name;
|
||||
res.ApplicationOwner = formValues.ApplicationOwner;
|
||||
res.ApplicationName = formValues.Name;
|
||||
if (formValues.PublishingType === KubernetesApplicationPublishingTypes.NODE_PORT) {
|
||||
res.Type = KubernetesServiceTypes.NODE_PORT;
|
||||
} else if (formValues.PublishingType === KubernetesApplicationPublishingTypes.LOAD_BALANCER) {
|
||||
res.Type = KubernetesServiceTypes.LOAD_BALANCER;
|
||||
}
|
||||
res.Type = formValues.PublishingType;
|
||||
const ports = _.map(formValues.PublishedPorts, (item) => _publishedPortToServicePort(formValues, item, res.Type));
|
||||
res.Ports = _.uniqBy(_.without(ports, undefined), (p) => p.targetPort + p.protocol);
|
||||
return res;
|
||||
|
@ -61,13 +56,7 @@ class KubernetesServiceConverter {
|
|||
res.StackName = formValues.StackName ? formValues.StackName : formValues.Name;
|
||||
res.ApplicationOwner = formValues.ApplicationOwner;
|
||||
res.ApplicationName = formValues.Name;
|
||||
if (service.Type === KubernetesApplicationPublishingTypes.NODE_PORT) {
|
||||
res.Type = KubernetesServiceTypes.NODE_PORT;
|
||||
} else if (service.Type === KubernetesApplicationPublishingTypes.LOAD_BALANCER) {
|
||||
res.Type = KubernetesServiceTypes.LOAD_BALANCER;
|
||||
} else if (service.Type === KubernetesApplicationPublishingTypes.CLUSTER_IP) {
|
||||
res.Type = KubernetesServiceTypes.CLUSTER_IP;
|
||||
}
|
||||
res.Type = service.Type;
|
||||
res.Ingress = service.Ingress;
|
||||
|
||||
if (service.Selector !== undefined) {
|
||||
|
@ -120,18 +109,7 @@ class KubernetesServiceConverter {
|
|||
payload.metadata.labels[KubernetesPortainerApplicationNameLabel] = service.ApplicationName;
|
||||
payload.metadata.labels[KubernetesPortainerApplicationOwnerLabel] = service.ApplicationOwner;
|
||||
|
||||
const ports = [];
|
||||
service.Ports.forEach((port) => {
|
||||
const p = {};
|
||||
p.name = port.name;
|
||||
p.port = port.port;
|
||||
p.nodePort = port.nodePort;
|
||||
p.protocol = port.protocol;
|
||||
p.targetPort = port.targetPort;
|
||||
ports.push(p);
|
||||
});
|
||||
payload.spec.ports = ports;
|
||||
|
||||
payload.spec.ports = service.Ports;
|
||||
payload.spec.selector = service.Selector;
|
||||
if (service.Headless) {
|
||||
payload.spec.clusterIP = KubernetesServiceHeadlessClusterIP;
|
||||
|
|
|
@ -1,29 +1,8 @@
|
|||
import _ from 'lodash-es';
|
||||
import { KubernetesApplicationDataAccessPolicies } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesApplicationTypes, KubernetesApplicationTypeStrings } from 'Kubernetes/models/application/models';
|
||||
import { nodeAffinityValues } from './application';
|
||||
|
||||
angular
|
||||
.module('portainer.kubernetes')
|
||||
.filter('kubernetesApplicationTypeText', function () {
|
||||
'use strict';
|
||||
return function (type) {
|
||||
switch (type) {
|
||||
case KubernetesApplicationTypes.DEPLOYMENT:
|
||||
return KubernetesApplicationTypeStrings.DEPLOYMENT;
|
||||
case KubernetesApplicationTypes.DAEMONSET:
|
||||
return KubernetesApplicationTypeStrings.DAEMONSET;
|
||||
case KubernetesApplicationTypes.STATEFULSET:
|
||||
return KubernetesApplicationTypeStrings.STATEFULSET;
|
||||
case KubernetesApplicationTypes.POD:
|
||||
return KubernetesApplicationTypeStrings.POD;
|
||||
case KubernetesApplicationTypes.HELM:
|
||||
return KubernetesApplicationTypeStrings.HELM;
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
};
|
||||
})
|
||||
.filter('kubernetesApplicationCPUValue', function () {
|
||||
'use strict';
|
||||
return function (value) {
|
||||
|
@ -34,31 +13,20 @@ angular
|
|||
'use strict';
|
||||
return function (value) {
|
||||
switch (value) {
|
||||
case KubernetesApplicationDataAccessPolicies.ISOLATED:
|
||||
case 'Isolated':
|
||||
return 'boxes';
|
||||
case KubernetesApplicationDataAccessPolicies.SHARED:
|
||||
case 'Shared':
|
||||
return 'box';
|
||||
}
|
||||
};
|
||||
})
|
||||
.filter('kubernetesApplicationDataAccessPolicyText', function () {
|
||||
'use strict';
|
||||
return function (value) {
|
||||
switch (value) {
|
||||
case KubernetesApplicationDataAccessPolicies.ISOLATED:
|
||||
return 'Isolated';
|
||||
case KubernetesApplicationDataAccessPolicies.SHARED:
|
||||
return 'Shared';
|
||||
}
|
||||
};
|
||||
})
|
||||
.filter('kubernetesApplicationDataAccessPolicyTooltip', function () {
|
||||
'use strict';
|
||||
return function (value) {
|
||||
switch (value) {
|
||||
case KubernetesApplicationDataAccessPolicies.ISOLATED:
|
||||
case 'Isolated':
|
||||
return 'All the instances of this application are using their own data.';
|
||||
case KubernetesApplicationDataAccessPolicies.SHARED:
|
||||
case 'Shared':
|
||||
return 'All the instances of this application are sharing the same data.';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,7 +22,8 @@ import {
|
|||
KubernetesApplicationVolumeSecretPayload,
|
||||
} from 'Kubernetes/models/application/payloads';
|
||||
import KubernetesVolumeHelper from 'Kubernetes/helpers/volumeHelper';
|
||||
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes, HelmApplication } from 'Kubernetes/models/application/models';
|
||||
import { HelmApplication } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
import { KubernetesPodAffinity, KubernetesPodNodeAffinityNodeSelectorRequirementOperators } from 'Kubernetes/pod/models';
|
||||
import {
|
||||
KubernetesNodeSelectorRequirementPayload,
|
||||
|
@ -287,13 +288,6 @@ class KubernetesApplicationHelper {
|
|||
svc.ApplicationOwner = app.ApplicationOwner;
|
||||
svc.ApplicationName = app.ApplicationName;
|
||||
svc.Type = service.spec.type;
|
||||
if (service.spec.type === KubernetesServiceTypes.CLUSTER_IP) {
|
||||
svc.Type = 1;
|
||||
} else if (service.spec.type === KubernetesServiceTypes.NODE_PORT) {
|
||||
svc.Type = 2;
|
||||
} else if (service.spec.type === KubernetesServiceTypes.LOAD_BALANCER) {
|
||||
svc.Type = 3;
|
||||
}
|
||||
|
||||
let ports = [];
|
||||
service.spec.ports.forEach(function (port) {
|
||||
|
@ -373,15 +367,15 @@ class KubernetesApplicationHelper {
|
|||
static generateAutoScalerFormValueFromHorizontalPodAutoScaler(autoScaler, replicasCount) {
|
||||
const res = new KubernetesApplicationAutoScalerFormValue();
|
||||
if (autoScaler) {
|
||||
res.IsUsed = true;
|
||||
res.MinReplicas = autoScaler.MinReplicas;
|
||||
res.MaxReplicas = autoScaler.MaxReplicas;
|
||||
res.TargetCPUUtilization = autoScaler.TargetCPUUtilization;
|
||||
res.ApiVersion = autoScaler.ApiVersion;
|
||||
res.isUsed = true;
|
||||
res.minReplicas = autoScaler.MinReplicas;
|
||||
res.maxReplicas = autoScaler.MaxReplicas;
|
||||
res.targetCpuUtilizationPercentage = autoScaler.TargetCPUUtilization;
|
||||
res.apiVersion = autoScaler.ApiVersion;
|
||||
} else {
|
||||
res.ApiVersion = 'apps/v1';
|
||||
res.MinReplicas = replicasCount;
|
||||
res.MaxReplicas = replicasCount;
|
||||
res.apiVersion = 'apps/v1';
|
||||
res.minReplicas = replicasCount;
|
||||
res.maxReplicas = replicasCount;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -461,7 +455,7 @@ class KubernetesApplicationHelper {
|
|||
}
|
||||
|
||||
static generateAffinityFromPlacements(app, formValues) {
|
||||
if (formValues.DeploymentType === KubernetesApplicationDeploymentTypes.REPLICATED) {
|
||||
if (formValues.DeploymentType === KubernetesApplicationDeploymentTypes.Replicated) {
|
||||
const placements = formValues.Placements;
|
||||
const res = new KubernetesPodNodeAffinityPayload();
|
||||
let expressions = _.map(placements, (p) => {
|
||||
|
@ -545,7 +539,7 @@ class KubernetesApplicationHelper {
|
|||
const helmAppsList = helmAppsEntriesList.map(([helmInstance, applications]) => {
|
||||
const helmApp = new HelmApplication();
|
||||
helmApp.Name = helmInstance;
|
||||
helmApp.ApplicationType = KubernetesApplicationTypes.HELM;
|
||||
helmApp.ApplicationType = KubernetesApplicationTypes.Helm;
|
||||
helmApp.ApplicationOwner = applications[0].ApplicationOwner;
|
||||
helmApp.KubernetesApplications = applications;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import _ from 'lodash-es';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
|
||||
class KubernetesVolumeHelper {
|
||||
// TODO: review
|
||||
// the following condition
|
||||
// && (app.ApplicationType === KubernetesApplicationTypes.STATEFULSET ? _.includes(volume.PersistentVolumeClaim.Name, app.Name) : true);
|
||||
// && (app.ApplicationType === KubernetesApplicationTypes.StatefulSet ? _.includes(volume.PersistentVolumeClaim.Name, app.Name) : true);
|
||||
// is made to enforce finding the good SFS when multiple SFS in the same namespace
|
||||
// are referencing an internal PVC using the same internal name
|
||||
// (PVC are not exposed to other apps so they can have the same name in differents SFS)
|
||||
|
@ -16,7 +16,7 @@ class KubernetesVolumeHelper {
|
|||
return (
|
||||
volume.ResourcePool.Namespace.Name === app.ResourcePool &&
|
||||
matchingNames.length &&
|
||||
(app.ApplicationType === KubernetesApplicationTypes.STATEFULSET ? _.includes(volume.PersistentVolumeClaim.Name, app.Name) : true)
|
||||
(app.ApplicationType === KubernetesApplicationTypes.StatefulSet ? _.includes(volume.PersistentVolumeClaim.Name, app.Name) : true)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export class KubernetesHorizontalPodAutoScalerConverter {
|
|||
payload.metadata.name = data.TargetEntity.Name;
|
||||
payload.spec.minReplicas = data.MinReplicas;
|
||||
payload.spec.maxReplicas = data.MaxReplicas;
|
||||
payload.spec.targetCPUUtilizationPercentage = data.TargetCPUUtilization;
|
||||
payload.spec.targetCPUUtilizationPercentage = data.targetCpuUtilizationPercentage;
|
||||
payload.spec.scaleTargetRef.apiVersion = data.TargetEntity.ApiVersion;
|
||||
payload.spec.scaleTargetRef.kind = data.TargetEntity.Kind;
|
||||
payload.spec.scaleTargetRef.name = data.TargetEntity.Name;
|
||||
|
@ -48,86 +48,12 @@ export class KubernetesHorizontalPodAutoScalerConverter {
|
|||
const res = new KubernetesHorizontalPodAutoScaler();
|
||||
res.Name = formValues.Name;
|
||||
res.Namespace = formValues.ResourcePool.Namespace.Name;
|
||||
res.MinReplicas = formValues.AutoScaler.MinReplicas;
|
||||
res.MaxReplicas = formValues.AutoScaler.MaxReplicas;
|
||||
res.TargetCPUUtilization = formValues.AutoScaler.TargetCPUUtilization;
|
||||
res.MinReplicas = formValues.AutoScaler.minReplicas;
|
||||
res.MaxReplicas = formValues.AutoScaler.maxReplicas;
|
||||
res.TargetCPUUtilization = formValues.AutoScaler.targetCpuUtilizationPercentage;
|
||||
res.TargetEntity.Name = formValues.Name;
|
||||
res.TargetEntity.Kind = kind;
|
||||
res.TargetEntity.ApiVersion = formValues.AutoScaler.ApiVersion;
|
||||
res.TargetEntity.ApiVersion = formValues.AutoScaler.apiVersion;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertion functions to use with v2beta2 model
|
||||
*/
|
||||
|
||||
// static apiToModel(data, yaml) {
|
||||
// const res = new KubernetesHorizontalPodAutoScaler();
|
||||
// res.Id = data.metadata.uid;
|
||||
// res.Namespace = data.metadata.namespace;
|
||||
// res.Name = data.metadata.name;
|
||||
// res.MinReplicas = data.spec.minReplicas;
|
||||
// res.MaxReplicas = data.spec.maxReplicas;
|
||||
// res.TargetCPUUtilization = data.spec.targetCPUUtilization;
|
||||
|
||||
// _.forEach(data.spec.metrics, (metric) => {
|
||||
// if (metric.type === 'Resource') {
|
||||
// if (metric.resource.name === 'cpu') {
|
||||
// res.TargetCPUUtilization = metric.resource.target.averageUtilization;
|
||||
// }
|
||||
// if (metric.resource.name === 'memory') {
|
||||
// res.TargetMemoryValue = parseFloat(metric.resource.target.averageValue) / 1000;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// if (data.spec.scaleTargetRef) {
|
||||
// res.TargetEntity.ApiVersion = data.spec.scaleTargetRef.apiVersion;
|
||||
// res.TargetEntity.Kind = data.spec.scaleTargetRef.kind;
|
||||
// res.TargetEntity.Name = data.spec.scaleTargetRef.name;
|
||||
// }
|
||||
// res.Yaml = yaml ? yaml.data : '';
|
||||
// return res;
|
||||
// }
|
||||
|
||||
// static createPayload(data) {
|
||||
// const payload = new KubernetesHorizontalPodAutoScalerCreatePayload();
|
||||
// payload.metadata.namespace = data.Namespace;
|
||||
// payload.metadata.name = data.TargetEntity.Name;
|
||||
// payload.spec.minReplicas = data.MinReplicas;
|
||||
// payload.spec.maxReplicas = data.MaxReplicas;
|
||||
|
||||
// if (data.TargetMemoryValue) {
|
||||
// const memoryMetric = new KubernetesHorizontalPodAutoScalerMemoryMetric();
|
||||
// memoryMetric.resource.target.averageValue = data.TargetMemoryValue;
|
||||
// payload.spec.metrics.push(memoryMetric);
|
||||
// }
|
||||
|
||||
// if (data.TargetCPUUtilization) {
|
||||
// const cpuMetric = new KubernetesHorizontalPodAutoScalerCPUMetric();
|
||||
// cpuMetric.resource.target.averageUtilization = data.TargetCPUUtilization;
|
||||
// payload.spec.metrics.push(cpuMetric);
|
||||
// }
|
||||
|
||||
// payload.spec.scaleTargetRef.apiVersion = data.TargetEntity.ApiVersion;
|
||||
// payload.spec.scaleTargetRef.kind = data.TargetEntity.Kind;
|
||||
// payload.spec.scaleTargetRef.name = data.TargetEntity.Name;
|
||||
|
||||
// return payload;
|
||||
// }
|
||||
|
||||
// static applicationFormValuesToModel(formValues, kind) {
|
||||
// const res = new KubernetesHorizontalPodAutoScaler();
|
||||
// res.Name = formValues.Name;
|
||||
// res.Namespace = formValues.ResourcePool.Namespace.Name;
|
||||
// res.MinReplicas = formValues.AutoScaler.MinReplicas;
|
||||
// res.MaxReplicas = formValues.AutoScaler.MaxReplicas;
|
||||
// res.TargetCPUUtilization = formValues.AutoScaler.TargetCPUUtilization;
|
||||
// if (formValues.AutoScaler.TargetMemoryValue) {
|
||||
// res.TargetMemoryValue = formValues.AutoScaler.TargetMemoryValue + 'M';
|
||||
// }
|
||||
// res.TargetEntity.Name = formValues.Name;
|
||||
// res.TargetEntity.Kind = kind;
|
||||
// return res;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,27 +1,8 @@
|
|||
import _ from 'lodash-es';
|
||||
import PortainerError from 'Portainer/error';
|
||||
import { KubernetesApplication, KubernetesApplicationTypes, KubernetesApplicationTypeStrings } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesDeployment } from 'Kubernetes/models/deployment/models';
|
||||
import { KubernetesStatefulSet } from 'Kubernetes/models/stateful-set/models';
|
||||
import { KubernetesDaemonSet } from 'Kubernetes/models/daemon-set/models';
|
||||
|
||||
export class KubernetesHorizontalPodAutoScalerHelper {
|
||||
static findApplicationBoundScaler(sList, app) {
|
||||
const kind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(app);
|
||||
const kind = app.ApplicationType;
|
||||
return _.find(sList, (item) => item.TargetEntity.Kind === kind && item.TargetEntity.Name === app.Name);
|
||||
}
|
||||
|
||||
static getApplicationTypeString(app) {
|
||||
if ((app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.DEPLOYMENT) || app instanceof KubernetesDeployment) {
|
||||
return KubernetesApplicationTypeStrings.DEPLOYMENT;
|
||||
} else if ((app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.DAEMONSET) || app instanceof KubernetesDaemonSet) {
|
||||
return KubernetesApplicationTypeStrings.DAEMONSET;
|
||||
} else if ((app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.STATEFULSET) || app instanceof KubernetesStatefulSet) {
|
||||
return KubernetesApplicationTypeStrings.STATEFULSET;
|
||||
} else if (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.POD) {
|
||||
return KubernetesApplicationTypeStrings.POD;
|
||||
} else {
|
||||
throw new PortainerError('Unable to determine application type');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
KubernetesResourcePoolIngressClassFormValue,
|
||||
KubernetesResourcePoolIngressClassHostFormValue,
|
||||
} from 'Kubernetes/models/resource-pool/formValues';
|
||||
import { KubernetesApplicationPublishingTypes } from '../models/application/models';
|
||||
import { KubernetesIngress, KubernetesIngressRule } from './models';
|
||||
import { KubernetesIngressCreatePayload, KubernetesIngressRuleCreatePayload, KubernetesIngressRulePathCreatePayload } from './payloads';
|
||||
import { KubernetesIngressClassAnnotation, PortainerIngressClassTypes } from './constants';
|
||||
|
@ -48,36 +47,6 @@ export class KubernetesIngressConverter {
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Application Form Value (from Create Application View) to Ingresses
|
||||
* @param {KubernetesApplicationFormValues} formValues
|
||||
* @param {string} serviceName
|
||||
* @returns {KubernetesIngressRule[]}
|
||||
*/
|
||||
static applicationFormValuesToIngresses(formValues, serviceName) {
|
||||
const isPublishingToIngress = formValues.PublishingType === KubernetesApplicationPublishingTypes.INGRESS;
|
||||
const ingresses = angular.copy(formValues.OriginalIngresses);
|
||||
_.forEach(formValues.PublishedPorts, (p) => {
|
||||
const ingress = _.find(ingresses, { Name: p.IngressName });
|
||||
if (ingress) {
|
||||
if (p.NeedsDeletion) {
|
||||
_.remove(ingress.Paths, (path) => path.Port === p.ContainerPort && path.ServiceName === serviceName && path.Path === p.IngressRoute);
|
||||
} else if (isPublishingToIngress && p.IsNew) {
|
||||
const rule = new KubernetesIngressRule();
|
||||
rule.IngressName = ingress.Name;
|
||||
rule.ServiceName = serviceName;
|
||||
rule.Port = p.ContainerPort;
|
||||
if (p.IngressRoute) {
|
||||
rule.Path = _.startsWith(p.IngressRoute, '/') ? p.IngressRoute : '/' + p.IngressRoute;
|
||||
}
|
||||
rule.Host = p.IngressHost;
|
||||
ingress.Paths.push(rule);
|
||||
}
|
||||
}
|
||||
});
|
||||
return ingresses;
|
||||
}
|
||||
|
||||
static applicationFormValuesToDeleteIngresses(formValues, application) {
|
||||
const ingresses = angular.copy(formValues.OriginalIngresses);
|
||||
application.Services.forEach((service) => {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { PorImageRegistryModel } from '@/docker/models/porImageRegistry';
|
||||
import { KubernetesApplicationDataAccessPolicies, KubernetesApplicationDeploymentTypes } from './models';
|
||||
import { KubernetesApplicationTypes, KubernetesApplicationDeploymentTypes, KubernetesApplicationDataAccessPolicies } from 'Kubernetes/models/application/models/appConstants';
|
||||
|
||||
/**
|
||||
* KubernetesApplicationFormValues Model
|
||||
*/
|
||||
export function KubernetesApplicationFormValues() {
|
||||
this.ApplicationType = undefined; // will only exist for formValues generated from Application (app edit situation;
|
||||
this.ApplicationType = KubernetesApplicationTypes.Deployment; // will only exist for formValues generated from Application (app edit situation;
|
||||
this.ResourcePool = {};
|
||||
this.Name = '';
|
||||
this.StackName = '';
|
||||
|
@ -14,13 +14,13 @@ export function KubernetesApplicationFormValues() {
|
|||
this.Note = '';
|
||||
this.MemoryLimit = 0;
|
||||
this.CpuLimit = 0;
|
||||
this.DeploymentType = KubernetesApplicationDeploymentTypes.REPLICATED;
|
||||
this.DeploymentType = KubernetesApplicationDeploymentTypes.Replicated;
|
||||
this.ReplicaCount = 1;
|
||||
this.AutoScaler = {};
|
||||
this.Containers = [];
|
||||
this.Services = [];
|
||||
this.EnvironmentVariables = []; // KubernetesApplicationEnvironmentVariableFormValue lis;
|
||||
this.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.ISOLATED;
|
||||
this.DataAccessPolicy = KubernetesApplicationDataAccessPolicies.Isolated;
|
||||
this.PersistedFolders = []; // KubernetesApplicationPersistedFolderFormValue lis;
|
||||
this.ConfigMaps = [];
|
||||
this.Secrets = [];
|
||||
|
@ -130,11 +130,11 @@ export function KubernetesApplicationPlacementFormValue() {
|
|||
* KubernetesApplicationAutoScalerFormValue Model
|
||||
*/
|
||||
const _KubernetesApplicationAutoScalerFormValue = Object.freeze({
|
||||
MinReplicas: 0,
|
||||
MaxReplicas: 0,
|
||||
TargetCPUUtilization: 50,
|
||||
ApiVersion: '',
|
||||
IsUsed: false,
|
||||
minReplicas: 0,
|
||||
maxReplicas: 0,
|
||||
targetCpuUtilizationPercentage: 50,
|
||||
apiVersion: '',
|
||||
isUsed: false,
|
||||
});
|
||||
|
||||
export class KubernetesApplicationAutoScalerFormValue {
|
||||
|
|
41
app/kubernetes/models/application/models/appConstants.ts
Normal file
41
app/kubernetes/models/application/models/appConstants.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import {
|
||||
AppType,
|
||||
AppDataAccessPolicy,
|
||||
DeploymentType,
|
||||
} from '@/react/kubernetes/applications/types';
|
||||
import { ServiceType } from '@/react/kubernetes/services/types';
|
||||
|
||||
// The following constants are used by angular views and can be removed once they are no longer referenced
|
||||
export const KubernetesApplicationTypes: Record<AppType, AppType> = {
|
||||
Deployment: 'Deployment',
|
||||
StatefulSet: 'StatefulSet',
|
||||
DaemonSet: 'DaemonSet',
|
||||
Pod: 'Pod',
|
||||
Helm: 'Helm',
|
||||
} as const;
|
||||
|
||||
export const KubernetesApplicationDeploymentTypes: Record<
|
||||
DeploymentType,
|
||||
DeploymentType
|
||||
> = {
|
||||
Global: 'Global',
|
||||
Replicated: 'Replicated',
|
||||
} as const;
|
||||
|
||||
export const KubernetesApplicationDataAccessPolicies: Record<
|
||||
AppDataAccessPolicy,
|
||||
AppDataAccessPolicy
|
||||
> = {
|
||||
Isolated: 'Isolated',
|
||||
Shared: 'Shared',
|
||||
} as const;
|
||||
|
||||
export const KubernetesApplicationServiceTypes: Record<
|
||||
ServiceType,
|
||||
ServiceType
|
||||
> = {
|
||||
ClusterIP: 'ClusterIP',
|
||||
NodePort: 'NodePort',
|
||||
LoadBalancer: 'LoadBalancer',
|
||||
ExternalName: 'ExternalName',
|
||||
} as const;
|
|
@ -1,35 +1,3 @@
|
|||
export const KubernetesApplicationDeploymentTypes = Object.freeze({
|
||||
REPLICATED: 1,
|
||||
GLOBAL: 2,
|
||||
});
|
||||
|
||||
export const KubernetesApplicationDataAccessPolicies = Object.freeze({
|
||||
SHARED: 1,
|
||||
ISOLATED: 2,
|
||||
});
|
||||
|
||||
export const KubernetesApplicationTypes = Object.freeze({
|
||||
DEPLOYMENT: 1,
|
||||
DAEMONSET: 2,
|
||||
STATEFULSET: 3,
|
||||
POD: 4,
|
||||
HELM: 5,
|
||||
});
|
||||
|
||||
export const KubernetesApplicationTypeStrings = Object.freeze({
|
||||
HELM: 'Helm',
|
||||
DEPLOYMENT: 'Deployment',
|
||||
DAEMONSET: 'DaemonSet',
|
||||
STATEFULSET: 'StatefulSet',
|
||||
POD: 'Pod',
|
||||
});
|
||||
|
||||
export const KubernetesApplicationPublishingTypes = Object.freeze({
|
||||
CLUSTER_IP: 1,
|
||||
NODE_PORT: 2,
|
||||
LOAD_BALANCER: 3,
|
||||
});
|
||||
|
||||
export const KubernetesApplicationQuotaDefaults = {
|
||||
CpuLimit: 0.1,
|
||||
MemoryLimit: 64, // MB
|
||||
|
|
|
@ -6,7 +6,6 @@ import { NamespacesSelector } from '@/react/kubernetes/cluster/RegistryAccessVie
|
|||
import { StorageAccessModeSelector } from '@/react/kubernetes/cluster/ConfigureView/ConfigureForm/StorageAccessModeSelector';
|
||||
import { NamespaceAccessUsersSelector } from '@/react/kubernetes/namespaces/AccessView/NamespaceAccessUsersSelector';
|
||||
import { RegistriesSelector } from '@/react/kubernetes/namespaces/components/RegistriesFormSection/RegistriesSelector';
|
||||
import { DataAccessPolicyFormSection } from '@/react/kubernetes/applications/CreateView/DataAccessPolicyFormSection';
|
||||
import { KubeServicesForm } from '@/react/kubernetes/applications/CreateView/application-services/KubeServicesForm';
|
||||
import { kubeServicesValidation } from '@/react/kubernetes/applications/CreateView/application-services/kubeServicesValidation';
|
||||
import { AppDeploymentTypeFormSection } from '@/react/kubernetes/applications/CreateView/AppDeploymentTypeFormSection';
|
||||
|
@ -22,6 +21,7 @@ import {
|
|||
PlacementFormSection,
|
||||
placementValidation,
|
||||
} from '@/react/kubernetes/applications/components/PlacementFormSection';
|
||||
import { ApplicationSummarySection } from '@/react/kubernetes/applications/components/ApplicationSummarySection';
|
||||
import { withFormValidation } from '@/react-tools/withFormValidation';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { YAMLInspector } from '@/react/kubernetes/components/YAMLInspector';
|
||||
|
@ -33,6 +33,7 @@ import { SecretsFormSection } from '@/react/kubernetes/applications/components/C
|
|||
import { configurationsValidationSchema } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/configurationValidationSchema';
|
||||
import { ConfigMapsFormSection } from '@/react/kubernetes/applications/components/ConfigurationsFormSection/ConfigMapsFormSection';
|
||||
import { PersistedFoldersFormSection } from '@/react/kubernetes/applications/components/PersistedFoldersFormSection';
|
||||
import { DataAccessPolicyFormSection } from '@/react/kubernetes/applications/CreateView/DataAccessPolicyFormSection';
|
||||
import { persistedFoldersValidation } from '@/react/kubernetes/applications/components/PersistedFoldersFormSection/persistedFoldersValidation';
|
||||
import {
|
||||
ResourceReservationFormSection,
|
||||
|
@ -46,6 +47,7 @@ import {
|
|||
AutoScalingFormSection,
|
||||
autoScalingValidation,
|
||||
} from '@/react/kubernetes/applications/components/AutoScalingFormSection';
|
||||
import { withControlledInput } from '@/react-tools/withControlledInput';
|
||||
|
||||
import { EnvironmentVariablesFieldset } from '@@/form-components/EnvironmentVariablesFieldset';
|
||||
|
||||
|
@ -112,7 +114,7 @@ export const ngModule = angular
|
|||
r2a(withUIRouter(withReactQuery(withCurrentUser(NodesDatatable))), [])
|
||||
)
|
||||
.component(
|
||||
'dataAccessPolicyFormSection',
|
||||
'accessPolicyFormSection',
|
||||
r2a(DataAccessPolicyFormSection, [
|
||||
'value',
|
||||
'onChange',
|
||||
|
@ -174,6 +176,13 @@ export const ngModule = angular
|
|||
[]
|
||||
)
|
||||
)
|
||||
.component(
|
||||
'applicationSummarySection',
|
||||
r2a(
|
||||
withUIRouter(withReactQuery(withCurrentUser(ApplicationSummarySection))),
|
||||
['formValues', 'oldFormValues']
|
||||
)
|
||||
)
|
||||
.component(
|
||||
'kubernetesApplicationsStacksDatatable',
|
||||
r2a(withUIRouter(withCurrentUser(ApplicationsStacksDatatable)), [
|
||||
|
@ -193,7 +202,9 @@ export const componentsModule = ngModule.name;
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(KubeServicesForm))),
|
||||
withControlledInput(
|
||||
withUIRouter(withCurrentUser(withReactQuery(KubeServicesForm)))
|
||||
),
|
||||
'kubeServicesForm',
|
||||
['values', 'onChange', 'appName', 'selector', 'isEditMode', 'namespace'],
|
||||
kubeServicesValidation
|
||||
|
@ -201,7 +212,7 @@ withFormValidation(
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
EnvironmentVariablesFieldset,
|
||||
withControlledInput(EnvironmentVariablesFieldset),
|
||||
'kubeEnvironmentVariablesFieldset',
|
||||
['canUndoDelete'],
|
||||
// use kubeEnvVarValidationSchema instead of envVarValidation to add a regex matches rule
|
||||
|
@ -210,7 +221,9 @@ withFormValidation(
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(ConfigMapsFormSection))),
|
||||
withControlledInput(
|
||||
withUIRouter(withCurrentUser(withReactQuery(ConfigMapsFormSection)))
|
||||
),
|
||||
'configMapsFormSection',
|
||||
['values', 'onChange', 'namespace'],
|
||||
configurationsValidationSchema
|
||||
|
@ -218,7 +231,9 @@ withFormValidation(
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(SecretsFormSection))),
|
||||
withControlledInput(
|
||||
withUIRouter(withCurrentUser(withReactQuery(SecretsFormSection)))
|
||||
),
|
||||
'secretsFormSection',
|
||||
['values', 'onChange', 'namespace'],
|
||||
configurationsValidationSchema
|
||||
|
@ -240,7 +255,11 @@ withFormValidation(
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(ResourceReservationFormSection))),
|
||||
withControlledInput(
|
||||
withUIRouter(
|
||||
withCurrentUser(withReactQuery(ResourceReservationFormSection))
|
||||
)
|
||||
),
|
||||
'resourceReservationFormSection',
|
||||
[
|
||||
'namespaceHasQuota',
|
||||
|
@ -253,7 +272,9 @@ withFormValidation(
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(ReplicationFormSection))),
|
||||
withControlledInput(
|
||||
withUIRouter(withCurrentUser(withReactQuery(ReplicationFormSection)))
|
||||
),
|
||||
'replicationFormSection',
|
||||
[
|
||||
'supportScalableReplicaDeployment',
|
||||
|
@ -266,7 +287,9 @@ withFormValidation(
|
|||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
withUIRouter(withCurrentUser(withReactQuery(AutoScalingFormSection))),
|
||||
withControlledInput(
|
||||
withUIRouter(withCurrentUser(withReactQuery(AutoScalingFormSection)))
|
||||
),
|
||||
'autoScalingFormSection',
|
||||
['isMetricsEnabled'],
|
||||
autoScalingValidation
|
||||
|
|
|
@ -2,12 +2,9 @@ import _ from 'lodash-es';
|
|||
import angular from 'angular';
|
||||
import PortainerError from 'Portainer/error';
|
||||
|
||||
import { KubernetesApplication, KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
|
||||
import KubernetesApplicationConverter from 'Kubernetes/converters/application';
|
||||
import { KubernetesDeployment } from 'Kubernetes/models/deployment/models';
|
||||
import { KubernetesStatefulSet } from 'Kubernetes/models/stateful-set/models';
|
||||
import { KubernetesDaemonSet } from 'Kubernetes/models/daemon-set/models';
|
||||
import KubernetesServiceHelper from 'Kubernetes/helpers/serviceHelper';
|
||||
import { KubernetesHorizontalPodAutoScalerHelper } from 'Kubernetes/horizontal-pod-auto-scaler/helper';
|
||||
import { KubernetesHorizontalPodAutoScalerConverter } from 'Kubernetes/horizontal-pod-auto-scaler/converter';
|
||||
|
@ -15,6 +12,7 @@ import KubernetesPodConverter from 'Kubernetes/pod/converter';
|
|||
import { notifyError } from '@/portainer/services/notifications';
|
||||
import { KubernetesIngressConverter } from 'Kubernetes/ingress/converter';
|
||||
import { generateNewIngressesFromFormPaths } from '@/react/kubernetes/applications/CreateView/application-services/utils';
|
||||
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
|
||||
class KubernetesApplicationService {
|
||||
/* #region CONSTRUCTOR */
|
||||
|
@ -58,13 +56,13 @@ class KubernetesApplicationService {
|
|||
/* #region UTILS */
|
||||
_getApplicationApiService(app) {
|
||||
let apiService;
|
||||
if (app instanceof KubernetesDeployment || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.DEPLOYMENT)) {
|
||||
if (app.ApplicationType === KubernetesApplicationTypes.Deployment) {
|
||||
apiService = this.KubernetesDeploymentService;
|
||||
} else if (app instanceof KubernetesDaemonSet || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.DAEMONSET)) {
|
||||
} else if (app.ApplicationType === KubernetesApplicationTypes.DaemonSet) {
|
||||
apiService = this.KubernetesDaemonSetService;
|
||||
} else if (app instanceof KubernetesStatefulSet || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.STATEFULSET)) {
|
||||
} else if (app.ApplicationType === KubernetesApplicationTypes.StatefulSet) {
|
||||
apiService = this.KubernetesStatefulSetService;
|
||||
} else if (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.POD) {
|
||||
} else if (app.ApplicationType === KubernetesApplicationTypes.Pod) {
|
||||
apiService = this.KubernetesPodService;
|
||||
} else {
|
||||
throw new PortainerError('Unable to determine which association to use to retrieve API Service');
|
||||
|
@ -257,8 +255,8 @@ class KubernetesApplicationService {
|
|||
await Promise.all(_.without(claimPromises, undefined));
|
||||
}
|
||||
|
||||
if (formValues.AutoScaler.IsUsed && formValues.DeploymentType !== KubernetesApplicationDeploymentTypes.GLOBAL) {
|
||||
const kind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(app);
|
||||
if (formValues.AutoScaler.isUsed && formValues.DeploymentType !== KubernetesApplicationDeploymentTypes.Global) {
|
||||
const kind = app.ApplicationType;
|
||||
const autoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(formValues, kind);
|
||||
await this.KubernetesHorizontalPodAutoScalerService.create(autoScaler);
|
||||
}
|
||||
|
@ -378,16 +376,16 @@ class KubernetesApplicationService {
|
|||
}
|
||||
}
|
||||
|
||||
const newKind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(newApp);
|
||||
const newKind = newApp.ApplicationType;
|
||||
const newAutoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(newFormValues, newKind);
|
||||
if (!oldFormValues.AutoScaler.IsUsed) {
|
||||
if (newFormValues.AutoScaler.IsUsed) {
|
||||
if (!oldFormValues.AutoScaler.isUsed) {
|
||||
if (newFormValues.AutoScaler.isUsed) {
|
||||
await this.KubernetesHorizontalPodAutoScalerService.create(newAutoScaler);
|
||||
}
|
||||
} else {
|
||||
const oldKind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(oldApp);
|
||||
const oldKind = oldApp.ApplicationType;
|
||||
const oldAutoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(oldFormValues, oldKind);
|
||||
if (newFormValues.AutoScaler.IsUsed) {
|
||||
if (newFormValues.AutoScaler.isUsed) {
|
||||
await this.KubernetesHorizontalPodAutoScalerService.patch(oldAutoScaler, newAutoScaler);
|
||||
} else {
|
||||
await this.KubernetesHorizontalPodAutoScalerService.delete(oldAutoScaler);
|
||||
|
|
|
@ -3,7 +3,7 @@ import _ from 'lodash-es';
|
|||
import KubernetesStackHelper from 'Kubernetes/helpers/stackHelper';
|
||||
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
|
||||
import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper';
|
||||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
import { KubernetesPortainerApplicationStackNameLabel } from 'Kubernetes/models/application/models';
|
||||
import { confirmDelete } from '@@/modals/confirm';
|
||||
import { getDeploymentOptions } from '@/react/portainer/environments/environment.service';
|
||||
|
@ -90,7 +90,7 @@ class KubernetesApplicationsController {
|
|||
let actionCount = selectedItems.length;
|
||||
for (const application of selectedItems) {
|
||||
try {
|
||||
if (application.ApplicationType === KubernetesApplicationTypes.HELM) {
|
||||
if (application.ApplicationType === KubernetesApplicationTypes.Helm) {
|
||||
await this.HelmService.uninstall(this.endpoint.Id, application);
|
||||
} else {
|
||||
await this.KubernetesApplicationService.delete(application);
|
||||
|
|
|
@ -103,9 +103,16 @@
|
|||
></kube-services-form>
|
||||
</div>
|
||||
<!-- kubernetes services options -->
|
||||
<kubernetes-summary-view form-values="ctrl.formValues" old-form-values="ctrl.savedFormValues"></kubernetes-summary-view>
|
||||
<!-- #region ACTIONS -->
|
||||
<!-- kubernetes summary for external application -->
|
||||
<application-summary-section
|
||||
application-kind="ctrl.formValues.ApplicationType"
|
||||
form-values="ctrl.formValues"
|
||||
old-form-values="ctrl.savedFormValues"
|
||||
ng-if="ctrl.isExternalApplication()"
|
||||
></application-summary-section>
|
||||
<!-- kubernetes summary for external application -->
|
||||
<div class="col-sm-12 form-section-title !mt-6" ng-if="ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.GIT" ng-hide="ctrl.stack.IsComposeFormat"> Actions </div>
|
||||
<!-- #region ACTIONS -->
|
||||
<div class="form-group" ng-hide="ctrl.stack.IsComposeFormat">
|
||||
<div class="col-sm-12">
|
||||
<button
|
||||
|
@ -423,12 +430,12 @@
|
|||
|
||||
<!-- #region DATA ACCESS POLICY -->
|
||||
<div ng-if="ctrl.showDataAccessPolicySection()">
|
||||
<data-access-policy-form-section
|
||||
<access-policy-form-section
|
||||
value="ctrl.formValues.DataAccessPolicy"
|
||||
on-change="(ctrl.onDataAccessPolicyChange)"
|
||||
is-edit="ctrl.state.isEdit"
|
||||
persisted-folders-use-existing-volumes="ctrl.state.persistedFoldersUseExistingVolumes"
|
||||
></data-access-policy-form-section>
|
||||
></access-policy-form-section>
|
||||
</div>
|
||||
<!-- #endregion -->
|
||||
|
||||
|
@ -451,7 +458,7 @@
|
|||
></app-deployment-type-form-section>
|
||||
|
||||
<!-- replica count -->
|
||||
<div ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED">
|
||||
<div ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.Replicated">
|
||||
<replication-form-section
|
||||
values="{replicaCount: ctrl.formValues.ReplicaCount}"
|
||||
on-change="(ctrl.onChangeReplicaCount)"
|
||||
|
@ -466,9 +473,9 @@
|
|||
<!-- #endregion -->
|
||||
|
||||
<!-- #region AUTO SCALING -->
|
||||
<div ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL">
|
||||
<div ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.Global">
|
||||
<auto-scaling-form-section
|
||||
values="{isUsed: ctrl.formValues.AutoScaler.IsUsed, minReplicas: ctrl.formValues.AutoScaler.MinReplicas, maxReplicas: ctrl.formValues.AutoScaler.MaxReplicas, targetCpuUtilizationPercentage: ctrl.formValues.AutoScaler.TargetCPUUtilization}"
|
||||
values="ctrl.formValues.AutoScaler"
|
||||
on-change="(ctrl.onAutoScaleChange)"
|
||||
validation-data="{autoScalerOverflow: ctrl.autoScalerOverflow()}"
|
||||
is-metrics-enabled="ctrl.state.useServerMetrics"
|
||||
|
@ -478,7 +485,7 @@
|
|||
</div>
|
||||
|
||||
<placement-form-section
|
||||
ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED"
|
||||
ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.Replicated"
|
||||
values="{placements: ctrl.formValues.Placements, placementType: ctrl.formValues.PlacementType}"
|
||||
on-change="(ctrl.onChangePlacements)"
|
||||
></placement-form-section>
|
||||
|
@ -497,11 +504,12 @@
|
|||
></kube-services-form>
|
||||
</div>
|
||||
<!-- kubernetes services options -->
|
||||
<kubernetes-summary-view
|
||||
<application-summary-section
|
||||
application-kind="ctrl.formValues.ApplicationType"
|
||||
ng-if="!(!kubernetesApplicationCreationForm.$valid || ctrl.isDeployUpdateButtonDisabled() || !ctrl.state.pullImageValidity)"
|
||||
form-values="ctrl.formValues"
|
||||
old-form-values="ctrl.savedFormValues"
|
||||
></kubernetes-summary-view>
|
||||
></application-summary-section>
|
||||
</div>
|
||||
<!-- #region ACTIONS -->
|
||||
<div class="col-sm-12 form-section-title !mt-6" ng-if="ctrl.state.appType !== ctrl.KubernetesDeploymentTypes.GIT" ng-hide="ctrl.stack.IsComposeFormat"> Actions </div>
|
||||
|
|
|
@ -10,17 +10,11 @@ import { getGlobalDeploymentOptions } from '@/react/portainer/settings/settings.
|
|||
import {
|
||||
KubernetesApplicationDataAccessPolicies,
|
||||
KubernetesApplicationDeploymentTypes,
|
||||
KubernetesApplicationPublishingTypes,
|
||||
KubernetesApplicationQuotaDefaults,
|
||||
KubernetesApplicationServiceTypes,
|
||||
KubernetesApplicationTypes,
|
||||
KubernetesDeploymentTypes,
|
||||
} from 'Kubernetes/models/application/models';
|
||||
import {
|
||||
KubernetesApplicationEnvironmentVariableFormValue,
|
||||
KubernetesApplicationFormValues,
|
||||
KubernetesApplicationPersistedFolderFormValue,
|
||||
KubernetesFormValidationReferences,
|
||||
} from 'Kubernetes/models/application/formValues';
|
||||
} from 'Kubernetes/models/application/models/appConstants';
|
||||
import { KubernetesApplicationQuotaDefaults, KubernetesDeploymentTypes } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesApplicationEnvironmentVariableFormValue, KubernetesApplicationFormValues, KubernetesFormValidationReferences } from 'Kubernetes/models/application/formValues';
|
||||
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper';
|
||||
import KubernetesApplicationConverter from 'Kubernetes/converters/application';
|
||||
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
|
||||
|
@ -76,7 +70,7 @@ class KubernetesCreateApplicationController {
|
|||
|
||||
this.ApplicationDeploymentTypes = KubernetesApplicationDeploymentTypes;
|
||||
this.ApplicationDataAccessPolicies = KubernetesApplicationDataAccessPolicies;
|
||||
this.ApplicationPublishingTypes = KubernetesApplicationPublishingTypes;
|
||||
this.KubernetesApplicationServiceTypes = KubernetesApplicationServiceTypes;
|
||||
this.ApplicationTypes = KubernetesApplicationTypes;
|
||||
this.ServiceTypes = KubernetesServiceTypes;
|
||||
this.KubernetesDeploymentTypes = KubernetesDeploymentTypes;
|
||||
|
@ -151,6 +145,9 @@ class KubernetesCreateApplicationController {
|
|||
this.onChangeReplicaCount = this.onChangeReplicaCount.bind(this);
|
||||
this.onAutoScaleChange = this.onAutoScaleChange.bind(this);
|
||||
this.onChangePlacements = this.onChangePlacements.bind(this);
|
||||
this.updateApplicationType = this.updateApplicationType.bind(this);
|
||||
this.getAppType = this.getAppType.bind(this);
|
||||
this.showDataAccessPolicySection = this.showDataAccessPolicySection.bind(this);
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
|
@ -165,6 +162,24 @@ class KubernetesCreateApplicationController {
|
|||
this.$scope.$evalAsync(() => {
|
||||
this.formValues.DeploymentType = value;
|
||||
});
|
||||
this.updateApplicationType();
|
||||
}
|
||||
|
||||
updateApplicationType() {
|
||||
return this.$scope.$evalAsync(() => {
|
||||
this.formValues.ApplicationType = this.getAppType();
|
||||
this.validatePersistedFolders();
|
||||
});
|
||||
}
|
||||
|
||||
getAppType() {
|
||||
if (this.formValues.DeploymentType === this.ApplicationDeploymentTypes.Global) {
|
||||
return this.ApplicationTypes.DaemonSet;
|
||||
}
|
||||
if (this.formValues.PersistedFolders && this.formValues.PersistedFolders.length) {
|
||||
return this.ApplicationTypes.StatefulSet;
|
||||
}
|
||||
return this.ApplicationTypes.Deployment;
|
||||
}
|
||||
|
||||
onChangeFileContent(value) {
|
||||
|
@ -230,28 +245,23 @@ class KubernetesCreateApplicationController {
|
|||
|
||||
/* #region AUTO SCALER UI MANAGEMENT */
|
||||
unselectAutoScaler() {
|
||||
if (this.formValues.DeploymentType === this.ApplicationDeploymentTypes.GLOBAL) {
|
||||
this.formValues.AutoScaler.IsUsed = false;
|
||||
if (this.formValues.DeploymentType === this.ApplicationDeploymentTypes.Global) {
|
||||
this.formValues.AutoScaler.isUsed = false;
|
||||
}
|
||||
}
|
||||
|
||||
onAutoScaleChange(values) {
|
||||
return this.$async(async () => {
|
||||
if (!this.formValues.AutoScaler.IsUsed && values.isUsed) {
|
||||
if (!this.formValues.AutoScaler.isUsed && values.isUsed) {
|
||||
this.formValues.AutoScaler = {
|
||||
IsUsed: values.isUsed,
|
||||
MinReplicas: 1,
|
||||
MaxReplicas: 3,
|
||||
TargetCPUUtilization: 50,
|
||||
isUsed: values.isUsed,
|
||||
minReplicas: 1,
|
||||
maxReplicas: 3,
|
||||
targetCpuUtilizationPercentage: 50,
|
||||
};
|
||||
return;
|
||||
}
|
||||
this.formValues.AutoScaler = {
|
||||
IsUsed: values.isUsed,
|
||||
MinReplicas: values.minReplicas,
|
||||
MaxReplicas: values.maxReplicas,
|
||||
TargetCPUUtilization: values.targetCpuUtilizationPercentage,
|
||||
};
|
||||
this.formValues.AutoScaler = values;
|
||||
});
|
||||
}
|
||||
/* #endregion */
|
||||
|
@ -319,22 +329,6 @@ class KubernetesCreateApplicationController {
|
|||
/* #endregion */
|
||||
|
||||
/* #region PERSISTENT FOLDERS UI MANAGEMENT */
|
||||
addPersistedFolder() {
|
||||
let storageClass = {};
|
||||
if (this.storageClasses.length > 0) {
|
||||
storageClass = this.storageClasses[0];
|
||||
}
|
||||
|
||||
const newPf = new KubernetesApplicationPersistedFolderFormValue(storageClass);
|
||||
this.formValues.PersistedFolders.push(newPf);
|
||||
this.resetDeploymentType();
|
||||
}
|
||||
|
||||
restorePersistedFolder(index) {
|
||||
this.formValues.PersistedFolders[index].needsDeletion = false;
|
||||
this.validatePersistedFolders();
|
||||
}
|
||||
|
||||
resetPersistedFolders() {
|
||||
this.formValues.PersistedFolders = _.forEach(this.formValues.PersistedFolders, (persistedFolder) => {
|
||||
persistedFolder.existingVolume = null;
|
||||
|
@ -342,32 +336,6 @@ class KubernetesCreateApplicationController {
|
|||
});
|
||||
this.validatePersistedFolders();
|
||||
}
|
||||
|
||||
removePersistedFolder(index) {
|
||||
if (this.state.isEdit && this.formValues.PersistedFolders[index].persistentVolumeClaimName) {
|
||||
this.formValues.PersistedFolders[index].needsDeletion = true;
|
||||
} else {
|
||||
this.formValues.PersistedFolders.splice(index, 1);
|
||||
}
|
||||
this.validatePersistedFolders();
|
||||
}
|
||||
|
||||
useNewVolume(index) {
|
||||
this.formValues.PersistedFolders[index].useNewVolume = true;
|
||||
this.formValues.PersistedFolders[index].existingVolume = null;
|
||||
this.state.persistedFoldersUseExistingVolumes = _.some(this.formValues.PersistedFolders, { useNewVolume: false });
|
||||
this.validatePersistedFolders();
|
||||
}
|
||||
|
||||
useExistingVolume(index) {
|
||||
this.formValues.PersistedFolders[index].useNewVolume = false;
|
||||
this.state.persistedFoldersUseExistingVolumes = _.some(this.formValues.PersistedFolders, { useNewVolume: false });
|
||||
if (this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.ISOLATED) {
|
||||
this.formValues.DataAccessPolicy = this.ApplicationDataAccessPolicies.SHARED;
|
||||
this.resetDeploymentType();
|
||||
}
|
||||
this.validatePersistedFolders();
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
/* #region PERSISTENT FOLDERS ON CHANGE VALIDATION */
|
||||
|
@ -389,7 +357,14 @@ class KubernetesCreateApplicationController {
|
|||
}
|
||||
|
||||
onChangePersistedFolder(values) {
|
||||
this.formValues.PersistedFolders = values;
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.formValues.PersistedFolders = values;
|
||||
if (values && values.length && !this.supportGlobalDeployment()) {
|
||||
this.onChangeDeploymentType(this.ApplicationDeploymentTypes.Replicated);
|
||||
return;
|
||||
}
|
||||
this.updateApplicationType();
|
||||
});
|
||||
}
|
||||
|
||||
onChangeExistingVolumeSelection() {
|
||||
|
@ -445,13 +420,12 @@ class KubernetesCreateApplicationController {
|
|||
}
|
||||
|
||||
resetDeploymentType() {
|
||||
this.formValues.DeploymentType = this.ApplicationDeploymentTypes.REPLICATED;
|
||||
this.formValues.DeploymentType = this.ApplicationDeploymentTypes.Replicated;
|
||||
}
|
||||
|
||||
// The data access policy panel is not shown when:
|
||||
// * There is not persisted folder specified
|
||||
// // The data access policy panel is shown when a persisted folder is specified
|
||||
showDataAccessPolicySection() {
|
||||
return this.formValues.PersistedFolders.length !== 0;
|
||||
return this.formValues.PersistedFolders.length > 0;
|
||||
}
|
||||
|
||||
// A global deployment is not available when either:
|
||||
|
@ -460,7 +434,7 @@ class KubernetesCreateApplicationController {
|
|||
supportGlobalDeployment() {
|
||||
const hasFolders = this.formValues.PersistedFolders.length !== 0;
|
||||
const hasRWOOnly = KubernetesApplicationHelper.hasRWOOnly(this.formValues);
|
||||
const isIsolated = this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.ISOLATED;
|
||||
const isIsolated = this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.Isolated;
|
||||
|
||||
if (hasFolders && (hasRWOOnly || isIsolated)) {
|
||||
return false;
|
||||
|
@ -469,9 +443,9 @@ class KubernetesCreateApplicationController {
|
|||
return true;
|
||||
}
|
||||
|
||||
// A StatefulSet is defined by DataAccessPolicy === ISOLATED
|
||||
// A StatefulSet is defined by DataAccessPolicy === 'Isolated'
|
||||
isEditAndStatefulSet() {
|
||||
return this.state.isEdit && this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.ISOLATED;
|
||||
return this.state.isEdit && this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.Isolated;
|
||||
}
|
||||
|
||||
// A scalable deployment is available when either:
|
||||
|
@ -482,7 +456,7 @@ class KubernetesCreateApplicationController {
|
|||
supportScalableReplicaDeployment() {
|
||||
const hasFolders = this.formValues.PersistedFolders.length !== 0;
|
||||
const hasRWOOnly = KubernetesApplicationHelper.hasRWOOnly(this.formValues);
|
||||
const isIsolated = this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.ISOLATED;
|
||||
const isIsolated = this.formValues.DataAccessPolicy === this.ApplicationDataAccessPolicies.Isolated;
|
||||
|
||||
if (!hasFolders || isIsolated || (hasFolders && !hasRWOOnly)) {
|
||||
return true;
|
||||
|
@ -540,7 +514,7 @@ class KubernetesCreateApplicationController {
|
|||
}
|
||||
|
||||
effectiveInstances() {
|
||||
return this.formValues.DeploymentType === this.ApplicationDeploymentTypes.GLOBAL ? this.nodeNumber : this.formValues.ReplicaCount;
|
||||
return this.formValues.DeploymentType === this.ApplicationDeploymentTypes.Global ? this.nodeNumber : this.formValues.ReplicaCount;
|
||||
}
|
||||
|
||||
hasPortErrors() {
|
||||
|
@ -564,11 +538,11 @@ class KubernetesCreateApplicationController {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (this.formValues.DeploymentType === this.ApplicationDeploymentTypes.REPLICATED) {
|
||||
if (this.formValues.DeploymentType === this.ApplicationDeploymentTypes.Replicated) {
|
||||
return this.nodesLimits.overflowForReplica(cpu, memory, instances);
|
||||
}
|
||||
|
||||
// DeploymentType == GLOBAL
|
||||
// DeploymentType == 'Global'
|
||||
return this.nodesLimits.overflowForGlobal(cpu, memory);
|
||||
}
|
||||
|
||||
|
@ -613,7 +587,7 @@ class KubernetesCreateApplicationController {
|
|||
}
|
||||
|
||||
isExistingVolumeButtonDisabled() {
|
||||
return !this.hasAvailableVolumes() || (this.isEdit && this.application.ApplicationType === this.ApplicationTypes.STATEFULSET);
|
||||
return !this.hasAvailableVolumes() || (this.isEdit && this.application.ApplicationType === this.ApplicationTypes.StatefulSet);
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
|
@ -630,7 +604,7 @@ class KubernetesCreateApplicationController {
|
|||
const scalable = this.supportScalableReplicaDeployment();
|
||||
const global = this.supportGlobalDeployment();
|
||||
const replica = this.formValues.ReplicaCount > 1;
|
||||
const replicated = this.formValues.DeploymentType === this.ApplicationDeploymentTypes.REPLICATED;
|
||||
const replicated = this.formValues.DeploymentType === this.ApplicationDeploymentTypes.Replicated;
|
||||
const res = (replicated && !scalable && replica) || (!replicated && !global);
|
||||
return res;
|
||||
}
|
||||
|
@ -784,7 +758,7 @@ class KubernetesCreateApplicationController {
|
|||
if (this.savedFormValues) {
|
||||
this.formValues.PublishingType = this.savedFormValues.PublishingType;
|
||||
} else {
|
||||
this.formValues.PublishingType = this.ApplicationPublishingTypes.CLUSTER_IP;
|
||||
this.formValues.PublishingType = this.KubernetesApplicationServiceTypes.ClusterIP;
|
||||
}
|
||||
}
|
||||
this.formValues.OriginalIngresses = this.ingresses;
|
||||
|
@ -1070,9 +1044,8 @@ class KubernetesCreateApplicationController {
|
|||
this.savedFormValues = angular.copy(this.formValues);
|
||||
this.updateNamespaceLimits(this.namespaceWithQuota);
|
||||
this.updateSliders(this.namespaceWithQuota);
|
||||
delete this.formValues.ApplicationType;
|
||||
|
||||
if (this.application.ApplicationType !== KubernetesApplicationTypes.STATEFULSET) {
|
||||
if (this.application.ApplicationType !== KubernetesApplicationTypes.StatefulSet) {
|
||||
_.forEach(this.formValues.PersistedFolders, (persistedFolder) => {
|
||||
const volume = _.find(this.availableVolumes, ['PersistentVolumeClaim.Name', persistedFolder.persistentVolumeClaimName]);
|
||||
if (volume) {
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import _ from 'lodash-es';
|
||||
import { KubernetesResourceTypes, KubernetesResourceActions } from 'Kubernetes/models/resource-types/models';
|
||||
import { KubernetesApplicationFormValues } from 'Kubernetes/models/application/formValues';
|
||||
import { KubernetesDeployment } from 'Kubernetes/models/deployment/models';
|
||||
import { KubernetesStatefulSet } from 'Kubernetes/models/stateful-set/models';
|
||||
import { KubernetesDaemonSet } from 'Kubernetes/models/daemon-set/models';
|
||||
import { KubernetesService, KubernetesServiceTypes } from 'Kubernetes/models/service/models';
|
||||
import { KubernetesApplication, KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models';
|
||||
import { KubernetesHorizontalPodAutoScalerHelper } from 'Kubernetes/horizontal-pod-auto-scaler/helper';
|
||||
import { KubernetesApplicationDeploymentTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
import { KubernetesHorizontalPodAutoScalerConverter } from 'Kubernetes/horizontal-pod-auto-scaler/converter';
|
||||
import KubernetesApplicationConverter from 'Kubernetes/converters/application';
|
||||
import KubernetesServiceConverter from 'Kubernetes/converters/service';
|
||||
|
@ -33,7 +30,7 @@ export function getApplicationResources(formValues, oldFormValues = {}) {
|
|||
* Get summary of Kubernetes resources to be created
|
||||
* @param {KubernetesApplicationFormValues} formValues
|
||||
*/
|
||||
function getCreatedApplicationResources(formValues) {
|
||||
export function getCreatedApplicationResources(formValues) {
|
||||
const resources = [];
|
||||
|
||||
let [app, headlessService, services, service, claims] = KubernetesApplicationConverter.applicationFormValuesToApplication(formValues);
|
||||
|
@ -65,14 +62,14 @@ function getCreatedApplicationResources(formValues) {
|
|||
}
|
||||
|
||||
// Horizontal pod autoscalers
|
||||
if (formValues.AutoScaler.IsUsed && formValues.DeploymentType !== KubernetesApplicationDeploymentTypes.GLOBAL) {
|
||||
const kind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(app);
|
||||
if (formValues.AutoScaler.IsUsed && formValues.DeploymentType !== KubernetesApplicationDeploymentTypes.Global) {
|
||||
const kind = app.ApplicationType;
|
||||
const autoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(formValues, kind);
|
||||
resources.push({ action: CREATE, kind: KubernetesResourceTypes.HORIZONTAL_POD_AUTOSCALER, name: autoScaler.Name });
|
||||
}
|
||||
|
||||
// Deployment
|
||||
const appResourceType = getApplicationResourceType(app);
|
||||
const appResourceType = app.ApplicationType;
|
||||
if (appResourceType !== null) {
|
||||
resources.push({ action: CREATE, kind: appResourceType, name: app.Name });
|
||||
}
|
||||
|
@ -85,13 +82,13 @@ function getCreatedApplicationResources(formValues) {
|
|||
* @param {KubernetesApplicationFormValues} oldFormValues
|
||||
* @param {KubernetesApplicationFormValues} newFormValues
|
||||
*/
|
||||
function getUpdatedApplicationResources(oldFormValues, newFormValues) {
|
||||
export function getUpdatedApplicationResources(oldFormValues, newFormValues) {
|
||||
const resources = [];
|
||||
|
||||
const [oldApp, oldHeadlessService, oldServices, oldService, oldClaims] = KubernetesApplicationConverter.applicationFormValuesToApplication(oldFormValues);
|
||||
const [newApp, newHeadlessService, newServices, newService, newClaims] = KubernetesApplicationConverter.applicationFormValuesToApplication(newFormValues);
|
||||
const oldAppResourceType = getApplicationResourceType(oldApp);
|
||||
const newAppResourceType = getApplicationResourceType(newApp);
|
||||
const oldAppResourceType = oldApp.ApplicationType;
|
||||
const newAppResourceType = newApp.ApplicationType;
|
||||
|
||||
if (oldAppResourceType !== newAppResourceType) {
|
||||
// Deployment
|
||||
|
@ -152,7 +149,7 @@ function getUpdatedApplicationResources(oldFormValues, newFormValues) {
|
|||
resources.push({ action: DELETE, kind: KubernetesResourceTypes.SERVICE, name: oldService.Name, type: oldService.Type || KubernetesServiceTypes.CLUSTER_IP });
|
||||
}
|
||||
|
||||
const newKind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(newApp);
|
||||
const newKind = newApp.ApplicationType;
|
||||
const newAutoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(newFormValues, newKind);
|
||||
if (!oldFormValues.AutoScaler.IsUsed) {
|
||||
if (newFormValues.AutoScaler.IsUsed) {
|
||||
|
@ -161,7 +158,7 @@ function getUpdatedApplicationResources(oldFormValues, newFormValues) {
|
|||
}
|
||||
} else {
|
||||
// Horizontal pod autoscalers
|
||||
const oldKind = KubernetesHorizontalPodAutoScalerHelper.getApplicationTypeString(oldApp);
|
||||
const oldKind = oldApp.ApplicationType;
|
||||
const oldAutoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(oldFormValues, oldKind);
|
||||
if (newFormValues.AutoScaler.IsUsed) {
|
||||
const hpaUpdateSummary = getHorizontalPodAutoScalerUpdateResourceSummary(oldAutoScaler, newAutoScaler);
|
||||
|
@ -176,17 +173,6 @@ function getUpdatedApplicationResources(oldFormValues, newFormValues) {
|
|||
return resources;
|
||||
}
|
||||
|
||||
function getApplicationResourceType(app) {
|
||||
if (app instanceof KubernetesDeployment || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.DEPLOYMENT)) {
|
||||
return KubernetesResourceTypes.DEPLOYMENT;
|
||||
} else if (app instanceof KubernetesDaemonSet || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.DAEMONSET)) {
|
||||
return KubernetesResourceTypes.DAEMONSET;
|
||||
} else if (app instanceof KubernetesStatefulSet || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.STATEFULSET)) {
|
||||
return KubernetesResourceTypes.STATEFULSET;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getIngressUpdateSummary(oldIngresses, newIngresses) {
|
||||
const ingressesSummaries = newIngresses
|
||||
.map((newIng) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue