You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2020/09/09 10:04:50 UTC
[cloudstack-primate] branch master updated: vm wizard: add MAC
Address validator (#657)
This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-primate.git
The following commit(s) were added to refs/heads/master by this push:
new d03e559 vm wizard: add MAC Address validator (#657)
d03e559 is described below
commit d03e559c5ad0155de4b4407c534e21c7d0b3f530
Author: Hoang Nguyen <ho...@unitech.vn>
AuthorDate: Wed Sep 9 17:04:42 2020 +0700
vm wizard: add MAC Address validator (#657)
* vm wizard: add MAC Address validator
* show IP range and check valid IP range
* add CIDR into expanding of network selection & configuration
* hide element when network type !== L2
---
src/locales/en.json | 3 +
src/views/compute/wizard/NetworkConfiguration.vue | 103 +++++++++++++++++++---
src/views/compute/wizard/NetworkSelection.vue | 9 +-
3 files changed, 104 insertions(+), 11 deletions(-)
diff --git a/src/locales/en.json b/src/locales/en.json
index 1159c58..300c549 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1254,6 +1254,7 @@
"label.lun.number": "LUN #",
"label.lxcnetworklabel": "LXC Traffic Label",
"label.macaddress": "MAC Address",
+"label.macaddress.example": "The MAC Address. Example: 01:23:45:67:89:ab",
"label.macaddresschanges": "MAC Address Changes",
"label.macos": "MacOS",
"label.make.project.owner": "Make account project owner",
@@ -2743,6 +2744,7 @@
"message.error.internallb.name": "Please specify a name for the Internal LB",
"message.error.internallb.source.port": "Please specify a Source Port",
"message.error.invalid.range": "Please enter values from {min} to {max}",
+"message.error.ip.range": "Please enter valid range",
"message.error.ipv4.address": "Please enter a valid IPv4 address",
"message.error.ipv4.dns1": "Please enter IpV4 DNS 1",
"message.error.ipv4.dns2": "Please enter IpV4 DNS 2",
@@ -2757,6 +2759,7 @@
"message.error.limit.value": "The value must not be less than",
"message.error.loading.setting": "There was an error loading these settings.",
"message.error.lun": "Please enter LUN #",
+"message.error.macaddress": "Please enter a valid MAC Address.",
"message.error.name": "Please enter name",
"message.error.netmask": "Please enter Netmask",
"message.error.network.domain": "Please enter Network domain",
diff --git a/src/views/compute/wizard/NetworkConfiguration.vue b/src/views/compute/wizard/NetworkConfiguration.vue
index 823f1b1..d19cec9 100644
--- a/src/views/compute/wizard/NetworkConfiguration.vue
+++ b/src/views/compute/wizard/NetworkConfiguration.vue
@@ -25,17 +25,45 @@
size="middle"
:scroll="{ y: 225 }"
>
+ <template slot="name" slot-scope="text, record">
+ <div>{{ text }}</div>
+ <small v-if="record.type!=='L2'">{{ $t('label.cidr') + ': ' + record.cidr }}</small>
+ </template>
<template slot="ipAddress" slot-scope="text, record">
- <a-input
- style="width: 150px;"
- :placeholder="$t('label.ipaddress')"
- @change="($event) => updateNetworkData('ipAddress', record.id, $event.target.value)" />
+ <a-form-item v-if="record.type!=='L2'">
+ <a-input
+ style="width: 150px;"
+ v-decorator="['ipAddress' + record.id, {
+ rules: [{
+ validator: validatorIpAddress,
+ cidr: record.cidr,
+ networkType: record.type
+ }]
+ }]"
+ :placeholder="record.cidr"
+ @change="($event) => updateNetworkData('ipAddress', record.id, $event.target.value)">
+ <a-tooltip v-if="record.type !== 'L2'" slot="suffix" :title="getIpRangeDescription(record)">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </a-input>
+ </a-form-item>
</template>
<template slot="macAddress" slot-scope="text, record">
- <a-input
- style="width: 150px;"
- :placeholder="$t('label.macaddress')"
- @change="($event) => updateNetworkData('macAddress', record.id, $event.target.value)" />
+ <a-form-item>
+ <a-input
+ style="width: 150px;"
+ :placeholder="$t('label.macaddress')"
+ v-decorator="[`macAddress` + record.id, {
+ rules: [{
+ validator: validatorMacAddress
+ }]
+ }]"
+ @change="($event) => updateNetworkData('macAddress', record.id, $event.target.value)">
+ <a-tooltip slot="suffix" :title="$t('label.macaddress.example')">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </a-input>
+ </a-form-item>
</template>
</a-table>
</template>
@@ -64,7 +92,8 @@ export default {
{
dataIndex: 'name',
title: this.$t('label.defaultnetwork'),
- width: '30%'
+ width: '30%',
+ scopedSlots: { customRender: 'name' }
},
{
dataIndex: 'ip',
@@ -80,7 +109,9 @@ export default {
}
],
selectedRowKeys: [],
- dataItems: []
+ dataItems: [],
+ macRegex: /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/i,
+ ipV4Regex: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i
}
},
beforeCreate () {
@@ -150,6 +181,49 @@ export default {
this.$emit('select-default-network-item', this.dataItems[0].id)
}
}
+ },
+ validatorMacAddress (rule, value, callback) {
+ if (!value || value === '') {
+ callback()
+ } else if (!this.macRegex.test(value)) {
+ callback(this.$t('message.error.macaddress'))
+ } else {
+ callback()
+ }
+ },
+ validatorIpAddress (rule, value, callback) {
+ if (!value || value === '') {
+ callback()
+ } else if (!this.ipV4Regex.test(value)) {
+ callback(this.$t('message.error.ipv4.address'))
+ } else if (rule.networkType !== 'L2' && !this.isIp4InCidr(value, rule.cidr)) {
+ const rangeIps = this.calculateCidrRange(rule.cidr)
+ const message = `${this.$t('message.error.ip.range')} ${this.$t('label.from')} ${rangeIps[0]} ${this.$t('label.to')} ${rangeIps[1]}`
+ callback(message)
+ } else {
+ callback()
+ }
+ },
+ getIpRangeDescription (network) {
+ const rangeIps = this.calculateCidrRange(network.cidr)
+ const rangeIpDescription = [`${this.$t('label.ip.range')}:`, rangeIps[0], '-', rangeIps[1]].join(' ')
+ return rangeIpDescription
+ },
+ isIp4InCidr (ip, cidr) {
+ const [range, bits = 32] = cidr.split('/')
+ const mask = ~(2 ** (32 - bits) - 1)
+ return (this.ip4ToInt(ip) & mask) === (this.ip4ToInt(range) & mask)
+ },
+ calculateCidrRange (cidr) {
+ const [range, bits = 32] = cidr.split('/')
+ const mask = ~(2 ** (32 - bits) - 1)
+ return [this.intToIp4(this.ip4ToInt(range) & mask), this.intToIp4(this.ip4ToInt(range) | ~mask)]
+ },
+ ip4ToInt (ip) {
+ return ip.split('.').reduce((int, oct) => (int << 8) + parseInt(oct, 10), 0) >>> 0
+ },
+ intToIp4 (int) {
+ return [(int >>> 24) & 0xFF, (int >>> 16) & 0xFF, (int >>> 8) & 0xFF, int & 0xFF].join('.')
}
}
}
@@ -159,4 +233,13 @@ export default {
.ant-table-wrapper {
margin: 2rem 0;
}
+
+ /deep/.ant-table-tbody > tr td:not(:first-child) {
+ vertical-align: baseline;
+ }
+
+ .ant-form .ant-form-item {
+ margin-bottom: 0;
+ padding-bottom: 0;
+ }
</style>
diff --git a/src/views/compute/wizard/NetworkSelection.vue b/src/views/compute/wizard/NetworkSelection.vue
index 9b7dd12..cf8df5a 100644
--- a/src/views/compute/wizard/NetworkSelection.vue
+++ b/src/views/compute/wizard/NetworkSelection.vue
@@ -237,7 +237,7 @@ export default {
inject: ['vmFetchNetworks'],
methods: {
getDetails (network) {
- return [
+ const detail = [
{
title: this.$t('label.description'),
description: network.displaytext
@@ -247,6 +247,13 @@ export default {
description: network.networkofferingdisplaytext
}
]
+ if (network.type !== 'L2') {
+ detail.push({
+ title: this.$t('label.cidr'),
+ description: network.cidr
+ })
+ }
+ return detail
},
handleSearch (value) {
this.filter = value