| // 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 class="form-layout" v-ctrl-enter="handleSubmit"> |
| <a-spin :spinning="loading"> |
| <a-alert |
| v-if="resource" |
| type="info" |
| style="margin-bottom: 16px"> |
| <template #message> |
| <div style="display: block; width: 100%;"> |
| <div style="display: block; margin-bottom: 8px;"> |
| <strong>{{ $t('message.clone.offering.from') }}: {{ resource.name }}</strong> |
| </div> |
| <div style="display: block; font-size: 12px;"> |
| {{ $t('message.clone.offering.edit.hint') }} |
| </div> |
| </div> |
| </template> |
| </a-alert> |
| <a-form |
| :ref="formRef" |
| :model="form" |
| :rules="rules" |
| @finish="handleSubmit" |
| layout="vertical" |
| > |
| <a-form-item name="name" ref="name"> |
| <template #label> |
| <tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/> |
| </template> |
| <a-input |
| v-focus="true" |
| v-model:value="form.name" |
| :placeholder="apiParams.name.description"/> |
| </a-form-item> |
| <a-form-item name="displaytext" ref="displaytext"> |
| <template #label> |
| <tooltip-label :title="$t('label.displaytext')" :tooltip="apiParams.displaytext.description"/> |
| </template> |
| <a-input |
| v-model:value="form.displaytext" |
| :placeholder="apiParams.displaytext.description"/> |
| </a-form-item> |
| <a-form-item name="internetprotocol" ref="internetprotocol"> |
| <template #label> |
| <tooltip-label :title="$t('label.internetprotocol')" :tooltip="apiParams.internetprotocol.description"/> |
| </template> |
| <span v-if="!ipv6NetworkOfferingEnabled || internetProtocolValue!=='ipv4'"> |
| <a-alert type="warning"> |
| <template #message> |
| <span v-html="ipv6NetworkOfferingEnabled ? $t('message.offering.internet.protocol.warning') : $t('message.offering.ipv6.warning')" /> |
| </template> |
| </a-alert> |
| <br/> |
| </span> |
| <a-radio-group |
| v-model:value="form.internetprotocol" |
| :disabled="!ipv6NetworkOfferingEnabled" |
| buttonStyle="solid" |
| @change="e => { internetProtocolValue = e.target.value }" > |
| <a-radio-button value="ipv4"> |
| {{ $t('label.ip.v4') }} |
| </a-radio-button> |
| <a-radio-button value="dualstack"> |
| {{ $t('label.ip.v4.v6') }} |
| </a-radio-button> |
| </a-radio-group> |
| </a-form-item> |
| <a-row :gutter="12"> |
| <a-col :md="12" :lg="12"> |
| <a-form-item name="provider" ref="provider"> |
| <template #label> |
| <tooltip-label :title="$t('label.provider')" :tooltip="apiParams.provider.description"/> |
| </template> |
| <a-select |
| v-model:value="form.provider" |
| @change="val => handleProviderChange(val)" |
| showSearch |
| disabled |
| optionFilterProp="label" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" |
| :placeholder="apiParams.provider.description" > |
| <a-select-option key="" value="">{{ $t('label.none') }}</a-select-option> |
| <a-select-option :value="'NSX'" :label="$t('label.nsx')"> {{ $t('label.nsx') }} </a-select-option> |
| <a-select-option :value="'Netris'" :label="$t('label.netris')"> {{ $t('label.netris') }} </a-select-option> |
| </a-select> |
| </a-form-item> |
| </a-col> |
| <a-col :md="12" :lg="12" v-if="form.provider === 'NSX'"> |
| <a-form-item name="nsxsupportlb" ref="nsxsupportlb"> |
| <template #label> |
| <tooltip-label :title="$t('label.nsx.supports.lb')" :tooltip="apiParams.nsxsupportlb.description"/> |
| </template> |
| <a-switch v-model:checked="form.nsxsupportlb" @change="val => { handleNsxLbService(val) }" /> |
| </a-form-item> |
| </a-col> |
| </a-row> |
| <a-row :gutter="12" v-if="routingMode === 'dynamic' && form.provider === 'NSX'"> |
| <a-col :md="12" :lg="12"> |
| <a-form-item name="specifyasnumber" ref="specifyasnumber"> |
| <template #label> |
| <tooltip-label :title="$t('label.specifyasnumber')"/> |
| </template> |
| <a-switch v-model:checked="form.specifyasnumber" /> |
| </a-form-item> |
| </a-col> |
| </a-row> |
| <a-form-item name="networkmode" ref="networkmode"> |
| <template #label> |
| <tooltip-label :title="$t('label.networkmode')" :tooltip="apiParams.networkmode.description"/> |
| </template> |
| <a-select |
| optionFilterProp="label" |
| v-model:value="form.networkmode" |
| :disabled="provider === 'NSX' || provider === 'Netris'" |
| @change="val => { handleForNetworkModeChange(val) }" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" |
| :placeholder="apiParams.networkmode.description"> |
| <a-select-option v-for="(opt) in networkmodes" :key="opt.name" :label="opt.name"> |
| {{ opt.name }} |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <a-form-item name="routingmode" ref="routingmode" v-if="networkmode === 'ROUTED' || internetProtocolValue === 'ipv6' || internetProtocolValue === 'dualstack'"> |
| <template #label> |
| <tooltip-label :title="$t('label.routingmode')" :tooltip="apiParams.routingmode.description"/> |
| </template> |
| <a-radio-group |
| v-model:value="form.routingmode" |
| buttonStyle="solid" |
| @change="selected => { routingMode = selected.target.value }"> |
| <a-radio-button value="static"> |
| {{ $t('label.static') }} |
| </a-radio-button> |
| <a-radio-button value="dynamic"> |
| {{ $t('label.dynamic') }} |
| </a-radio-button> |
| </a-radio-group> |
| </a-form-item> |
| <a-form-item> |
| <template #label> |
| <tooltip-label :title="$t('label.supportedservices')" :tooltip="apiParams.supportedservices ? apiParams.supportedservices.description : ''"/> |
| </template> |
| <div class="supported-services-container" scroll-to="last-child"> |
| <a-spin v-if="!servicesReady" :spinning="true" /> |
| <a-list v-else itemLayout="horizontal" :dataSource="supportedServices"> |
| <template #renderItem="{ item }"> |
| <a-list-item> |
| <CheckBoxSelectPair |
| :key="`${item.name}-${item.selectedProvider || 'none'}`" |
| :resourceKey="item.name" |
| :checkBoxLabel="item.description" |
| :forExternalNetProvider="form.provider === 'NSX' || form.provider === 'Netris'" |
| :defaultCheckBoxValue="item.defaultChecked" |
| :defaultSelectValue="item.selectedProvider" |
| :selectOptions="item.provider" |
| @handle-checkselectpair-change="handleSupportedServiceChange"/> |
| </a-list-item> |
| </template> |
| </a-list> |
| </div> |
| </a-form-item> |
| <a-form-item name="regionlevelvpc" ref="regionlevelvpc" :label="$t('label.service.connectivity.regionlevelvpccapabilitycheckbox')" v-if="connectivityServiceChecked"> |
| <a-switch v-model:checked="form.regionlevelvpc" /> |
| </a-form-item> |
| <a-form-item name="distributedrouter" ref="distributedrouter" :label="$t('label.service.connectivity.distributedroutercapabilitycheckbox')" v-if="connectivityServiceChecked"> |
| <a-switch v-model:checked="form.distributedrouter" /> |
| </a-form-item> |
| <a-form-item name="redundantrouter" ref="redundantrouter" :label="$t('label.redundantrouter')" v-if="sourceNatServiceChecked"> |
| <a-switch v-model:checked="form.redundantrouter" /> |
| </a-form-item> |
| <a-form-item name="serviceofferingid" ref="serviceofferingid"> |
| <a-alert v-if="!isVpcVirtualRouterForAtLeastOneService" type="warning" style="margin-bottom: 10px"> |
| <template #message> |
| <span v-html="$t('message.vr.alert.upon.network.offering.creation.others')" /> |
| </template> |
| </a-alert> |
| <template #label> |
| <tooltip-label :title="$t('label.serviceofferingid')" :tooltip="apiParams.serviceofferingid.description"/> |
| </template> |
| <a-select |
| showSearch |
| optionFilterProp="label" |
| v-model:value="form.serviceofferingid" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" |
| :loading="serviceOfferingLoading" |
| :placeholder="apiParams.serviceofferingid.description"> |
| <a-select-option v-for="(opt) in serviceOfferings" :key="opt.id" :label="opt.name || opt.description"> |
| {{ opt.name || opt.description }} |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <a-form-item name="ispublic" ref="ispublic" :label="$t('label.ispublic')" v-if="isAdmin()"> |
| <a-switch v-model:checked="form.ispublic" @change="val => { isPublic = val }" /> |
| </a-form-item> |
| <a-form-item name="domainid" ref="domainid" v-if="!isPublic"> |
| <template #label> |
| <tooltip-label :title="$t('label.domainid')" :tooltip="apiParams.domainid.description"/> |
| </template> |
| <a-select |
| mode="multiple" |
| v-model:value="form.domainid" |
| showSearch |
| optionFilterProp="label" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" |
| :loading="domainLoading" |
| :placeholder="apiParams.domainid.description"> |
| <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex" :label="opt.path || opt.name || opt.description"> |
| <span> |
| <resource-icon v-if="opt && opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/> |
| <block-outlined v-else style="margin-right: 5px" /> |
| {{ opt.path || opt.name || opt.description }} |
| </span> |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <a-form-item name="zoneid" ref="zoneid"> |
| <template #label> |
| <tooltip-label :title="$t('label.zoneid')" :tooltip="apiParams.zoneid.description"/> |
| </template> |
| <a-select |
| id="zone-selection" |
| mode="multiple" |
| v-model:value="form.zoneid" |
| showSearch |
| optionFilterProp="label" |
| :filterOption="(input, option) => { |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| }" |
| :loading="zoneLoading" |
| :placeholder="apiParams.zoneid.description"> |
| <a-select-option v-for="(opt, optIndex) in zones" :key="optIndex" :label="opt.name || opt.description"> |
| <span> |
| <resource-icon v-if="opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/> |
| <global-outlined v-else style="margin-right: 5px"/> |
| {{ opt.name || opt.description }} |
| </span> |
| </a-select-option> |
| </a-select> |
| </a-form-item> |
| <a-form-item name="enable" ref="enable" v-if="apiParams.enable"> |
| <template #label> |
| <tooltip-label :title="$t('label.enable.vpc.offering')" :tooltip="apiParams.enable.description"/> |
| </template> |
| <a-switch v-model:checked="form.enable" /> |
| </a-form-item> |
| </a-form> |
| <div :span="24" class="action-button"> |
| <a-button @click="closeAction">{{ $t('label.cancel') }}</a-button> |
| <a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button> |
| </div> |
| </a-spin> |
| </div> |
| </template> |
| |
| <script> |
| import { ref, reactive, toRaw } from 'vue' |
| import { getAPI, postAPI } from '@/api' |
| import { isAdmin } from '@/role' |
| import { mixinForm } from '@/utils/mixin' |
| import CheckBoxSelectPair from '@/components/CheckBoxSelectPair' |
| import ResourceIcon from '@/components/view/ResourceIcon' |
| import TooltipLabel from '@/components/widgets/TooltipLabel' |
| import { BlockOutlined, GlobalOutlined } from '@ant-design/icons-vue' |
| import { buildVpcServiceCapabilityParams } from '@/composables/useServiceCapabilityParams' |
| |
| export default { |
| name: 'CloneVpcOffering', |
| mixins: [mixinForm], |
| components: { |
| CheckBoxSelectPair, |
| ResourceIcon, |
| TooltipLabel, |
| BlockOutlined, |
| GlobalOutlined |
| }, |
| props: { |
| resource: { |
| type: Object, |
| required: true |
| } |
| }, |
| data () { |
| return { |
| selectedDomains: [], |
| selectedZones: [], |
| isConserveMode: true, |
| internetProtocolValue: 'ipv4', |
| domains: [], |
| domainLoading: false, |
| zones: [], |
| zoneLoading: false, |
| forNsx: false, |
| provider: '', |
| loading: false, |
| supportedServices: [], |
| supportedServiceLoading: false, |
| servicesReady: false, |
| serviceOfferings: [], |
| serviceOfferingLoading: false, |
| isVpcVirtualRouterForAtLeastOneService: false, |
| connectivityServiceChecked: false, |
| sourceNatServiceChecked: false, |
| selectedServiceProviderMap: {}, |
| serviceProviderMap: {}, |
| ipv6NetworkOfferingEnabled: false, |
| routedNetworkEnabled: false, |
| routingMode: 'static', |
| networkmode: '', |
| networkmodes: [ |
| { |
| id: 0, |
| name: 'NATTED' |
| }, |
| { |
| id: 1, |
| name: 'ROUTED' |
| } |
| ], |
| isPublic: true, |
| VPCVR: { |
| name: 'VpcVirtualRouter', |
| description: 'VpcVirtualRouter', |
| enabled: true |
| }, |
| NSX: { |
| name: 'Nsx', |
| description: 'Nsx', |
| enabled: true |
| }, |
| Netris: { |
| name: 'Netris', |
| description: 'Netris', |
| enabled: true |
| } |
| } |
| }, |
| beforeCreate () { |
| this.apiParams = this.$getApiParams('cloneVPCOffering') |
| }, |
| created () { |
| this.zones = [ |
| { |
| id: null, |
| name: this.$t('label.all.zone') |
| } |
| ] |
| this.isPublic = isAdmin() |
| this.initForm() |
| this.fetchData() |
| }, |
| methods: { |
| initForm () { |
| this.formRef = ref() |
| this.form = reactive({ |
| regionlevelvpc: true, |
| distributedrouter: true, |
| ispublic: this.isPublic, |
| internetprotocol: this.internetProtocolValue, |
| nsxsupportlb: true, |
| routingmode: 'static', |
| domainid: [], |
| zoneid: [] |
| }) |
| this.rules = reactive({ |
| name: [{ required: true, message: this.$t('message.error.name') }], |
| domainid: [{ type: 'array', required: true, message: this.$t('message.error.select') }], |
| zoneid: [{ |
| type: 'array', |
| validator: async (rule, value) => { |
| if (value && value.length > 1 && value.indexOf(0) !== -1) { |
| return Promise.reject(this.$t('message.error.zone.combined')) |
| } |
| return Promise.resolve() |
| } |
| }] |
| }) |
| }, |
| fetchData () { |
| this.fetchDomainData() |
| this.fetchZoneData() |
| this.fetchIpv6NetworkOfferingConfiguration() |
| this.fetchRoutedNetworkConfiguration() |
| this.fetchSupportedServiceData() |
| }, |
| isAdmin () { |
| return isAdmin() |
| }, |
| fetchIpv6NetworkOfferingConfiguration () { |
| this.ipv6NetworkOfferingEnabled = false |
| const params = { name: 'ipv6.offering.enabled' } |
| getAPI('listConfigurations', params).then(json => { |
| const value = json?.listconfigurationsresponse?.configuration?.[0].value || null |
| this.ipv6NetworkOfferingEnabled = value === 'true' |
| }) |
| }, |
| fetchRoutedNetworkConfiguration () { |
| this.routedNetworkEnabled = false |
| const params = { name: 'routed.network.vpc.enabled' } |
| getAPI('listConfigurations', params).then(json => { |
| const value = json?.listconfigurationsresponse?.configuration?.[0].value || null |
| this.routedNetworkEnabled = value === 'true' |
| if (!this.routedNetworkEnabled) { |
| this.networkmodes.pop() |
| } |
| }) |
| }, |
| fetchDomainData () { |
| const params = {} |
| params.listAll = true |
| params.showicon = true |
| params.details = 'min' |
| this.domainLoading = true |
| getAPI('listDomains', params).then(json => { |
| const listDomains = json.listdomainsresponse.domain |
| this.domains = this.domains.concat(listDomains) |
| }).finally(() => { |
| this.domainLoading = false |
| }) |
| }, |
| fetchZoneData () { |
| const params = {} |
| params.showicon = true |
| this.zoneLoading = true |
| getAPI('listZones', params).then(json => { |
| const listZones = json.listzonesresponse.zone |
| if (listZones) { |
| this.zones = this.zones.concat(listZones) |
| } |
| }).finally(() => { |
| this.zoneLoading = false |
| }) |
| }, |
| fetchSupportedServiceData () { |
| this.supportedServiceLoading = true |
| getAPI('listSupportedNetworkServices', {}).then(json => { |
| const networkServices = json.listsupportednetworkservicesresponse.networkservice || [] |
| |
| let services = [] |
| if (this.provider === 'NSX') { |
| services = this.buildNsxServices(networkServices) |
| } else if (this.provider === 'Netris') { |
| services = this.buildNetrisServices(networkServices) |
| } else { |
| services = this.buildDefaultServices(networkServices) |
| } |
| |
| if (this.networkmode === 'ROUTED') { |
| services = services.filter(service => { |
| return !['SourceNat', 'StaticNat', 'Lb', 'PortForwarding', 'Vpn'].includes(service.name) |
| }) |
| if (['NSX', 'Netris'].includes(this.provider)) { |
| services.push({ |
| name: 'Gateway', |
| description: 'Gateway', |
| enabled: true, |
| provider: [{ name: this.provider }] |
| }) |
| } |
| } |
| |
| for (const i in services) { |
| services[i].description = services[i].name |
| } |
| |
| this.supportedServices = services |
| this.supportedServiceLoading = false |
| |
| this.$nextTick(() => { |
| this.populateFormFromResource() |
| }) |
| }) |
| }, |
| buildNsxServices (networkServices) { |
| return [ |
| { name: 'Dhcp', enabled: true, provider: [{ name: 'VpcVirtualRouter' }] }, |
| { name: 'Dns', enabled: true, provider: [{ name: 'VpcVirtualRouter' }] }, |
| { name: 'Lb', enabled: true, provider: [{ name: 'Nsx' }] }, |
| { name: 'StaticNat', enabled: true, provider: [{ name: 'Nsx' }] }, |
| { name: 'SourceNat', enabled: true, provider: [{ name: 'Nsx' }] }, |
| { name: 'NetworkACL', enabled: true, provider: [{ name: 'Nsx' }] }, |
| { name: 'PortForwarding', enabled: true, provider: [{ name: 'Nsx' }] }, |
| { name: 'UserData', enabled: true, provider: [{ name: 'VpcVirtualRouter' }] } |
| ] |
| }, |
| buildNetrisServices (networkServices) { |
| return [ |
| { name: 'Dhcp', enabled: true, provider: [{ name: 'VpcVirtualRouter' }] }, |
| { name: 'Dns', enabled: true, provider: [{ name: 'VpcVirtualRouter' }] }, |
| { name: 'Lb', enabled: true, provider: [{ name: 'Netris' }] }, |
| { name: 'StaticNat', enabled: true, provider: [{ name: 'Netris' }] }, |
| { name: 'SourceNat', enabled: true, provider: [{ name: 'Netris' }] }, |
| { name: 'NetworkACL', enabled: true, provider: [{ name: 'Netris' }] }, |
| { name: 'PortForwarding', enabled: true, provider: [{ name: 'Netris' }] }, |
| { name: 'UserData', enabled: true, provider: [{ name: 'VpcVirtualRouter' }] } |
| ] |
| }, |
| buildDefaultServices (networkServices) { |
| return [ |
| { name: 'Dhcp', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] }, |
| { name: 'Dns', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] }, |
| { name: 'Lb', provider: [{ name: 'VpcVirtualRouter' }, { name: 'InternalLbVm' }] }, |
| { name: 'Gateway', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] }, |
| { name: 'StaticNat', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] }, |
| { name: 'SourceNat', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] }, |
| { name: 'NetworkACL', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] }, |
| { name: 'PortForwarding', provider: [{ name: 'VpcVirtualRouter' }] }, |
| { name: 'UserData', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] }, |
| { name: 'Vpn', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] }, |
| { name: 'Connectivity', provider: [{ name: 'BigSwitchBcf' }, { name: 'NiciraNvp' }, { name: 'Ovs' }, { name: 'JuniperContrailVpcRouter' }] } |
| ] |
| }, |
| populateFormFromResource () { |
| if (!this.resource) return |
| |
| const r = this.resource |
| this.form.name = r.name + ' - Clone' |
| this.form.displaytext = r.displaytext || r.name |
| |
| if (r.internetprotocol) { |
| this.form.internetprotocol = r.internetprotocol.toLowerCase() |
| this.internetProtocolValue = r.internetprotocol.toLowerCase() |
| } |
| |
| if (r.service && Array.isArray(r.service)) { |
| const networkAclService = r.service.find(svc => svc.name === 'NetworkACL') |
| if (networkAclService && networkAclService.provider && networkAclService.provider.length > 0) { |
| const providerName = networkAclService.provider[0].name |
| if (providerName === 'Nsx') { |
| this.provider = 'NSX' |
| this.form.provider = 'NSX' |
| } else if (providerName === 'Netris') { |
| this.provider = 'Netris' |
| this.form.provider = 'Netris' |
| } |
| } |
| } |
| |
| if (r.networkmode) { |
| this.networkmode = r.networkmode |
| this.form.networkmode = r.networkmode |
| } |
| |
| if (r.routingmode) { |
| this.routingMode = r.routingmode |
| this.form.routingmode = r.routingmode |
| } |
| |
| if (r.serviceofferingid) { |
| this.form.serviceofferingid = r.serviceofferingid |
| } |
| |
| if (r.service && Array.isArray(r.service)) { |
| const sourceServiceMap = {} |
| r.service.forEach(svc => { |
| if (svc.provider && svc.provider.length > 0) { |
| const providerName = svc.provider[0].name |
| sourceServiceMap[svc.name] = providerName |
| } |
| }) |
| |
| this.serviceProviderMap = sourceServiceMap |
| |
| const updatedServices = this.supportedServices.map(svc => { |
| const serviceCopy = { ...svc, provider: [...svc.provider] } |
| |
| if (sourceServiceMap[serviceCopy.name]) { |
| const providerName = sourceServiceMap[serviceCopy.name] |
| const providerIndex = serviceCopy.provider.findIndex(p => p.name === providerName) |
| |
| if (providerIndex > 0) { |
| const targetProvider = serviceCopy.provider[providerIndex] |
| serviceCopy.provider.splice(providerIndex, 1) |
| serviceCopy.provider.unshift(targetProvider) |
| } |
| |
| serviceCopy.defaultChecked = true |
| serviceCopy.selectedProvider = providerName |
| this.selectedServiceProviderMap[serviceCopy.name] = providerName |
| } else { |
| serviceCopy.defaultChecked = false |
| serviceCopy.selectedProvider = null |
| } |
| return serviceCopy |
| }) |
| |
| this.supportedServices = updatedServices |
| |
| this.connectivityServiceChecked = Boolean(this.selectedServiceProviderMap.Connectivity) |
| this.sourceNatServiceChecked = Boolean(this.selectedServiceProviderMap.SourceNat) |
| |
| this.$nextTick(() => { |
| this.servicesReady = true |
| this.$nextTick(() => { |
| this.checkVpcVirtualRouterForServices() |
| }) |
| }) |
| } |
| |
| if (r.service && Array.isArray(r.service)) { |
| const connectivityService = r.service.find(svc => svc.name === 'Connectivity') |
| if (connectivityService && connectivityService.capability) { |
| const regionLevelCapability = connectivityService.capability.find(cap => cap.name === 'RegionLevelVpc') |
| if (regionLevelCapability) { |
| this.form.regionlevelvpc = regionLevelCapability.value === 'true' |
| } |
| const distributedRouterCapability = connectivityService.capability.find(cap => cap.name === 'DistributedRouter') |
| if (distributedRouterCapability) { |
| this.form.distributedrouter = distributedRouterCapability.value === 'true' |
| } |
| } |
| |
| const sourceNatService = r.service.find(svc => svc.name === 'SourceNat') |
| if (sourceNatService && sourceNatService.capability) { |
| const redundantRouterCapability = sourceNatService.capability.find(cap => cap.name === 'RedundantRouter') |
| if (redundantRouterCapability) { |
| this.form.redundantrouter = redundantRouterCapability.value === 'true' |
| } |
| } |
| |
| const gatewayService = r.service.find(svc => svc.name === 'Gateway') |
| if (gatewayService && gatewayService.capability) { |
| const redundantRouterCapability = gatewayService.capability.find(cap => cap.name === 'RedundantRouter') |
| if (redundantRouterCapability) { |
| this.form.redundantrouter = redundantRouterCapability.value === 'true' |
| } |
| } |
| } |
| |
| if (this.provider === 'NSX') { |
| this.form.nsxsupportlb = Boolean(this.serviceProviderMap.Lb) |
| } |
| }, |
| async handleProviderChange (value) { |
| this.provider = value |
| if (this.provider === 'NSX') { |
| this.form.nsxsupportlb = true |
| this.handleNsxLbService(true) |
| } |
| this.fetchSupportedServiceData() |
| }, |
| handleNsxLbService (supportLb) { |
| if (!supportLb) { |
| this.supportedServices = this.supportedServices.filter(svc => svc.name !== 'Lb') |
| delete this.selectedServiceProviderMap.Lb |
| } else { |
| const lbExists = this.supportedServices.some(svc => svc.name === 'Lb') |
| if (!lbExists) { |
| this.supportedServices.push({ |
| name: 'Lb', |
| description: 'Lb', |
| enabled: true, |
| provider: [{ name: 'Nsx' }] |
| }) |
| } |
| } |
| }, |
| handleSupportedServiceChange (service, checked, provider) { |
| if (checked) { |
| const correctProvider = this.serviceProviderMap[service] |
| if (correctProvider && provider !== correctProvider) { |
| this.selectedServiceProviderMap[service] = correctProvider |
| } else { |
| this.selectedServiceProviderMap[service] = provider |
| } |
| } else { |
| delete this.selectedServiceProviderMap[service] |
| } |
| |
| if (service === 'Connectivity') { |
| this.connectivityServiceChecked = checked |
| } |
| if (service === 'SourceNat') { |
| this.sourceNatServiceChecked = checked |
| } |
| |
| this.checkVpcVirtualRouterForServices() |
| }, |
| checkVpcVirtualRouterForServices () { |
| this.isVpcVirtualRouterForAtLeastOneService = false |
| const providers = Object.values(this.selectedServiceProviderMap) |
| for (const provider of providers) { |
| if (provider === 'VpcVirtualRouter') { |
| this.isVpcVirtualRouterForAtLeastOneService = true |
| break |
| } |
| } |
| if (this.isVpcVirtualRouterForAtLeastOneService && this.serviceOfferings.length === 0) { |
| this.fetchServiceOfferingData() |
| } |
| }, |
| handleForNetworkModeChange (networkMode) { |
| this.networkmode = networkMode |
| this.fetchSupportedServiceData() |
| }, |
| fetchServiceOfferingData () { |
| const params = {} |
| params.issystem = true |
| params.systemvmtype = 'domainrouter' |
| this.serviceOfferingLoading = true |
| getAPI('listServiceOfferings', params).then(json => { |
| const listServiceOfferings = json.listserviceofferingsresponse.serviceoffering |
| this.serviceOfferings = this.serviceOfferings.concat(listServiceOfferings) |
| }).finally(() => { |
| this.serviceOfferingLoading = false |
| }) |
| }, |
| handleSubmit (e) { |
| if (e) { |
| e.preventDefault() |
| } |
| if (this.loading) return |
| this.formRef.value.validate().then(() => { |
| const formRaw = toRaw(this.form) |
| const values = this.handleRemoveFields(formRaw) |
| const params = { |
| sourceofferingid: this.resource.id, |
| name: values.name |
| } |
| if (values.displaytext) { |
| params.displaytext = values.displaytext |
| } |
| |
| if (values.ispublic !== true) { |
| const domainIndexes = values.domainid |
| let domainId = null |
| if (domainIndexes && domainIndexes.length > 0) { |
| const domainIds = [] |
| for (let i = 0; i < domainIndexes.length; i++) { |
| domainIds.push(this.domains[domainIndexes[i]].id) |
| } |
| domainId = domainIds.join(',') |
| } |
| if (domainId) { |
| params.domainid = domainId |
| } |
| } |
| |
| const zoneIndexes = values.zoneid |
| let zoneId = null |
| if (zoneIndexes && zoneIndexes.length > 0) { |
| const zoneIds = [] |
| for (let j = 0; j < zoneIndexes.length; j++) { |
| zoneIds.push(this.zones[zoneIndexes[j]].id) |
| } |
| zoneId = zoneIds.join(',') |
| } |
| if (zoneId) { |
| params.zoneid = zoneId |
| } |
| |
| if (values.internetprotocol) { |
| params.internetprotocol = values.internetprotocol |
| } |
| |
| const forNsx = values.provider === 'NSX' |
| if (forNsx) { |
| params.provider = 'NSX' |
| params.nsxsupportlb = values.nsxsupportlb |
| } |
| const forNetris = values.provider === 'Netris' |
| if (forNetris) { |
| params.provider = 'Netris' |
| } |
| |
| if (values.networkmode) { |
| params.networkmode = values.networkmode |
| } |
| |
| if (values.specifyasnumber !== undefined) { |
| params.specifyasnumber = values.specifyasnumber |
| } |
| |
| if (values.routingmode) { |
| params.routingmode = values.routingmode |
| } |
| |
| if (this.selectedServiceProviderMap != null) { |
| const supportedServices = Object.keys(this.selectedServiceProviderMap) |
| if (!forNsx && !forNetris) { |
| params.supportedservices = supportedServices.join(',') |
| } |
| for (const k in supportedServices) { |
| params['serviceProviderList[' + k + '].service'] = supportedServices[k] |
| params['serviceProviderList[' + k + '].provider'] = this.selectedServiceProviderMap[supportedServices[k]] |
| } |
| buildVpcServiceCapabilityParams(params, values, this.selectedServiceProviderMap, this.isVpcVirtualRouterForAtLeastOneService) |
| } else { |
| params.supportedservices = '' |
| } |
| |
| if (values.enable !== undefined) { |
| params.enable = values.enable |
| } |
| |
| this.loading = true |
| postAPI('cloneVPCOffering', params).then(json => { |
| this.$message.success(`${this.$t('message.success.clone.vpc.offering')} ${values.name}`) |
| this.$emit('refresh-data') |
| this.closeAction() |
| }).catch(error => { |
| this.$notifyError(error) |
| }).finally(() => { |
| this.loading = false |
| }) |
| }).catch(error => { |
| this.formRef.value.scrollToField(error.errorFields[0].name) |
| }) |
| }, |
| closeAction () { |
| this.$emit('close-action') |
| } |
| } |
| } |
| </script> |
| |
| <style scoped lang="scss"> |
| .form-layout { |
| width: 80vw; |
| |
| @media (min-width: 800px) { |
| width: 500px; |
| } |
| } |
| |
| .supported-services-container { |
| height: 250px; |
| overflow: auto; |
| } |
| </style> |