| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- <template>
- <base-dialog @cancel="cancelDialog">
- <div slot="header">{{$t('compute.text_390')}}</div>
- <div slot="body">
- <dialog-selected-tips :count="params.data.length" :action="$t('compute.text_390')" />
- <dialog-table :data="params.data" :columns="columns" />
- <a-form :form="form.fc" hideRequiredMark v-bind="formItemLayout">
- <a-form-model-item :label="$t('compute.text_106')" class="mb-0">
- <a-form-item :help="help">
- <base-select
- class="w-100"
- v-decorator="decorators.network"
- resource="networks"
- :params="networkParams"
- :item.sync="form.fi.network"
- remote
- :label-format="networkLabelFormat"
- :remote-fn="q => ({ filter: `name.contains(${q})` })"
- :select-props="{ placeholder: $t('compute.text_195') }"
- :mapper="mapper" />
- </a-form-item>
- <a-form-model-item v-if="isSupportIPv4 && !(hasIpv6 && ipv6Mode === 'only')">
- <div class="d-flex">
- <a-form-item class="mb-0">
- <a-checkbox v-model="ipv4ConfigShow" style="display:inline-block;min-width:200px"><a-button type="link" class="pl-1">{{ $t('compute.text_198') }}</a-button></a-checkbox>
- </a-form-item>
- <a-form-item class="mb-0">
- <ip-select v-if="ipv4ConfigShow" v-decorator="decorators.ip" :value="form.fi.ip" :network="form.fi.network" @change="ipChange" />
- </a-form-item>
- </div>
- </a-form-model-item>
- <template v-if="isSupportIPv6">
- <a-form-model-item class="mb-0">
- <div class="d-flex">
- <div>
- <a-checkbox v-if="isSupportIPv4" v-model="hasIpv6" @change="requireIpv6Change" class="mr-1" />
- <a-dropdown>
- <a-menu slot="overlay" @click="triggerIpv6Mode" v-if="isSupportIPv4">
- <a-menu-item key="all">{{ $t('compute.server_create.require_ipv6_all') }}</a-menu-item>
- <a-menu-item key="only">{{ $t('compute.server_create.require_ipv6_only') }}</a-menu-item>
- </a-menu>
- <a-button type="link" class="pl-1" v-if="isSupportIPv4">{{ ipv6Mode === 'only' ? $t('compute.server_create.require_ipv6_only') : $t('compute.server_create.require_ipv6_all') }}<a-icon type="down" /> </a-button>
- </a-dropdown>
- </div>
- <template v-if="isSupportIPv6 && ipv6ConfigShow">
- <template v-if="ipv6InputShow">
- <div class="mb-0 ml-1" style="display:flex">
- <span class="mr-1">{{ getIpv6Prefix(form.fi.network?.guest_ip6_start) }}</span>
- <a-form-item class="mb-0" style="display:inline-block">
- <a-input
- style="width: 164px"
- :placeholder="$t('compute.complete_ipv6_address')"
- v-decorator="decorators.address6" />
- </a-form-item>
- <a-button type="link" class="mt-1" @click="triggerShowIpv6">{{$t('compute.text_135')}}</a-button>
- </div>
- </template>
- <a-button v-else type="link" class="mt-1" @click="triggerShowIpv6">{{$t('compute.ipv6_config')}}</a-button>
- </template>
- </div>
- </a-form-model-item>
- </template>
- </a-form-model-item>
- <a-form-item>
- <a-checkbox v-decorator="decorators.restartNetwork">{{$t('compute.restart_network')}}</a-checkbox>
- <help-tooltip name="restartNetworkToEffectIp" />
- </a-form-item>
- </a-form>
- </div>
- <div slot="footer">
- <a-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('dialog.ok') }}</a-button>
- <a-button @click="cancelDialog">{{ $t('dialog.cancel') }}</a-button>
- </div>
- </base-dialog>
- </template>
- <script>
- import * as R from 'ramda'
- import { mapGetters } from 'vuex'
- import ipaddr from 'ipaddr.js'
- import IpSelect from '@Compute/sections/ServerNetwork/IpSelect'
- import { validate, isWithinRange } from '@/utils/validate'
- import DialogMixin from '@/mixins/dialog'
- import WindowsMixin from '@/mixins/windows'
- import { HYPERVISORS_MAP } from '@/constants'
- import expectStatus from '@/constants/expectStatus'
- import { getIpv6Start, ipv6ToHex } from '@Compute/utils/createServer'
- export default {
- name: 'VmChangeIpDialog',
- components: {
- IpSelect,
- },
- mixins: [DialogMixin, WindowsMixin],
- data () {
- const validateIp = (rule, value, callback) => {
- let msg
- if (!R.isNil(value) && !R.isEmpty(value)) {
- if (R.isEmpty(this.form.fi.network)) {
- msg = this.$t('compute.text_1191')
- return callback(msg)
- }
- if (validate(value, 'IPv4') !== true) {
- msg = this.$t('compute.text_1192')
- return callback(msg)
- }
- if (!isWithinRange(value, this.form.fi.network.guest_ip_start, this.form.fi.network.guest_ip_end)) {
- msg = this.$t('compute.text_1193')
- return callback(msg)
- }
- }
- return callback()
- }
- const validateIpv6 = (rule, value, cb) => {
- const networkData = this.form.fi.network
- const ipv6First = getIpv6Start(networkData.guest_ip6_start)
- try {
- const ipv6 = ipv6First + value
- const ipAddr = ipaddr.IPv6.parse(ipv6)
- const subnet1Addr = ipaddr.IPv6.parse(networkData.guest_ip6_start)
- const subnet2Addr = ipaddr.IPv6.parse(networkData.guest_ip6_end)
- if (ipAddr.kind() !== 'ipv6') {
- cb(new Error(this.$t('compute.error_ipv6')))
- }
- const target = ipv6ToHex(ipAddr)
- const start = ipv6ToHex(subnet1Addr)
- const end = ipv6ToHex(subnet2Addr)
- // 检查IP是否在两个子网之间
- if (!((target >= start && target <= end))) {
- cb(new Error(this.$t('compute.ipv6_within_range')))
- }
- cb()
- } catch (err) {
- cb(new Error(this.$t('compute.error_ipv6')))
- }
- }
- let hasIpv6 = false
- let initIpv6Value = ''
- let initIpv4Value = ''
- if (this.params.data[0].ip6_addr) {
- hasIpv6 = true
- initIpv6Value = this.getIpv6Value(this.params.data[0].ip6_addr)
- }
- if (this.params.data[0].ip_addr) {
- initIpv4Value = this.params.data[0].ip_addr
- }
- return {
- loading: false,
- form: {
- fc: this.$form.createForm(this),
- fi: {
- network: {},
- ip: this.params.data[0].ip_addr,
- },
- },
- hasIpv6,
- decorators: {
- network: [
- 'network',
- {
- initialValue: this.params.data[0].network_id,
- rules: [
- { required: true, message: this.$t('compute.text_1191') },
- ],
- },
- ],
- ip: [
- 'ip',
- {
- initialValue: this.params.data[0].ip_addr,
- rules: [
- { required: true, message: this.$t('common.tips.select', ['IP']), validator: validateIp },
- ],
- },
- ],
- address6: [
- 'address6',
- {
- initialValue: initIpv6Value,
- validateFirst: true,
- validateTrigger: ['blur', 'change'],
- rules: [
- {
- required: true,
- message: this.$t('compute.complete_ipv6_address'),
- },
- {
- validator: validateIpv6,
- },
- ],
- },
- ],
- restartNetwork: [
- 'restartNetwork',
- {
- valuePropName: 'checked',
- initialValue: true,
- },
- ],
- },
- formItemLayout: {
- wrapperCol: {
- span: 21,
- },
- labelCol: {
- span: 3,
- },
- },
- ipv4ConfigShow: !!initIpv4Value,
- ipv6ConfigShow: hasIpv6,
- ipv6InputShow: hasIpv6,
- ipv6Mode: 'all',
- }
- },
- computed: {
- ...mapGetters(['scope']),
- networkParams () {
- const params = {
- zone: this.params.zone,
- scope: this.scope,
- wire: this.params.data[0].wire_id,
- filter: 'server_type.notin(ipmi, pxe)',
- }
- if (this.params.hypervisor === HYPERVISORS_MAP.esxi.key) {
- params.vpc_id = 'default'
- }
- return params
- },
- columns () {
- const showFields = ['ifname', 'ip_addr', 'mac_addr']
- return this.params.columns.filter((item) => { return showFields.includes(item.field) })
- },
- help () {
- if (this.params.hypervisor === HYPERVISORS_MAP.esxi.key) {
- return this.$t('compute.text_1194')
- }
- return ''
- },
- isSupportIPv4 () {
- return !!this.form.fi.network.guest_ip_start && !!this.form.fi.network.guest_ip_end
- },
- isSupportIPv6 () {
- return !!this.form.fi.network.guest_ip6_start && !!this.form.fi.network.guest_ip6_end
- },
- },
- methods: {
- triggerIpv6Mode (e) {
- this.ipv6Mode = e.key
- },
- networkLabelFormat (item) {
- let label = item.name
- const details = []
- if (item.guest_ip_start && item.guest_ip_end) {
- details.push(`${item.guest_ip_start} - ${item.guest_ip_end}/${item.guest_ip_mask}`)
- }
- if (item.guest_ip6_start && item.guest_ip6_end) {
- details.push(`${item.guest_ip6_start} - ${item.guest_ip6_end}/${item.guest_ip6_mask}`)
- }
- details.push(`vlan=${item.vlan_id}`)
- label += `(${details.join(',')})`
- return label
- },
- ipChange (e) {
- this.form.fi.ip = e
- },
- requireIpv6Change (e) {
- this.ipv6ConfigShow = e.target.checked
- },
- triggerShowIpv6 () {
- this.ipv6InputShow = !this.ipv6InputShow
- },
- getIpv6Prefix (ipv6 = '') {
- if (ipv6) {
- const list = ipaddr.parse(ipv6).toNormalizedString().split(':')
- return list.slice(0, 4).join(':') + ':'
- }
- return ''
- },
- getIpv6Value (ipv6 = '') {
- if (ipv6) {
- const list = ipaddr.parse(ipv6).toNormalizedString().split(':')
- return list.slice(4, 8).join(':')
- }
- return ''
- },
- async handleConfirm () {
- this.loading = true
- let manager = new this.$Manager('servers')
- try {
- const values = await this.form.fc.validateFields()
- const net_desc = {}
- if (values.network) {
- net_desc.network = values.network
- }
- if (values.ip) {
- net_desc.address = values.ip
- }
- if (this.hasIpv6) {
- net_desc.require_ipv6 = true
- } else {
- net_desc.require_ipv6 = false
- }
- if (!this.isSupportIPv4 && net_desc.require_ipv6) {
- net_desc.strict_ipv6 = true
- }
- const address6 = values.address6
- if (address6) {
- const ipv6Last = address6
- const target = this.form.fi.network
- const ipv6First = getIpv6Start(target?.guest_ip6_start)
- net_desc.address6 = ipv6First + ipv6Last
- }
- if (!net_desc.address6 && net_desc.require_ipv6) {
- net_desc.address6 = ''
- }
- if (this.ipv6Mode === 'only' && net_desc.require_ipv6) {
- net_desc.strict_ipv6 = true
- }
- const data = {
- ip_addr: this.params.data[0].ip_addr,
- net_desc,
- restart_network: values.restartNetwork,
- }
- await manager.performAction({
- id: this.params.resId,
- action: 'change-ipaddr',
- data,
- })
- this.params.refresh()
- this.$bus.$emit('VMInstanceListSingleRefresh', [this.params.resId, Object.values(expectStatus.server).flat()])
- this.cancelDialog()
- this.$message.success(this.$t('compute.text_423'))
- } finally {
- this.loading = false
- manager = null
- }
- },
- mapper (list) {
- return list.sort((a, b) => { return (b.ports - b.ports_used) - (a.ports - a.ports_used) })
- },
- },
- }
- </script>
|