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') }}
+
@@ -374,6 +392,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ handleDeleteInstanceFromRule(instance, record, ip)" />
+
+
@@ -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