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

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Hoang Nguyen 2020-09-09 17:04:42 +07:00 committed by Rohit Yadav
parent 2ad58f0973
commit c697322bad
3 changed files with 104 additions and 11 deletions

View File

@ -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",

View File

@ -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>

View File

@ -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