| // 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. |
| |
| <template> |
| <div v-ctrl-enter="handleSubmit"> |
| <a-card |
| class="ant-form-text" |
| style="text-align: justify; margin: 10px 0; padding: 24px;" |
| v-html="$t(description)"> |
| </a-card> |
| <a-form |
| class="form-content" |
| :ref="formRef" |
| :model="form" |
| :rules="rules" |
| > |
| <a-form-item |
| name="name" |
| ref="name" |
| :label="$t('label.name')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-input |
| v-model:value="form.name" |
| v-focus="true" |
| /> |
| </a-form-item> |
| <div v-if="!this.isEdgeZone"> |
| <a-form-item |
| name="ipv4Dns1" |
| ref="ipv4Dns1" |
| :label="$t('label.ipv4.dns1')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-input v-model:value="form.ipv4Dns1" /> |
| </a-form-item> |
| <a-form-item |
| name="ipv4Dns2" |
| ref="ipv4Dns2" |
| :label="$t('label.ipv4.dns2')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-input v-model:value="form.ipv4Dns2" /> |
| </a-form-item> |
| <a-form-item |
| name="ipv6Dns1" |
| ref="ipv6Dns1" |
| :label="$t('label.ipv6.dns1')" |
| v-bind="formItemLayout" |
| v-if="isAdvancedZone" |
| has-feedback> |
| <a-input v-model:value="form.ipv6Dns1" /> |
| </a-form-item> |
| <a-form-item |
| name="ipv6Dns2" |
| ref="ipv6Dns2" |
| :label="$t('label.ipv6.dns2')" |
| v-bind="formItemLayout" |
| v-if="isAdvancedZone" |
| has-feedback> |
| <a-input v-model:value="form.ipv6Dns2" /> |
| </a-form-item> |
| <a-form-item |
| name="ipv6Cidr" |
| ref="ipv6Cidr" |
| :label="$t('label.ip6cidr')" |
| v-bind="formItemLayout" |
| v-if="isAdvancedZone && securityGroupsEnabled" |
| has-feedback> |
| <a-input v-model:value="form.ipv6Cidr" /> |
| </a-form-item> |
| <a-form-item |
| name="ip6gateway" |
| ref="ip6gateway" |
| :label="$t('label.ip6gateway')" |
| v-bind="formItemLayout" |
| v-if="isAdvancedZone && securityGroupsEnabled" |
| has-feedback> |
| <a-input v-model:value="form.ip6gateway" /> |
| </a-form-item> |
| <a-form-item |
| name="internalDns1" |
| ref="internalDns1" |
| :label="$t('label.internal.dns.1')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-input v-model:value="form.internalDns1" /> |
| </a-form-item> |
| <a-form-item |
| name="internalDns2" |
| ref="internalDns2" |
| :label="$t('label.internal.dns.2')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-input v-model:value="form.internalDns2" /> |
| </a-form-item> |
| </div> |
| <a-form-item |
| name="hypervisor" |
| ref="hypervisor" |
| :label="$t('label.hypervisor')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-select |
| v-model:value="form.hypervisor" |
| :placeholder="$t('message.error.hypervisor.type')" |
| :loading="hypervisors === null" |
| :disabled="this.isEdgeZone" |
| showSearch |
| optionFilterProp="value" |
| :filterOption="(input, option) => { |
| return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" > |
| <a-select-option v-for="hypervisor in hypervisors" :key="hypervisor.name"> |
| {{ hypervisor.name }} |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <div v-if="!this.isEdgeZone"> |
| <a-form-item |
| name="networkOfferingId" |
| ref="networkOfferingId" |
| :label="$t('label.network.offering')" |
| v-bind="formItemLayout" |
| v-if="!isAdvancedZone || securityGroupsEnabled" |
| has-feedback> |
| <a-select |
| :loading="availableNetworkOfferings === null" |
| v-model:value="form.networkOfferingId" |
| :placeholder="$t('message.error.network.offering')" |
| showSearch |
| optionFilterProp="label" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" > |
| <a-select-option |
| v-for="networkOffering in availableNetworkOfferings" |
| :key="networkOffering.id" |
| :label="networkOffering.displaytext || networkOffering.name || networkOffering.description"> |
| {{ networkOffering.displaytext || networkOffering.name || networkOffering.description }} |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <a-form-item |
| name="networkDomain" |
| ref="networkDomain" |
| :label="$t('label.network.domain')" |
| v-bind="formItemLayout" |
| has-feedback> |
| <a-input v-model:value="form.networkDomain" /> |
| </a-form-item> |
| <a-form-item |
| name="guestcidraddress" |
| ref="guestcidraddress" |
| :label="$t('label.guest.cidr')" |
| v-bind="formItemLayout" |
| v-if="isAdvancedZone && !securityGroupsEnabled" |
| has-feedback> |
| <a-input v-model:value="form.guestcidraddress" /> |
| </a-form-item> |
| </div> |
| <a-form-item |
| name="isDedicated" |
| ref="isDedicated" |
| :label="$t('label.dedicated')" |
| v-bind="formItemLayout"> |
| <a-switch v-model:checked="form.isDedicated" /> |
| </a-form-item> |
| <a-form-item |
| name="domainId" |
| ref="domainId" |
| :label="$t('label.domains')" |
| v-bind="formItemLayout" |
| has-feedback |
| v-if="isDedicated"> |
| <a-select |
| :loading="domains === null" |
| v-model:value="form.domainId" |
| :placeholder="$t('message.error.select.domain.to.dedicate')" |
| showSearch |
| optionFilterProp="label" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" > |
| <a-select-option v-for="dom in domains" :key="dom.id" :label="dom.path"> |
| {{ dom.path }} |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <a-alert style="margin-top: 5px" type="warning" v-if="this.isEdgeZone"> |
| <template #message> |
| <span v-html="$t('message.zone.edge.local.storage')" /> |
| </template> |
| </a-alert> |
| <div v-else> |
| <a-form-item |
| name="account" |
| ref="account" |
| :label="$t('label.account')" |
| v-bind="formItemLayout" |
| v-if="isDedicated"> |
| <a-input v-model:value="form.account" /> |
| </a-form-item> |
| <a-form-item |
| name="localstorageenabled" |
| ref="localstorageenabled" |
| :label="$t('label.local.storage.enabled')" |
| v-bind="formItemLayout"> |
| <a-switch v-model:checked="form.localstorageenabled"/> |
| </a-form-item> |
| <a-form-item |
| name="localstorageenabledforsystemvm" |
| ref="localstorageenabledforsystemvm" |
| :label="$t('label.local.storage.enabled.system.vms')" |
| v-bind="formItemLayout"> |
| <a-switch v-model:checked="form.localstorageenabledforsystemvm" /> |
| </a-form-item> |
| </div> |
| </a-form> |
| <div class="form-action"> |
| <a-button |
| @click="handleBack" |
| class="button-back" |
| v-if="!isFixError"> |
| {{ $t('label.previous') }} |
| </a-button> |
| <a-button ref="submit" type="primary" @click="handleSubmit" class="button-next"> |
| {{ $t('label.next') }} |
| </a-button> |
| </div> |
| </div> |
| </template> |
| |
| <script> |
| |
| import { ref, reactive, toRaw } from 'vue' |
| import { api } from '@/api' |
| |
| export default { |
| props: { |
| prefillContent: { |
| type: Object, |
| default: function () { |
| return {} |
| } |
| }, |
| isFixError: { |
| type: Boolean, |
| default: false |
| } |
| }, |
| data: () => ({ |
| formItemLayout: { |
| labelCol: { span: 8 }, |
| wrapperCol: { span: 12 } |
| }, |
| hypervisors: null, |
| networkOfferings: null, |
| domains: null, |
| baremetalProviders: ['BaremetalDhcpProvider', 'BaremetalPxeProvider', 'BaremetalUserdataProvider'], |
| selectedBaremetalProviders: [], |
| availableNetworkOfferings: null, |
| 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, |
| ipV6Regex: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i, |
| formModel: {} |
| }), |
| created () { |
| this.hypervisors = this.prefillContent?.hypervisors || null |
| this.networkOfferings = this.prefillContent?.networkOfferings || null |
| |
| this.initForm() |
| this.fetchData() |
| }, |
| mounted () { |
| this.form.name = this.name |
| this.form.ipv4Dns1 = this.ipv4Dns1 |
| this.form.ipv4Dns2 = this.ipv4Dns2 |
| this.form.ipv6Dns1 = this.ipv6Dns1 |
| this.form.ipv6Dns2 = this.ipv6Dns2 |
| this.form.internalDns1 = this.internalDns1 |
| this.form.internalDns2 = this.internalDns2 |
| this.form.hypervisor = this.currentHypervisor |
| this.form.networkOfferingId = this.currentNetworkOfferingId |
| this.form.networkDomain = this.networkDomain |
| this.form.guestcidraddress = this.isAdvancedZone && !this.securityGroupsEnabled ? this.guestcidraddress : null |
| this.form.isDedicated = this.isDedicated |
| this.form.domain = this.domain |
| this.form.account = this.account |
| this.form.localstorageenabled = this.localstorageenabled |
| this.form.localstorageenabledforsystemvm = this.localstorageenabledforsystemvm |
| |
| this.formModel = toRaw(this.form) |
| }, |
| watch: { |
| formModel: { |
| deep: true, |
| handler (changedFields) { |
| const fieldsChanged = toRaw(changedFields) |
| if (fieldsChanged.networkOfferingId && this.prefillContent.networkOfferingSelected) { |
| if (this.prefillContent.networkOfferingSelected.id !== fieldsChanged.networkOfferingId) { |
| fieldsChanged.physicalNetworks = [] |
| } |
| } |
| if (this.networkOfferings && fieldsChanged.networkOfferingId) { |
| fieldsChanged.networkOfferings = this.networkOfferings |
| fieldsChanged.networkOfferingSelected = this.networkOfferings[fieldsChanged.networkOfferingId] |
| } |
| if (this.hypervisors && fieldsChanged.hypervisor) { |
| fieldsChanged.hypervisors = this.hypervisors |
| this.availableNetworkOfferings = this.getAvailableNetworkOfferings(fieldsChanged.hypervisor) |
| } |
| if (this.domains && fieldsChanged.domain) { |
| fieldsChanged.domains = this.domains |
| } |
| this.$emit('fieldsChanged', fieldsChanged) |
| } |
| } |
| }, |
| computed: { |
| isAdvancedZone () { |
| return this.zoneType === 'Advanced' |
| }, |
| zoneType () { |
| return this.prefillContent?.zoneType || null |
| }, |
| securityGroupsEnabled () { |
| return this.isAdvancedZone && (this.prefillContent?.securityGroupsEnabled || false) |
| }, |
| isEdgeZone () { |
| return this.prefillContent?.zoneSuperType === 'Edge' || false |
| }, |
| description () { |
| return this.isEdgeZone ? 'message.desc.zone.edge' : 'message.desc.zone' |
| }, |
| name () { |
| return this.prefillContent?.name || null |
| }, |
| ipv4Dns1 () { |
| if (this.isEdgeZone) { |
| return '8.8.8.8' |
| } |
| return this.prefillContent?.ipv4Dns1 || null |
| }, |
| ipv4Dns2 () { |
| return this.prefillContent?.ipv4Dns2 || null |
| }, |
| ipv6Dns1 () { |
| return this.prefillContent?.ipv6Dns1 || null |
| }, |
| ipv6Dns2 () { |
| return this.prefillContent?.ipv6Dns2 || null |
| }, |
| internalDns1 () { |
| if (this.isEdgeZone) { |
| return '8.8.8.8' |
| } |
| return this.prefillContent?.internalDns1 || null |
| }, |
| internalDns2 () { |
| return this.prefillContent?.internalDns2 || null |
| }, |
| ipv6Cidr () { |
| return this.prefillContent?.ipv6Cidr || null |
| }, |
| ip6gateway () { |
| return this.prefillContent?.ip6gateway || null |
| }, |
| currentHypervisor () { |
| if (this.isEdgeZone) { |
| return 'KVM' |
| } |
| if (this.prefillContent.hypervisor) { |
| return this.prefillContent.hypervisor |
| } else if (this.hypervisors && this.hypervisors.length > 0) { |
| return this.hypervisors[0].name |
| } |
| return null |
| }, |
| currentNetworkOfferingId () { |
| const lastNetworkOfferingId = this.prefillContent?.networkOfferingSelected?.id || null |
| if (this.networkOfferings) { |
| if (lastNetworkOfferingId !== null && this.networkOfferings[lastNetworkOfferingId]) { |
| return lastNetworkOfferingId |
| } |
| return this.availableNetworkOfferings[0].id |
| } |
| return null |
| }, |
| networkDomain () { |
| return this.prefillContent?.networkDomain || null |
| }, |
| guestcidraddress () { |
| return this.prefillContent?.guestcidraddress || '10.1.1.0/24' |
| }, |
| isDedicated () { |
| return this.prefillContent?.isDedicated || false |
| }, |
| domain () { |
| const lastDomainId = this.prefillContent?.domainId || null |
| if (this.domains !== null && lastDomainId !== null && this.domains[lastDomainId]) { |
| return lastDomainId |
| } |
| return null |
| }, |
| account () { |
| return this.prefillContent?.account || null |
| }, |
| localstorageenabled () { |
| if (this.isEdgeZone) { |
| return true |
| } |
| return this.prefillContent?.localstorageenabled || false |
| }, |
| localstorageenabledforsystemvm () { |
| if (this.isEdgeZone) { |
| return true |
| } |
| return this.prefillContent?.localstorageenabledforsystemvm || false |
| } |
| }, |
| methods: { |
| initForm () { |
| this.formRef = ref() |
| this.form = reactive({}) |
| this.rules = reactive({ |
| name: [{ required: true, message: this.$t('message.error.zone.name') }], |
| ipv4Dns1: [ |
| { required: true, message: this.$t('message.error.ipv4.dns1') }, |
| { ipV4: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv4.address') } |
| ], |
| ipv4Dns2: [{ ipV4: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv4.address') }], |
| ipv6Dns1: [{ ipV6: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv6.address') }], |
| ipv6Dns2: [{ ipV6: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv6.address') }], |
| ip6gateway: [{ ipV6: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv6.gateway.format') }], |
| internalDns1: [ |
| { required: true, message: this.$t('message.error.internal.dns1') }, |
| { ipV4: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv4.address') } |
| ], |
| internalDns2: [{ ipV4: true, validator: this.checkIpFormat, message: this.$t('message.error.ipv4.address') }], |
| hypervisor: [{ required: true, message: this.$t('message.error.hypervisor.type') }] |
| }) |
| }, |
| fetchData () { |
| api('listHypervisors').then(json => { |
| this.hypervisors = json.listhypervisorsresponse.hypervisor |
| if ('listSimulatorHAStateTransitions' in this.$store.getters.apis) { |
| this.hypervisors.push({ name: 'Simulator' }) |
| } |
| this.form.hypervisor = this.currentHypervisor |
| this.formModel = toRaw(this.form) |
| }) |
| |
| if (!this.isAdvancedZone || this.securityGroupsEnabled) { |
| api('listNetworkOfferings', { state: 'Enabled', guestiptype: 'Shared' }).then(json => { |
| this.networkOfferings = {} |
| json.listnetworkofferingsresponse.networkoffering.forEach(offering => { |
| this.setupNetworkOfferingAdditionalFlags(offering) |
| this.networkOfferings[offering.id] = offering |
| }) |
| this.availableNetworkOfferings = this.getAvailableNetworkOfferings(this.currentHypervisor) |
| this.form.networkOfferingId = this.currentNetworkOfferingId |
| this.formModel = toRaw(this.form) |
| }) |
| } |
| |
| api('listDomains', { listAll: true }).then(json => { |
| this.domains = {} |
| json.listdomainsresponse.domain.forEach(dom => { |
| this.domains[dom.id] = dom |
| }) |
| this.form.domain = this.domain |
| this.formModel = toRaw(this.form) |
| }) |
| }, |
| handleSubmit () { |
| this.formRef.value.validate().then(() => { |
| if (this.isFixError) { |
| this.$emit('submitLaunchZone') |
| return |
| } |
| |
| this.$emit('nextPressed') |
| }).catch(error => { |
| this.formRef.value.scrollToField(error.errorFields[0].name) |
| }) |
| }, |
| handleBack () { |
| this.$emit('backPressed') |
| }, |
| setupNetworkOfferingAdditionalFlags (nOffering) { |
| nOffering.havingNetscaler = false |
| nOffering.havingSG = false |
| nOffering.havingEIP = false |
| nOffering.havingELB = false |
| nOffering.selectedBaremetalProviders = [] |
| |
| nOffering.service.forEach(service => { |
| service.provider.forEach(provider => { |
| if (provider.name === 'Netscaler') { |
| nOffering.havingNetscaler = true |
| } else if (this.baremetalProviders.includes(provider.name)) { |
| this.selectedBaremetalProviders.push(this.name) |
| nOffering.selectedBaremetalProviders = this.selectedBaremetalProviders |
| } |
| }) |
| |
| if (service.name === 'SecurityGroup') { |
| nOffering.havingSG = true |
| } else if (service.name === 'StaticNat') { |
| service.capability.forEach(capability => { |
| if (capability.name === 'ElasticIp' && capability.value === 'true') { |
| nOffering.havingEIP = true |
| } |
| }) |
| } else if (service.name === 'Lb') { |
| service.capability.forEach(capability => { |
| if (capability.name === 'ElasticLb' && capability.value === 'true') { |
| nOffering.havingELB = true |
| } |
| }) |
| } |
| }) |
| }, |
| getAvailableNetworkOfferings (hypervisor) { |
| if (this.networkOfferings) { |
| return Object.values(this.networkOfferings).filter(nOffering => { |
| if ((hypervisor === 'VMware' || |
| (this.isAdvancedZone && this.securityGroupsEnabled)) && |
| (nOffering.havingEIP && nOffering.havingELB)) { |
| return false |
| } |
| |
| if (this.isAdvancedZone && this.securityGroupsEnabled && !nOffering.havingSG) { |
| return false |
| } |
| |
| return true |
| }) |
| } |
| return null |
| }, |
| async checkIpFormat (rule, value) { |
| if (!value || value === '') { |
| return Promise.resolve() |
| } else if (rule.ipV4 && !this.ipV4Regex.test(value)) { |
| return Promise.reject(rule.message) |
| } else if (rule.ipV6 && !this.ipV6Regex.test(value)) { |
| return Promise.reject(rule.message) |
| } else { |
| return Promise.resolve() |
| } |
| } |
| } |
| } |
| </script> |
| <style scoped lang="less"> |
| .form-content { |
| border: 1px dashed #e9e9e9; |
| border-radius: 6px; |
| background-color: #fafafa; |
| min-height: 200px; |
| text-align: center; |
| vertical-align: center; |
| padding: 8px; |
| padding-top: 16px; |
| margin-top: 8px; |
| max-height: 40vh; |
| overflow-y: auto; |
| |
| :deep(.has-error) { |
| .ant-form-explain { |
| text-align: left; |
| } |
| } |
| |
| :deep(.ant-form-item-control) { |
| text-align: left; |
| } |
| } |
| </style> |