fix(k8s/ingress): ensure new ports are only added to ingress only if app is published via ingress (#6153)

* fix(k8s/ingress): ensure new ports are only added to ingress only if app is published via ingress

* refactor(k8s/ingress): removed deleted ports of ingress in a single pass
pull/6176/head
LP B 2021-11-30 05:14:52 +01:00 committed by GitHub
parent 69c17986d9
commit b6fbf8eecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 32 deletions

View File

@ -7,6 +7,7 @@ import {
KubernetesResourcePoolIngressClassFormValue, KubernetesResourcePoolIngressClassFormValue,
KubernetesResourcePoolIngressClassHostFormValue, KubernetesResourcePoolIngressClassHostFormValue,
} from 'Kubernetes/models/resource-pool/formValues'; } from 'Kubernetes/models/resource-pool/formValues';
import { KubernetesApplicationPublishingTypes } from '../models/application/models';
import { KubernetesIngress, KubernetesIngressRule } from './models'; import { KubernetesIngress, KubernetesIngressRule } from './models';
import { KubernetesIngressCreatePayload, KubernetesIngressRuleCreatePayload, KubernetesIngressRulePathCreatePayload } from './payloads'; import { KubernetesIngressCreatePayload, KubernetesIngressRuleCreatePayload, KubernetesIngressRulePathCreatePayload } from './payloads';
import { KubernetesIngressClassAnnotation, KubernetesIngressClassRewriteTargetAnnotations } from './constants'; import { KubernetesIngressClassAnnotation, KubernetesIngressClassRewriteTargetAnnotations } from './constants';
@ -45,23 +46,31 @@ export class KubernetesIngressConverter {
return res; return res;
} }
/**
* Converts Application Form Value (from Create Application View) to Ingresses
* @param {KubernetesApplicationFormValues} formValues
* @param {string} serviceName
* @returns {KubernetesIngressRule[]}
*/
static applicationFormValuesToIngresses(formValues, serviceName) { static applicationFormValuesToIngresses(formValues, serviceName) {
const isPublishingToIngress = formValues.PublishingType === KubernetesApplicationPublishingTypes.INGRESS;
const ingresses = angular.copy(formValues.OriginalIngresses); const ingresses = angular.copy(formValues.OriginalIngresses);
_.forEach(formValues.PublishedPorts, (p) => { _.forEach(formValues.PublishedPorts, (p) => {
const ingress = _.find(ingresses, { Name: p.IngressName }); const ingress = _.find(ingresses, { Name: p.IngressName });
if (ingress && p.NeedsDeletion) { if (ingress) {
const path = _.find(ingress.Paths, { Port: p.ContainerPort, ServiceName: serviceName, Path: p.IngressRoute }); if (p.NeedsDeletion) {
_.remove(ingress.Paths, path); _.remove(ingress.Paths, (path) => path.Port === p.ContainerPort && path.ServiceName === serviceName && path.Path === p.IngressRoute);
} else if (ingress && p.IsNew) { } else if (isPublishingToIngress && p.IsNew) {
const rule = new KubernetesIngressRule(); const rule = new KubernetesIngressRule();
rule.IngressName = ingress.Name; rule.IngressName = ingress.Name;
rule.ServiceName = serviceName; rule.ServiceName = serviceName;
rule.Port = p.ContainerPort; rule.Port = p.ContainerPort;
if (p.IngressRoute) { if (p.IngressRoute) {
rule.Path = _.startsWith(p.IngressRoute, '/') ? p.IngressRoute : '/' + p.IngressRoute; rule.Path = _.startsWith(p.IngressRoute, '/') ? p.IngressRoute : '/' + p.IngressRoute;
}
rule.Host = p.IngressHost;
ingress.Paths.push(rule);
} }
rule.Host = p.IngressHost;
ingress.Paths.push(rule);
} }
}); });
return ingresses; return ingresses;
@ -69,7 +78,8 @@ export class KubernetesIngressConverter {
/** /**
* *
* @param {KubernetesResourcePoolIngressClassFormValue} formValues * @param {KubernetesResourcePoolIngressClassFormValue[]} formValues
* @returns {KubernetesIngress} Ingress
*/ */
static resourcePoolIngressClassFormValueToIngress(formValues) { static resourcePoolIngressClassFormValueToIngress(formValues) {
const res = new KubernetesIngress(); const res = new KubernetesIngress();

View File

@ -27,6 +27,7 @@ export function KubernetesApplicationFormValues() {
this.PlacementType = KubernetesApplicationPlacementTypes.PREFERRED; this.PlacementType = KubernetesApplicationPlacementTypes.PREFERRED;
this.Placements = []; // KubernetesApplicationPlacementFormValue lis; this.Placements = []; // KubernetesApplicationPlacementFormValue lis;
this.OriginalIngresses = undefined; this.OriginalIngresses = undefined;
this.IsPublishingService = false;
} }
export const KubernetesApplicationConfigurationFormValueOverridenKeyTypes = Object.freeze({ export const KubernetesApplicationConfigurationFormValueOverridenKeyTypes = Object.freeze({

View File

@ -346,10 +346,14 @@ class KubernetesApplicationService {
await apiService.patch(oldAppPayload, newAppPayload); await apiService.patch(oldAppPayload, newAppPayload);
} }
// accept either formValues or applications as parameters // accept either formValues or applications as parameters depending on partial value
// depending on partial value
// true = KubernetesApplication // true = KubernetesApplication
// false = KubernetesApplicationFormValues // false = KubernetesApplicationFormValues
//
// e.g. signatures are
//
// patch(oldValues: KubernetesApplication, newValues: KubernetesApplication, partial: (undefined | false)): Promise<unknown>
// patch(oldValues: KubernetesApplicationFormValues, newValues: KubernetesApplicationFormValues, partial: true): Promise<unknown>
patch(oldValues, newValues, partial = false) { patch(oldValues, newValues, partial = false) {
if (partial) { if (partial) {
return this.$async(this.patchPartialAsync, oldValues, newValues); return this.$async(this.patchPartialAsync, oldValues, newValues);

View File

@ -1246,7 +1246,13 @@
Enable publishing for this application Enable publishing for this application
</label> </label>
<label class="switch" style="margin-left: 20px;"> <label class="switch" style="margin-left: 20px;">
<input type="checkbox" class="form-control" name="enable_port_publishing" ng-model="ctrl.formValues.IsPublishingService" /> <input
type="checkbox"
class="form-control"
name="enable_port_publishing"
ng-model="ctrl.formValues.IsPublishingService"
ng-change="ctrl.onServicePublishChange()"
/>
<i></i> <i></i>
</label> </label>
</div> </div>

View File

@ -144,8 +144,6 @@ class KubernetesCreateApplicationController {
this.setPullImageValidity = this.setPullImageValidity.bind(this); this.setPullImageValidity = this.setPullImageValidity.bind(this);
this.onChangeFileContent = this.onChangeFileContent.bind(this); this.onChangeFileContent = this.onChangeFileContent.bind(this);
this.onServicePublishChange = this.onServicePublishChange.bind(this); this.onServicePublishChange = this.onServicePublishChange.bind(this);
this.$scope.$watch(() => this.formValues.IsPublishingService, this.onServicePublishChange);
} }
/* #endregion */ /* #endregion */
@ -426,34 +424,31 @@ class KubernetesCreateApplicationController {
/* #endregion */ /* #endregion */
/* #region PUBLISHED PORTS UI MANAGEMENT */
onServicePublishChange() { onServicePublishChange() {
// service creation // enable publishing with no previous ports exposed
if (this.formValues.PublishedPorts.length === 0) { if (this.formValues.IsPublishingService && !this.formValues.PublishedPorts.length) {
if (this.formValues.IsPublishingService) { this.addPublishedPort();
// toggle enabled
this.addPublishedPort();
}
return; return;
} }
// service update // service update
if (this.formValues.IsPublishingService) { if (this.formValues.IsPublishingService) {
// toggle enabled
this.formValues.PublishedPorts.forEach((port) => (port.NeedsDeletion = false)); this.formValues.PublishedPorts.forEach((port) => (port.NeedsDeletion = false));
} else { } else {
// toggle disabled // delete new ports, mark old ports to be deleted
// all new ports need to be deleted, existing ports need to be marked as needing deletion
this.formValues.PublishedPorts = this.formValues.PublishedPorts.filter((port) => !port.IsNew).map((port) => ({ ...port, NeedsDeletion: true })); this.formValues.PublishedPorts = this.formValues.PublishedPorts.filter((port) => !port.IsNew).map((port) => ({ ...port, NeedsDeletion: true }));
} }
} }
/* #region PUBLISHED PORTS UI MANAGEMENT */
addPublishedPort() { addPublishedPort() {
const p = new KubernetesApplicationPublishedPortFormValue(); const p = new KubernetesApplicationPublishedPortFormValue();
const ingresses = this.ingresses; const ingresses = this.ingresses;
p.IngressName = ingresses && ingresses.length ? ingresses[0].Name : undefined; if (this.formValues.PublishingType === KubernetesApplicationPublishingTypes.INGRESS) {
p.IngressHost = ingresses && ingresses.length ? ingresses[0].Hosts[0] : undefined; p.IngressName = ingresses && ingresses.length ? ingresses[0].Name : undefined;
p.IngressHosts = ingresses && ingresses.length ? ingresses[0].Hosts : undefined; p.IngressHost = ingresses && ingresses.length ? ingresses[0].Hosts[0] : undefined;
p.IngressHosts = ingresses && ingresses.length ? ingresses[0].Hosts : undefined;
}
if (this.formValues.PublishedPorts.length) { if (this.formValues.PublishedPorts.length) {
p.Protocol = this.formValues.PublishedPorts[0].Protocol; p.Protocol = this.formValues.PublishedPorts[0].Protocol;
} }

View File

@ -28,7 +28,12 @@
"lib": ["dom", "dom.iterable", "esnext"], "lib": ["dom", "dom.iterable", "esnext"],
"paths": { "paths": {
// paths relative to the baseUrl // paths relative to the baseUrl
"@/*": ["./*", "../app/*"] "@/*": ["./*", "../app/*"],
"Agent/*": ["agent/*"],
"Azure/*": ["azure/*"],
"Docker/*": ["docker/*"],
"Kubernetes/*": ["kubernetes/*"],
"Portainer/*": ["portainer/*"],
} }
}, },
"exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"], "exclude": ["api", "build", "dist", "distribution", "node_modules", "test", "webpack"],