From d64539e4622fb219046fa47f003cc93d50ba7d73 Mon Sep 17 00:00:00 2001 From: Robert Patrick Date: Mon, 14 Feb 2022 16:16:37 -0600 Subject: [PATCH] refactoring most calls to get service details --- electron/app/locales/en/webui.json | 8 +- webui/src/js/utils/ingress-routes-updater.js | 75 +++++++------------ webui/src/js/utils/wkt-actions-base.js | 35 +++++++++ .../js/viewModels/ingress-design-view-impl.js | 33 ++++---- webui/src/js/viewModels/route-edit-dialog.js | 32 +++++++- 5 files changed, 111 insertions(+), 72 deletions(-) diff --git a/electron/app/locales/en/webui.json b/electron/app/locales/en/webui.json index 37c2b3a39..f824907b4 100644 --- a/electron/app/locales/en/webui.json +++ b/electron/app/locales/en/webui.json @@ -707,8 +707,8 @@ "ingress-design-ingress-route-traefik-mw-label": "Traefik Middleware", "ingress-design-ingress-route-traefik-mw-help": "Customize Traefik Middlewares Object", - "ingress-design-ingress-routes-getting-target-service-title" : "Retrieving existing domain service details", - "ingress-design-ingress-routes-getting-target-service-error-message": "Failed to get existing domain service details from Kubernetes namespace {{namespace}}: {{error}}.", + "ingress-design-ingress-routes-get-services-in-namespace-title" : "Retrieving existing domain service details", + "ingress-design-ingress-routes-get-services-in-namespace-error-message": "Failed to get existing domain services from Kubernetes namespace {{namespace}}: {{error}}.", "ingress-design-ingress-route-name-field-validation-error": "Route {{routeName}}", "ingress-design-ingress-route-field-validation-error": "Route: {{routeName}}, Field: {{fieldName}}", @@ -790,7 +790,7 @@ "ingress-routes-updater-tls-key-invalid-error-message": "Unable to update ingress routes because the TLS Private Key File '{{file}}' does not exist.", "ingress-routes-updater-project-not-saved-error-prefix": "Unable to update ingress routes because project save failed", "ingress-routes-updater-check-ingress-service-exists": "Checking ingress controller service exists", - "ingress-routes-updater-service-not-installed-error-message": "Unable to update ingress routes because the ingress controller service {{serviceName}} for ingress controller {{name}} was not found in Kubernetes namespace {{namespace}}. The ingress controller may not have been installed correctly: {{error}}.", + "ingress-routes-updater-service-not-exists-error-message": "Unable to update ingress routes because the ingress controller service {{serviceName}} for ingress controller {{name}} was not found in Kubernetes namespace {{namespace}}. The ingress controller may not have been installed correctly: {{error}}.", "ingress-routes-updater-create-tls-secret-in-progress": "Creating ingress TLS secret", "ingress-routes-updater-generate-tls-files-error-message": "Unable to update ingress routes because an error occurred while generating the TLS certificate and private key files: {{error}}.", "ingress-routes-updater-create-tls-secret-error-message": "Unable to update ingress routes because an error occurred while creating the TLS secret {{name}} in Kubernetes namespace {{namespace}}: {{error}}", @@ -800,7 +800,7 @@ "ingress-routes-updater-routes-prompt-question": "The following routes `{{routes}}` already exist in the Kubernetes cluster, are you sure you want to overwrite them?", "ingress-routes-updater-get-service-details-error-message": "Unable to update ingress routes because an error occurred getting the ingress service details in Kubernetes namespace {{namespace}}: {{error}}.", "ingress-routes-updater-get-ingresses-error-message": "Unable to getting ingress details in Kubernetes namespace {{namespace}}: {{error}}.", - "ingress-routes-updater-route-target-service-not-exists-error-message": "Unable to update ingress routes because the application was unable to get the details for the target service {{targetService}} specified in route {{name}}: {{error}}.", + "ingress-routes-updater-target-service-not-exists-error-message": "Unable to update ingress routes because the application was unable to get the details for the target service {{serviceName}} specified in route {{name}}: {{error}}.", "ingress-routes-updater-route-target-port-not-exists-error-message": "Unable to update ingress routes because the target port {{targetPort}} specified in route {{name}} does not exists.", "ingress-routes-updater-check-route-target-service-in-progress": "Validating target services and ports for routes", "ingress-routes-updater-update-route-in-progress": "Updating ingress route {{routeName}}", diff --git a/webui/src/js/utils/ingress-routes-updater.js b/webui/src/js/utils/ingress-routes-updater.js index 75b3134b2..34c47cb6f 100644 --- a/webui/src/js/utils/ingress-routes-updater.js +++ b/webui/src/js/utils/ingress-routes-updater.js @@ -111,7 +111,7 @@ function(IngressActionsBase, project, wktConsole, k8sHelper, i18n, projectIo, di const ingressControllerNamespace = this.project.ingress.ingressControllerNamespace.value; const results = await this.doesIngressServiceExist(kubectlExe, kubectlOptions, ingressControllerProvider, - ingressControllerName, ingressControllerNamespace, errTitle); + ingressControllerName, ingressControllerNamespace, errTitle, errPrefix); if (!results) { return Promise.resolve(false); } @@ -179,7 +179,7 @@ function(IngressActionsBase, project, wktConsole, k8sHelper, i18n, projectIo, di busyDialogMessage = i18n.t('ingress-routes-updater-check-route-target-service-in-progress'); dialogHelper.updateBusyDialog(busyDialogMessage, 7/totalSteps); for (const route of routes) { - if (! await this.checkTargetService(kubectlExe, route, kubectlOptions)) { + if (! await this.checkTargetService(kubectlExe, route, kubectlOptions, errTitle, errPrefix)) { return Promise.resolve(false); } } @@ -328,24 +328,12 @@ function(IngressActionsBase, project, wktConsole, k8sHelper, i18n, projectIo, di return Promise.resolve(true); } - async doesIngressServiceExist(kubectlExe, kubectlOptions, provider, name, namespace, errTitle) { - try { - const serviceName = provider === 'nginx' ? `${name}-ingress-nginx-controller` : name; - const result = await window.api.ipc.invoke('k8s-get-service-details', kubectlExe, namespace, - serviceName, kubectlOptions); - if (!result.isSuccess) { - const errMessage = i18n.t('ingress-routes-updater-service-not-installed-error-message', { - error: result.reason, - serviceName: serviceName, - name: name, - namespace: namespace - }); - dialogHelper.closeBusyDialog(); - await window.api.ipc.invoke('show-error-message', errTitle, errMessage); - return Promise.resolve(false); - } - } catch (err) { - return Promise.reject(err); + async doesIngressServiceExist(kubectlExe, kubectlOptions, provider, name, namespace, errTitle, errPrefix) { + const serviceName = provider === 'nginx' ? `${name}-ingress-nginx-controller` : name; + const result = await k8sHelper.getDetailsForService(kubectlExe, kubectlOptions, name, namespace, serviceName, + errTitle, errPrefix); + if (!result) { + return Promise.resolve(false); } return Promise.resolve(true); } @@ -412,12 +400,15 @@ function(IngressActionsBase, project, wktConsole, k8sHelper, i18n, projectIo, di return Promise.resolve(clusterAddress); } + // TODO - this code should be refactored to use k8sHelper's getDetailsForService()/getServiceDetailsForNamespace() + // between the complexity of this code and the code calling it, I left this as is for now... --rpatrick + // async getIngressServiceDetails(kubectlExe, ingressControllerProvider, ingressControllerNamespace, ingressDefinition, k8sCluster, kubectlOptions) { // serviceName == '' for Nginx and Traefik for all ingress routes created by the UI // serviceName = 'voyager-' for each ingress route if it's provider is // voyagerProviderMappedValue is baremetal - + // let serviceName = ''; if (ingressControllerProvider === 'voyager') { serviceName = 'voyager-' + ingressDefinition.name; @@ -426,8 +417,6 @@ function(IngressActionsBase, project, wktConsole, k8sHelper, i18n, projectIo, di const results = await window.api.ipc.invoke('k8s-get-service-details', kubectlExe, ingressControllerNamespace, serviceName, kubectlOptions); - wktLogger.debug('k8s-get-service-details for service %s returned: %s', serviceName, - JSON.stringify(results, 0, null)); if (results.isSuccess) { let ingressPlainPort = 80; let ingressSSLPort = 443; @@ -549,33 +538,25 @@ function(IngressActionsBase, project, wktConsole, k8sHelper, i18n, projectIo, di return Promise.resolve(results); } - async checkTargetService(kubectlExe, ingressDefinition, kubectlOptions, errTitle) { - const results = await window.api.ipc.invoke('k8s-get-service-details', - kubectlExe, ingressDefinition.targetServiceNameSpace, ingressDefinition.targetService, kubectlOptions); - - if (results.isSuccess) { - const serviceDetail = results.serviceDetails; - let found = false; - serviceDetail.spec['ports'].forEach((port) => { - if (Number(port.port) === Number(ingressDefinition.targetPort)) { - found = true; - } - }); + async checkTargetService(kubectlExe, ingressDefinition, kubectlOptions, errTitle, errPrefix) { + const results = await k8sHelper.getDetailsForService(kubectlExe, kubectlOptions, ingressDefinition.name, + ingressDefinition.targetServiceNameSpace, ingressDefinition.targetService, errTitle, errPrefix); + if (!results) { + return Promise.resolve(false); + } - if (!found) { - const errMessage = i18n.t('ingress-routes-updater-route-target-port-not-exists-error-message', { - name: ingressDefinition['name'], - targetPort: ingressDefinition['targetPort'] - }); - dialogHelper.closeBusyDialog(); - await window.api.ipc.invoke('show-error-message', errTitle, errMessage); - return Promise.resolve(false); + const serviceDetail = results; + let found = false; + serviceDetail.spec['ports'].forEach((port) => { + if (Number(port.port) === Number(ingressDefinition.targetPort)) { + found = true; } - } else { - const errMessage = i18n.t('ingress-routes-updater-route-target-service-not-exists-error-message', { + }); + + if (!found) { + const errMessage = i18n.t('ingress-routes-updater-route-target-port-not-exists-error-message', { name: ingressDefinition['name'], - targetService: ingressDefinition['targetService'], - error:results.reason + targetPort: ingressDefinition['targetPort'] }); dialogHelper.closeBusyDialog(); await window.api.ipc.invoke('show-error-message', errTitle, errMessage); diff --git a/webui/src/js/utils/wkt-actions-base.js b/webui/src/js/utils/wkt-actions-base.js index 2630fae9c..53df8b978 100644 --- a/webui/src/js/utils/wkt-actions-base.js +++ b/webui/src/js/utils/wkt-actions-base.js @@ -459,6 +459,41 @@ function(project, wktConsole, i18n, projectIo, dialogHelper, return Promise.resolve(true); } + async getDetailsForService(kubectlExe, kubectlOptions, objectName, serviceNamespace, serviceName, errTitle, errPrefix, + shouldCloseBusyDialog = true) { + const results = await window.api.ipc.invoke('k8s-get-service-details', kubectlExe, serviceNamespace, + serviceName, kubectlOptions); + + if (!results.isSuccess) { + const errMessage = i18n.t(`${errPrefix}-service-not-exists-error-message`, { + name: objectName, + namespace: serviceNamespace, + serviceName: serviceName, + error:results.reason + }); + this._closeBusyDialog(shouldCloseBusyDialog); + await window.api.ipc.invoke('show-error-message', errTitle, errMessage); + return Promise.resolve(false); + } + return Promise.resolve(results.serviceDetails); + } + + async getServicesDetailsForNamespace(kubectlExe, kubectlOptions, serviceNamespace, errTitle, errPrefix, + shouldCloseBusyDialog = true) { + const results = await window.api.ipc.invoke('k8s-get-service-details', kubectlExe, serviceNamespace, + '', kubectlOptions); + if (!results.isSuccess) { + const errMessage = i18n.t(`${errPrefix}-get-services-in-namespace-error-message`, { + error: results.reason, + namespace: namespace + }); + this._closeBusyDialog(shouldCloseBusyDialog); + await window.api.ipc.invoke('show-error-message', errTitle, errMessage); + return Promise.resolve(false); + } + return Promise.resolve(results.serviceDetails); + } + _closeBusyDialog(shouldCloseBusyDialog) { if (shouldCloseBusyDialog) { dialogHelper.closeBusyDialog(); diff --git a/webui/src/js/viewModels/ingress-design-view-impl.js b/webui/src/js/viewModels/ingress-design-view-impl.js index a11bf91db..3fbbc0080 100644 --- a/webui/src/js/viewModels/ingress-design-view-impl.js +++ b/webui/src/js/viewModels/ingress-design-view-impl.js @@ -212,23 +212,23 @@ function(i18n, accUtils, ko, ArrayDataProvider, BufferingDataProvider, project, async function getTargetServiceDetails(myProject) { const kubectlExe = k8sHelper.getKubectlExe(); const kubectlOptions = k8sHelper.getKubectlOptions(); - const results = await window.api.ipc.invoke('k8s-get-service-details', - kubectlExe, myProject.k8sDomain.kubernetesNamespace.value, '', kubectlOptions); - let serviceLists = {}; - if (results.isSuccess) { - for (const item of results.serviceDetails.items) { - serviceLists[item.metadata.name] = { ports: item.spec.ports}; + const namespace = myProject.k8sDomain.kubernetesNamespace.value; + const errTitle = i18n.t('ingress-design-ingress-routes-get-services-in-namespace-title'); + const errPrefix = 'ingress-design-ingress-routes'; + + dialogHelper.openBusyDialog(i18n.t('ingress-design-route-get-services-title', { namespace: namespace })); + const results = + await k8sHelper.getServicesDetailsForNamespace(kubectlExe, kubectlOptions, namespace, errTitle, errPrefix); + if (results) { + const servicesList = {}; + console.log('results.items is a ' + typeof(results.items)); + for (const item of results.items) { + servicesList[item.metadata.name] = { ports: item.spec.ports }; } - } else { - const errTitle = i18n.t('ingress-design-ingress-routes-getting-target-service-title'); - const errMessage = i18n.t('ingress-design-ingress-routes-getting-target-service-error-message', { - error: results.reason, - namespace: namespace - }); - await window.api.ipc.invoke('show-error-message', errTitle, errMessage); - return Promise.resolve(false); + dialogHelper.closeBusyDialog(); + return Promise.resolve({ serviceList: servicesList }); } - return Promise.resolve( { serviceList: serviceLists}); + return Promise.resolve(false); } this.handleEditRoute = async (event, context) => { @@ -237,10 +237,7 @@ function(i18n, accUtils, ko, ArrayDataProvider, BufferingDataProvider, project, const index = context.item.index; let route = this.routes.observable()[index]; - dialogHelper.openBusyDialog(this.labelMapper('route-get-services-title', - { namespace: this.project.k8sDomain.kubernetesNamespace.value })); const targetServiceDetails = await getTargetServiceDetails(this.project); - dialogHelper.closeBusyDialog(); if (targetServiceDetails) { const options = {route: route, serviceList: targetServiceDetails.serviceList}; dialogHelper.promptDialog('route-edit-dialog', options).then(result => { diff --git a/webui/src/js/viewModels/route-edit-dialog.js b/webui/src/js/viewModels/route-edit-dialog.js index 50c99f22f..f8c48f371 100644 --- a/webui/src/js/viewModels/route-edit-dialog.js +++ b/webui/src/js/viewModels/route-edit-dialog.js @@ -53,7 +53,7 @@ function(accUtils, ko, i18n, project, viewHelper, ArrayDataProvider, BufferingDa let options = []; if (this.serviceList[svcName]) { for (const port of this.serviceList[svcName].ports) { - options.push( { id : port.port, value: port.port, text: port.port} ); + options.push( { id : port.port, value: port.port, text: port.port.toString()} ); } } @@ -154,7 +154,6 @@ function(accUtils, ko, i18n, project, viewHelper, ArrayDataProvider, BufferingDa }); this.getTargetPortPlaceholder = ko.computed(() => { - console.log('targetSvcPorts is a ' + typeof(this.targetSvcPorts)); const ports = this.targetSvcPorts(); if (Array.isArray(ports) && ports.length > 0) { return this.labelMapper('route-targetport-placeholder'); @@ -204,8 +203,35 @@ function(accUtils, ko, i18n, project, viewHelper, ArrayDataProvider, BufferingDa }; this.targetSvcNameChanged = (event) => { + const newServiceName = event.detail.value; this.targetSvcPorts.removeAll(); - this.buildTargetSvcPorts(event.detail.value).forEach(port => this.targetSvcPorts.push(port)); + this.buildTargetSvcPorts(newServiceName).forEach(port => this.targetSvcPorts.push(port)); + + // If the new service name is a known service and the current target port value is not + // associated with the service, clear the target port selection. + // + let foundService = false; + for (const name in this.serviceList) { + if (name === newServiceName) { + foundService = true; + break; + } + } + if (foundService) { + const currentPortValue = this['targetPort'].observable(); + if (currentPortValue !== DEFAULT_ROUTE_PORT) { + let foundPort = false; + for (const port of this.targetSvcPorts()) { + if (currentPortValue === port.text) { + foundPort = true; + break; + } + } + if (!foundPort) { + this['targetPort'].observable(DEFAULT_ROUTE_PORT); + } + } + } }; this.okInput = () => {