diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 5b1cc6a95178..e8658cbcbe3d 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -634,6 +634,7 @@ "label.crosszones": "Cross Zones", "label.currency": "Currency", "label.current": "isCurrent", +"label.currentsslcert": "Current SSL Certificate", "label.currentpassword": "Current Password", "label.custom": "Custom", "label.custom.disk.offering": "Custom Disk Offering", @@ -1217,6 +1218,11 @@ "label.lb.algorithm.roundrobin": "Round-robin", "label.lb.algorithm.source": "Source", "label.lb.cookie": "LbCookie", +"label.lb.config": "LB Configs", +"label.lb.configuration": "Configuration", +"label.lb.config.value": "Value", +"label.lb.config.name": "Lb Config name", +"label.lb.config.default.value": "Default value", "label.lb.protocol.http": "HTTP", "label.lb.protocol.ssl": "SSL", "label.lb.protocol.tcp.proxy": "TCP-proxy", @@ -1977,6 +1983,7 @@ "label.ssh.port": "SSH Port", "label.sshkeypair": "New SSH Key Pair", "label.sshkeypairs": "SSH keypairs", +"label.ssl": "SSL", "label.sslcertificates": "SSL Certificates", "label.standard.us.keyboard": "Standard (US) keyboard", "label.start": "Start", @@ -2460,6 +2467,7 @@ "message.add.ip.range.direct.network": "Add an IP range to direct network in zone ", "message.add.ip.range.to.pod": "

Add an IP range to pod:

", "message.add.iprange.processing": "Adding IP Range...", +"message.add.lbconfig.processing": "Adding new load balancer config", "message.add.load.balancer": "Add a load balancer to zone", "message.add.load.balancer.under.ip": "The load balancer rule has been added under IP:", "message.add.network": "Add a new network for zone: ", @@ -2852,6 +2860,7 @@ "message.failed.to.add": "Failed to add", "message.failed.to.assign.vms": "Failed to assign VMs", "message.failed.to.remove": "Failed to remove", +"message.failed.to.remove.lbconfig": "Failed to remove load balancer config", "message.generate.keys": "Please confirm that you would like to generate new keys for this user.", "message.gslb.delete.confirm": "Please confirm you want to delete this GSLB", "message.gslb.lb.remove.confirm": "Please confirm you want to remove load balancing from GSLB", @@ -3019,6 +3028,8 @@ "message.remove.instance.failed": "Failed to remove instance", "message.remove.instance.processing": "Removing...", "message.remove.iprange.processing": "Removing IP Range...", +"message.remove.lbconfig.processing": "Removing load balancer config", +"message.remove.lbconfig.failed": "Failed to remove Load Balancer Config", "message.remove.ldap": "Are you sure you want to delete the LDAP configuration?", "message.remove.nic.processing": "Removing NIC...", "message.remove.port.forward.failed": "Removing Port Forwarding rule failed", @@ -3139,6 +3150,7 @@ "message.success.remove.instance.rule": "Successfully removed instance from rule", "message.success.remove.ip": "Successfully removed IP", "message.success.remove.iprange": "Successfully removed IP Range", +"message.success.remove.lbconfig": "Successfully removed load balancer config", "message.success.remove.nic": "Successfully removed", "message.success.remove.port.forward": "Successfully removed Port Forwarding rule", "message.success.remove.rule": "Successfully deleted rule", diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index 29b57e2f3f5d..3aaf81369c62 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -45,6 +45,10 @@ export default { name: 'egress.rules', component: () => import('@/views/network/EgressRulesTab.vue'), show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis } + }, { + name: 'lb.config', + component: () => import('@/views/network/LbConfigTab.vue'), + show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis } }, { name: 'public.ip.addresses', component: () => import('@/views/network/IpAddressesTab.vue'), diff --git a/ui/src/views/network/LbConfigTab.vue b/ui/src/views/network/LbConfigTab.vue new file mode 100644 index 000000000000..53d75ea2d16e --- /dev/null +++ b/ui/src/views/network/LbConfigTab.vue @@ -0,0 +1,341 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + + + + + + \ No newline at end of file diff --git a/ui/src/views/network/LoadBalancing.vue b/ui/src/views/network/LoadBalancing.vue index ea991329b79c..560d1c084592 100644 --- a/ui/src/views/network/LoadBalancing.vue +++ b/ui/src/views/network/LoadBalancing.vue @@ -50,8 +50,15 @@ {{ $t('label.tcp.proxy') }} {{ $t('label.tcp') }} {{ $t('label.udp') }} + {{ $t('label.ssl') }} +
+
{{ $t('label.sslcertificates') }}
+ + SSl Certificate + +
{{ $t('label.add.vms') }}
@@ -82,6 +89,16 @@ {{ returnStickinessLabel(record.id) }} + + @@ -396,6 +534,7 @@ export default { data () { return { loading: true, + visible: true, lbRules: [], newTagsForm: this.$form.createForm(this), tagsModalVisible: false, @@ -428,7 +567,8 @@ export default { publicport: '', protocol: 'tcp', virtualmachineid: [], - vmguestip: [] + vmguestip: [], + sslcert: '' }, addVmModalVisible: false, addVmModalLoading: false, @@ -438,6 +578,34 @@ export default { totalCount: 0, page: 1, pageSize: 10, + lbConfigs: [], + savedLbConfigs: [], + totalCountLbConfig: 0, + sslcerts: { + loading: false, + data: [] + }, + selectedSsl: { + name: '', + id: null + }, + addSslCertModalVisible: false, + showAssignedSsl: false, + addLbConfigVisible: false, + addLbConfigModalLoading: false, + currentAccountId: null, + assignedSslCert: 'None', + buttonVisible: false, + deleteSslButtonVisible: true, + addSslButtonVisible: true, + lbConfig: { + scope: 'LoadBalancerRule', + name: '', + description: null, + defaultvalue: null, + value: null, + forced: 'true' + }, columns: [ { title: this.$t('label.name'), @@ -467,6 +635,14 @@ export default { title: this.$t('label.action.configure.stickiness'), scopedSlots: { customRender: 'stickiness' } }, + { + title: this.$t('label.lb.configuration'), + scopedSlots: { customRender: 'configuration' } + }, + { + title: this.$t('label.sslcertificates'), + scopedSlots: { customRender: 'sslcert' } + }, { title: this.$t('label.add.vms'), scopedSlots: { customRender: 'add' } @@ -476,6 +652,28 @@ export default { scopedSlots: { customRender: 'actions' } } ], + lbconfigColumns: [ + { + title: this.$t('label.lb.config.name'), + dataIndex: 'name' + }, + { + title: this.$t('label.description'), + dataIndex: 'description' + }, + { + title: this.$t('label.lb.config.default.value'), + dataIndex: 'defaultvalue' + }, + { + title: this.$t('label.lb.config.value'), + dataIndex: 'value' + }, + { + title: this.$t('label.action'), + scopedSlots: { customRender: 'actions' } + } + ], tiers: { loading: false, data: [] @@ -614,6 +812,242 @@ export default { }) }) }, + fetchSslCerts () { + this.sslcerts.loading = true + this.sslcerts.data = [] + // Firt get the account id + api('listAccounts', { + name: this.resource.account, + domainid: this.resource.domainid + }).then(json => { + const accounts = json.listaccountsresponse.account || [] + if (accounts.length > 0) { + // Now fetch all the ssl certs for this account + this.currentAccountId = accounts[0].id + api('listSslCerts', { + accountid: this.currentAccountId + }).then(json => { + if (json.listsslcertsresponse.sslcert && json.listsslcertsresponse.sslcert.length > 0) { + this.selectedSsl.name = json.listsslcertsresponse.sslcert[0].name + this.selectedSsl.id = json.listsslcertsresponse.sslcert[0].id + json.listsslcertsresponse.sslcert.forEach(entry => this.sslcerts.data.push(entry)) + } + }).catch(error => { + this.$notifyError(error) + }) + } + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + this.sslcerts.loading = false + }) + if (this.selectedRule !== null) { + this.getCurrentlyAssignedSslCert() + } + }, + getCurrentlyAssignedSslCert () { + api('listSslCerts', { + accountid: this.currentAccountId, + lbruleid: this.selectedRule.id + }).then(json => { + if (json.listsslcertsresponse.sslcert && json.listsslcertsresponse.sslcert.length > 0) { + this.assignedSslCert = json.listsslcertsresponse.sslcert[0].name + this.deleteSslButtonVisible = true + } else { + this.assignedSslCert = 'None' + this.deleteSslButtonVisible = false + } + }).catch(error => { + this.$notifyError(error) + }) + }, + selectssl (e) { + this.selectedSsl.id = e + }, + handleAddSslCert (data) { + this.addSslCert(data, this.selectedSsl.id) + }, + addSslTolbRule () { + this.visible = false + this.addSslCert(this.selectedRule.id, this.selectedSsl.id) + }, + addSslCert (lbRuleId, certId) { + this.disableSslAddDeleteButtons() + api('assignCertToLoadBalancer', { + lbruleid: lbRuleId, + certid: certId, + forced: true + }).then(response => { + this.$pollJob({ + jobId: response.assigncerttoloadbalancerresponse.jobid, + successMessage: `Successfully assigned Ssl certificate`, + successMethod: () => { + if (this.selectedRule !== null) { + this.getCurrentlyAssignedSslCert() + } + this.enableSslAddDeleteButtons() + }, + errorMessage: 'Failed to assign ssl certificate', + errorMethod: () => { + }, + loadingMessage: `Assigning ssl certificate...`, + catchMessage: 'Error encountered while fetching async job result addSslTolbRule', + catchMethod: (e) => { + this.closeModal() + } + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + }) + }, + removeSslFromLbRule () { + this.disableSslAddDeleteButtons() + api('removeCertFromLoadBalancer', { + lbruleid: this.selectedRule.id + }).then(response => { + this.$pollJob({ + jobId: response.removecertfromloadbalancerresponse.jobid, + successMessage: `Successfully removed Ssl certificate`, + successMethod: () => { + this.visible = true + this.getCurrentlyAssignedSslCert() + this.enableSslAddDeleteButtons() + }, + errorMessage: 'Failed to remove ssl certificate', + errorMethod: () => { + this.visible = true + }, + loadingMessage: `Removing ssl certificate...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.closeModal() + } + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + }) + }, + populateValues () { + for (let i = 0; i < this.lbConfigs.length; i++) { + if (this.lbConfig.name === this.lbConfigs[i].name) { + this.lbConfig.description = this.lbConfigs[i].description + this.lbConfig.defaultvalue = this.lbConfigs[i].defaultvalue + } + } + }, + enableSslAddDeleteButtons () { + this.deleteSslButtonVisible = true + this.addSslButtonVisible = true + }, + disableSslAddDeleteButtons () { + this.addSslButtonVisible = false + this.deleteSslButtonVisible = false + }, + handleDeleteLoadBalancerConfig (rule) { + this.addLbConfigModalLoading = true + api('deleteLoadBalancerConfig', { + id: rule.id + }).then(response => { + this.$pollJob({ + jobId: response.deleteloadbalancerconfigresponse.jobid, + successMessage: `Successfully removed load balancer config`, + successMethod: () => { + this.fetchSavedLbConfigs() + }, + errorMessage: 'Failed to remove load balancer config', + errorMethod: () => { + this.fetchSavedLbConfigs() + }, + loadingMessage: `Removing load balancer config...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.fetchSavedLbConfigs() + } + }) + }).catch(error => { + this.$notifyError(error) + this.fetchSavedLbConfigs() + }) + }, + handleOpenAddConfiguration () { + api('listLoadBalancerConfigs', { + listAll: true, + scope: 'LoadBalancerRule', + loadbalancerid: this.selectedRule.id + }).then(response => { + this.lbConfigs = response.listloadbalancerconfigsresponse.loadbalancerconfig + this.addLbConfigVisible = true + const tempLbConfig = response.listloadbalancerconfigsresponse.loadbalancerconfig[0] + this.lbConfig.name = tempLbConfig.name + this.lbConfig.description = tempLbConfig.description + this.lbConfig.defaultvalue = tempLbConfig.defaultvalue + }).catch(error => { + this.$notifyError(error) + this.closeModal() + }) + this.fetchSavedLbConfigs() + }, + handleAddNewLbConfig () { + if (!this.lbConfig.value) { + this.$refs.lbconfigValue.classList.add('error') + return + } else { + this.$refs.lbconfigValue.classList.remove('error') + } + this.addLbConfigModalLoading = true + api('createLoadBalancerConfig', { + scope: 'LoadBalancerRule', + name: this.lbConfig.name, + value: this.lbConfig.value, + forced: 'true', + loadbalancerid: this.selectedRule.id + }).then(response => { + this.$pollJob({ + jobId: response.createloadbalancerconfigresponse.jobid, + successMessage: this.$t('message.success.create.lbconfig'), + successMethod: () => { + this.fetchSavedLbConfigs() + }, + errorMessage: this.$t('message.failed.to.remove.lbconfig'), + errorMethod: () => { + this.fetchSavedLbConfigs() + }, + loadingMessage: this.$t('message.add.lbconfig.processing'), + catchMessage: this.$t('error.fetching.async.job.result'), + catchMethod: () => { + this.fetchSavedLbConfigs() + } + }) + this.addLbConfigModalLoading = true + }).catch(error => { + this.$notifyError(error) + this.fetchSavedLbConfigs() + }) + this.lbConfig.value = null + }, + fetchSavedLbConfigs () { + api('listLoadBalancerConfigs', { + scope: 'LoadBalancerRule', + loadbalancerid: this.selectedRule.id + }).then(response => { + this.savedLbConfigs = response.listloadbalancerconfigsresponse.loadbalancerconfig + this.totalCountLbConfig = response.listloadbalancerconfigsresponse.count || 0 + }).catch(error => { + this.$notifyError(error) + this.loading = false + }) + this.addLbConfigModalLoading = false + }, + handleOpenAddSslCertModal () { + this.addSslCertModalVisible = true + if (this.selectedRule) { + this.showAssignedSsl = true + this.buttonVisible = true + } + this.fetchSslCerts() + }, returnAlgorithmName (name) { switch (name) { case 'leastconn': @@ -1076,6 +1510,9 @@ export default { successMethod: () => { this.parentFetchData() this.parentToggleLoading() + if (this.selectedSsl.id !== null) { + this.handleAddSslCert(data) + } this.fetchData() this.closeModal() }, @@ -1145,6 +1582,11 @@ export default { this.newRule.virtualmachineid = [] this.newTagsForm.resetFields() this.stickinessPolicyForm.resetFields() + this.addLbConfigVisible = false + this.addSslCertModalVisible = false + this.showAssignedSsl = false + this.buttonVisible = false + this.savedLbConfigs = [] }, handleChangePage (page, pageSize) { this.page = page