vpc: consolidated tabs for configuration and management (#143)

Adds VPC consolidated component that has tabs for may related items.

Co-authored-by: Rohit Yadav <rohit@apache.org>
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Ritchie Vincent 2020-02-05 11:04:07 +00:00 committed by Rohit Yadav
parent 3cd1884ef0
commit f4626bb4d8
6 changed files with 980 additions and 144 deletions

View File

@ -27,7 +27,14 @@
class="spin-content"
:bordered="true"
style="width:100%">
<component
v-if="tabs.length === 1"
:is="tabs[0].component"
:resource="resource"
:loading="loading"
:tab="tabs[0].name" />
<a-tabs
v-else
style="width: 100%"
:animated="false"
:defaultActiveKey="tabs[0].name"

View File

@ -119,43 +119,13 @@ export default {
columns: ['name', 'state', 'displaytext', 'cidr', 'account', 'zonename'],
details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 'domain'],
related: [{
name: 'privategw',
title: 'Private Gateways',
param: 'vpcid'
}, {
name: 'publicip',
title: 'Public IP Addresses',
param: 'vpcid'
}, {
name: 's2svpn',
title: 'Site-to-Site VPN Gateways',
param: 'vpcid'
}, {
name: 's2svpnconn',
title: 'Site-to-Site VPN Connections',
param: 'vpcid'
}, {
name: 'acllist',
title: 'Network ACL Lists',
param: 'vpcid'
}, {
name: 'guestnetwork',
title: 'Networks',
param: 'vpcid'
}, {
name: 'vm',
title: 'Instances',
param: 'vpcid'
}],
tabs: [{
name: 'details',
component: () => import('@/components/view/DetailsTab.vue')
}, {
name: 'Router',
component: () => import('@/views/network/VpcRouterTab.vue')
}, {
name: 'Network',
component: () => import('@/views/network/VpcTiersTab.vue')
name: 'VPC',
component: () => import('@/views/network/VpcTab.vue')
}],
actions: [
{

View File

@ -458,8 +458,10 @@
"label.add.l2.guest.network": "Add L2 Guest Network",
"label.add.ldap.account": "Add LDAP account",
"label.add.ldap.list.users": "List LDAP users",
"label.add.list.name":"ACL List Name",
"label.add.netScaler.device": "Add Netscaler device",
"label.add.network.offering": "Add network offering",
"label.add.new.gateway": "Add new gateway",
"label.add.new.tier": "Add new tier",
"label.add.nfs.secondary.staging.store": "Add NFS Secondary Staging Store",
"label.add.pod": "Add Pod",
@ -635,6 +637,7 @@
"label.revoke.project.invite": "Revoke invitation",
"label.secondary.storage":"Secondary Storage",
"label.secondary.storage.vm":"Secondary storage VM",
"label.service.offering":"Service Offering",
"label.set.default.NIC": "Set default NIC",
"label.shutdown.provider": "Shutdown provider",
"label.snapshot.schedule": "Set up Recurring Snapshot",
@ -708,6 +711,7 @@
"memoryusedgb": "Used",
"memused": "Memory Usage",
"message.edit.account": "Edit (\"-1\" indicates no limit to the amount of resources create)",
"message.add.new.gateway.to.vpc":"Please specify the information to add a new gateway to this VPC.",
"message.assign.instance.another": "Please specify the account type, domain, account name and network (optional) of the new account. <br> If the default nic of the vm is on a shared network, CloudStack will check if the network can be used by the new account if you do not specify one network. <br> If the default nic of the vm is on a isolated network, and the new account has more one isolated networks, you should specify one.",
"message.network.addVM.desc":"Please specify the network that you would like to add this VM to. A new NIC will be added for this network.",
"message.network.removeNIC": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.",

View File

@ -1,98 +0,0 @@
// 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>
<a-spin :spinning="fetchLoading">
<a-tabs :animated="false" tabPosition="left">
<a-tab-pane tab="Private Gateways" key="pgw" v-if="'listPrivateGateways' in $store.getters.apis">
<a-button type="dashed" icon="plus" style="width: 100%">Add Private Gateway</a-button>
</a-tab-pane>
<a-tab-pane tab="Public IP Addresses" key="ip" v-if="'listPublicIpAddresses' in $store.getters.apis">
<a-button type="dashed" icon="plus" style="width: 100%">Acquire New IP</a-button>
</a-tab-pane>
<a-tab-pane tab="S2S VPN Gateway" key="vpngw" v-if="'listVpnGateways' in $store.getters.apis">
<a-button type="dashed" icon="plus" style="width: 100%">Create Site-to-Site VPN Gateway</a-button>
</a-tab-pane>
<a-tab-pane tab="S2S VPN Connection" key="vpnc" v-if="'listVpnConnections' in $store.getters.apis">
<a-button type="dashed" icon="plus" style="width: 100%">Create Site-to-Site VPN Connection</a-button>
</a-tab-pane>
<a-tab-pane tab="Network ACL Lists" key="acl" v-if="'listNetworkACLLists' in $store.getters.apis">
<a-button type="dashed" icon="plus" style="width: 100%">Add Network ACL List</a-button>
</a-tab-pane>
<a-tab-pane tab="Virtual Routers" key="vr" v-if="'listRouters' in $store.getters.apis">
{{ routers }}
</a-tab-pane>
</a-tabs>
</a-spin>
</template>
<script>
import { api } from '@/api'
import Status from '@/components/widgets/Status'
export default {
name: 'VpcRouterTab',
components: {
Status
},
props: {
resource: {
type: Object,
required: true
},
loading: {
type: Boolean,
default: false
}
},
data () {
return {
routers: [],
fetchLoading: false
}
},
mounted () {
this.fetchData()
},
watch: {
loading (newData, oldData) {
if (!newData && this.resource.id) {
this.fetchData()
}
}
},
methods: {
fetchData () {
this.fetchLoading = true
api('listRouters', { vpcid: this.resource.id, listAll: true }).then(json => {
this.routers = json.listroutersresponse.router
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
}
}
}
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,939 @@
// 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>
<a-spin :spinning="fetchLoading">
<a-tabs
:activeKey="currentTab"
:tabPosition="device === 'tablet' || device === 'mobile' ? 'top' : 'left'"
:animated="false"
@change="handleChangeTab">
<a-tab-pane :tab="$t('details')" key="details">
<DetailsTab :resource="resource" :loading="loading" />
</a-tab-pane>
<a-tab-pane :tab="$t('networks')" key="tier">
<VpcTiersTab :resource="resource" :loading="loading" />
</a-tab-pane>
<a-tab-pane tab="Private Gateways" key="pgw" v-if="'listPrivateGateways' in $store.getters.apis">
<a-button
type="dashed"
icon="plus"
style="width: 100%"
@click="() => handleOpenModals('privateGateways')">Add Private Gateway</a-button>
<a-table
class="table"
size="small"
:columns="privateGatewaysColumns"
:dataSource="privateGateways"
:rowKey="item => item.id"
:pagination="false"
>
<template slot="ipaddress" slot-scope="text, item">
<router-link :to="{ path: '/privategw/' + item.id }">{{ text }}</router-link>
</template>
<template slot="state" slot-scope="text, item">
<status :text="item.state" displayText></status>
</template>
</a-table>
<a-pagination
class="row-element pagination"
size="small"
:current="page"
:pageSize="pageSize"
:total="itemCounts.privateGateways"
:showTotal="total => `Total ${total} items`"
:pageSizeOptions="['10', '20', '40', '80', '100']"
@change="changePage"
@showSizeChange="changePageSize"
showSizeChanger/>
<a-modal v-model="modals.gateway" :title="$t('label.add.new.gateway')" @ok="handleGatewayFormSubmit">
<a-spin :spinning="modals.gatewayLoading">
<p>{{ $t('message.add.new.gateway.to.vpc') }}</p>
<a-form @submit.prevent="handleGatewayFormSubmit" :form="gatewayForm">
<a-form-item :label="$t('physicalnetworkid')">
<a-select v-decorator="['physicalnetwork']">
<a-select-option v-for="item in physicalnetworks" :key="item.id" :value="item.id">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item :label="$t('label.vlan')" :required="true">
<a-input
:placeholder="placeholders.vlan"
v-decorator="['vlan', {rules: [{ required: true, message: 'Required' }]}]"
></a-input>
</a-form-item>
<a-form-item :label="$t('publicip')" :required="true">
<a-input
:placeholder="placeholders.ipaddress"
v-decorator="['ipaddress', {rules: [{ required: true, message: 'Required' }]}]"
></a-input>
</a-form-item>
<a-form-item :label="$t('gateway')" :required="true">
<a-input
:placeholder="placeholders.gateway"
v-decorator="['gateway', {rules: [{ required: true, message: 'Required' }]}]"
></a-input>
</a-form-item>
<a-form-item :label="$t('netmask')" :required="true">
<a-input
:placeholder="placeholders.netmask"
v-decorator="['netmask', {rules: [{ required: true, message: 'Required' }]}]"
></a-input>
</a-form-item>
<a-form-item :label="$t('sourceNat')">
<a-checkbox v-decorator="['nat']"></a-checkbox>
</a-form-item>
<a-form-item :label="$t('aclid')">
<a-select v-decorator="['acl']">
<a-select-option v-for="item in networkAcls" :key="item.id" :value="item.id">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</a-tab-pane>
<a-tab-pane tab="Public IP Addresses" key="ip" v-if="'listPublicIpAddresses' in $store.getters.apis">
<a-button type="dashed" icon="plus" style="width: 100%" @click="handleAcquireNewIp">Acquire New IP</a-button>
<a-table
class="table"
size="small"
:columns="publicIpAddressesColumns"
:dataSource="publicIpAddresses"
:rowKey="item => item.id"
:pagination="false"
>
<template slot="ipaddress" slot-scope="text, item">
<router-link :to="{ path: '/publicip/' + item.id }">
{{ text }}
<a-tag v-if="item.issourcenat">source-nat</a-tag>
<a-tag v-if="item.isstaticnat">static-nat</a-tag>
</router-link>
</template>
<template slot="state" slot-scope="text, item">
<status :text="item.state" displayText></status>
</template>
<template slot="vm" slot-scope="text, item">
<router-link :to="{ path: '/vm/' + item.virtualmachineid }">
{{ item.virtualmachinedisplayname || item.virtualmachinename }}
</router-link>
</template>
<template slot="network" slot-scope="text, item">
<router-link :to="{ path: '/guestnetwork/' + item.associatednetworkid }">
{{ item.associatednetworkname }}
</router-link>
</template>
</a-table>
<a-pagination
class="row-element pagination"
size="small"
:current="page"
:pageSize="pageSize"
:total="itemCounts.publicIpAddresses"
:showTotal="total => `Total ${total} items`"
:pageSizeOptions="['10', '20', '40', '80', '100']"
@change="changePage"
@showSizeChange="changePageSize"
showSizeChanger/>
</a-tab-pane>
<a-tab-pane tab="VPN Gateway" key="vpngw" v-if="'listVpnGateways' in $store.getters.apis">
<a-button
v-if="vpnGateways.length === 0"
type="dashed"
icon="plus"
style="width: 100%"
@click="handleCreateVpnGateway">
Create Site-to-Site VPN Gateway
</a-button>
<a-list class="list">
<a-list-item v-for="item in vpnGateways" :key="item.id">
<div class="list__item">
<div class="list__col">
<div class="list__label">{{ $t('ip') }}</div>
<div>
<router-link :to="{ path: '/s2svpn/' + item.id }">
{{ item.publicip }}
</router-link>
</div>
</div>
</div>
</a-list-item>
</a-list>
</a-tab-pane>
<a-tab-pane tab="VPN Connections" key="vpnc" v-if="'listVpnConnections' in $store.getters.apis">
<a-button
type="dashed"
icon="plus"
style="width: 100%"
@click="handleOpenModals('vpnConnection')">
Create Site-to-Site VPN Connection
</a-button>
<a-table
class="table"
size="small"
:columns="vpnConnectionsColumns"
:dataSource="vpnConnections"
:pagination="false"
:rowKey="record => record.id">
<a slot="publicip" slot-scope="text, record" href="javascript:;">
<router-link :to="{ path: '/s2svpnconn/' + record.id }">
{{ text }}
</router-link>
</a>
<template slot="state" slot-scope="text">
<status :text="text ? text : ''" displayText />
</template>
</a-table>
<a-pagination
class="row-element pagination"
size="small"
:current="page"
:pageSize="pageSize"
:total="itemCounts.vpnConnections"
:showTotal="total => `Total ${total} items`"
:pageSizeOptions="['10', '20', '40', '80', '100']"
@change="changePage"
@showSizeChange="changePageSize"
showSizeChanger/>
<a-modal v-model="modals.vpnConnection" :title="$t('label.create.VPN.connection')" @ok="handleVpnConnectionFormSubmit">
<a-spin :spinning="modals.vpnConnectionLoading">
<a-form @submit.prevent="handleVpnConnectionFormSubmit" :form="vpnConnectionForm">
<a-form-item :label="$t('vpncustomergatewayid')">
<a-select v-decorator="['vpncustomergateway']">
<a-select-option v-for="item in vpncustomergateways" :key="item.id" :value="item.id">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item :label="$t('passive')">
<a-checkbox v-decorator="['passive']"></a-checkbox>
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</a-tab-pane>
<a-tab-pane tab="Network ACL Lists" key="acl" v-if="'listNetworkACLLists' in $store.getters.apis">
<a-button
type="dashed"
icon="plus"
style="width: 100%"
@click="() => handleOpenModals('networkAcl')">
Add Network ACL List
</a-button>
<a-table
class="table"
size="small"
:columns="networkAclsColumns"
:dataSource="networkAcls"
:rowKey="item => item.id"
:pagination="false"
>
<template slot="name" slot-scope="text, item">
<router-link :to="{ path: '/acllist/' + item.id }">
{{ text }}
</router-link>
</template>
</a-table>
<a-pagination
class="row-element pagination"
size="small"
:current="page"
:pageSize="pageSize"
:total="itemCounts.networkAcls"
:showTotal="total => `Total ${total} items`"
:pageSizeOptions="['10', '20', '40', '80', '100']"
@change="changePage"
@showSizeChange="changePageSize"
showSizeChanger/>
<a-modal
v-model="modals.networkAcl"
:title="$t('label.add.acl.list')"
@ok="handleNetworkAclFormSubmit">
<a-form @submit.prevent="handleNetworkAclFormSubmit" :form="networkAclForm">
<a-form-item :label="$t('label.add.list.name')">
<a-input v-decorator="['name', {rules: [{ required: true, message: 'Required' }]}]"></a-input>
</a-form-item>
<a-form-item :label="$t('description')">
<a-input v-decorator="['description', {rules: [{ required: true, message: 'Required' }]}]"></a-input>
</a-form-item>
</a-form>
</a-modal>
</a-tab-pane>
<a-tab-pane tab="Virtual Routers" key="vr" v-if="'listRouters' in $store.getters.apis">
<a-list>
<a-list-item v-for="item in routers" :key="item.id">
<div class="list__item">
<div class="list__row">
<div class="list__col">
<div class="list__label">{{ $t('name') }}</div>
<div>
<router-link :to="{ path: '/router/' + item.id }">
{{ item.name }}
</router-link>
</div>
</div>
<div class="list__col">
<div class="list__label">{{ $t('state') }}</div>
<div><status :text="item.state" displayText></status></div>
</div>
<div class="list__col">
<div class="list__label">{{ $t('publicip') }}</div>
<div>{{ item.publicip }}</div>
</div>
<div class="list__col">
<div class="list__label">{{ $t('redundantrouter') }}</div>
<div>{{ item.isredundantrouter }}</div>
</div>
<div class="list__col">
<div class="list__label">{{ $t('redundantstate') }}</div>
<div>{{ item.redundantstate }}</div>
</div>
<div class="list__col">
<div class="list__label">{{ $t('hostname') }}</div>
<div>
<router-link :to="{ path: '/host/' + item.hostid }">
{{ item.hostname }}
</router-link>
</div>
</div>
</div>
</div>
</a-list-item>
</a-list>
</a-tab-pane>
</a-tabs>
</a-spin>
</template>
<script>
import { api } from '@/api'
import DetailsTab from '@/components/view/DetailsTab'
import Status from '@/components/widgets/Status'
import VpcTiersTab from './VpcTiersTab'
import { mixinDevice } from '@/utils/mixin.js'
export default {
name: 'VpcTab',
components: {
DetailsTab,
Status,
VpcTiersTab
},
mixins: [mixinDevice],
props: {
resource: {
type: Object,
required: true
},
loading: {
type: Boolean,
default: false
}
},
data () {
return {
routers: [],
fetchLoading: false,
privateGateways: [],
publicIpAddresses: [],
vpnGateways: [],
vpnConnections: [],
networkAcls: [],
modals: {
gateway: false,
gatewayLoading: false,
vpnConnection: false,
vpnConnectionLoading: false,
networkAcl: false
},
placeholders: {
vlan: null,
ipaddress: null,
gateway: null,
netmask: null
},
physicalnetworks: [],
vpncustomergateways: [],
privateGatewaysColumns: [
{
title: this.$t('ip'),
dataIndex: 'ipaddress',
scopedSlots: { customRender: 'ipaddress' }
},
{
title: this.$t('state'),
dataIndex: 'state',
scopedSlots: { customRender: 'state' }
},
{
title: this.$t('gateway'),
dataIndex: 'gateway'
},
{
title: this.$t('netmask'),
dataIndex: 'netmask'
},
{
title: this.$t('vlan'),
dataIndex: 'vlan'
}
],
vpnConnectionsColumns: [
{
title: this.$t('ip'),
dataIndex: 'publicip',
scopedSlots: { customRender: 'publicip' }
},
{
title: this.$t('state'),
dataIndex: 'state',
scopedSlots: { customRender: 'state' }
},
{
title: this.$t('gateway'),
dataIndex: 'gateway'
},
{
title: this.$t('ipsecpsk'),
dataIndex: 'ipsecpsk'
}
],
publicIpAddressesColumns: [
{
title: this.$t('ip'),
dataIndex: 'ipaddress',
scopedSlots: { customRender: 'ipaddress' }
},
{
title: this.$t('state'),
dataIndex: 'state',
scopedSlots: { customRender: 'state' }
},
{
title: this.$t('vm'),
dataIndex: 'vm',
scopedSlots: { customRender: 'vm' }
},
{
title: this.$t('network'),
dataIndex: 'network',
scopedSlots: { customRender: 'network' }
}
],
networkAclsColumns: [
{
title: this.$t('name'),
dataIndex: 'name',
scopedSlots: { customRender: 'name' }
},
{
title: this.$t('description'),
dataIndex: 'description'
}
],
itemCounts: {
privateGateways: 0,
publicIpAddresses: 0,
vpnConnections: 0,
networkAcls: 0
},
page: 1,
pageSize: 10,
currentTab: 'details'
}
},
beforeCreate () {
this.gatewayForm = this.$form.createForm(this)
this.vpnConnectionForm = this.$form.createForm(this)
this.networkAclForm = this.$form.createForm(this)
},
mounted () {
this.handleFetchData()
},
watch: {
loading (newData, oldData) {
if (!newData && this.resource.id) {
this.handleFetchData()
}
}
},
methods: {
handleChangeTab (e) {
this.currentTab = e
this.page = 1
this.pageSize = 10
this.handleFetchData()
},
handleFetchData () {
switch (this.currentTab) {
case 'pgw':
this.fetchPrivateGateways()
break
case 'ip':
this.fetchPublicIpAddresses()
break
case 'vpngw':
this.fetchVpnGateways()
break
case 'vpnc':
this.fetchVpnConnections()
break
case 'acl':
this.fetchAclList()
break
case 'vr':
this.fetchRouters()
break
}
},
fetchRouters () {
this.fetchLoading = true
api('listRouters', { vpcid: this.resource.id, listAll: true }).then(json => {
this.routers = json.listroutersresponse.router
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
},
fetchPrivateGateways () {
this.fetchLoading = true
api('listPrivateGateways', {
vpcid: this.resource.id,
listAll: true,
page: this.page,
pagesize: this.pageSize
}).then(json => {
this.privateGateways = json.listprivategatewaysresponse.privategateway
this.itemCounts.privateGateways = json.listprivategatewaysresponse.count
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
},
fetchPublicIpAddresses () {
this.fetchLoading = true
api('listPublicIpAddresses', {
vpcid: this.resource.id,
listAll: true,
page: this.page,
pagesize: this.pageSize,
forvirtualnetwork: true
}).then(json => {
this.publicIpAddresses = json.listpublicipaddressesresponse.publicipaddress
this.itemCounts.publicIpAddresses = json.listpublicipaddressesresponse.count
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
},
fetchVpnGateways () {
this.fetchLoading = true
api('listVpnGateways', {
vpcid: this.resource.id,
listAll: true
}).then(json => {
this.vpnGateways = json.listvpngatewaysresponse.vpngateway ? json.listvpngatewaysresponse.vpngateway : []
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
},
fetchVpnConnections () {
this.fetchLoading = true
api('listVpnConnections', {
vpcid: this.resource.id,
listAll: true,
page: this.page,
pagesize: this.pageSize
}).then(json => {
this.vpnConnections = json.listvpnconnectionsresponse.vpnconnection
this.itemCounts.vpnConnections = json.listvpnconnectionsresponse.count
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
},
fetchAclList () {
this.fetchLoading = true
api('listNetworkACLLists', {
vpcid: this.resource.id,
listAll: true,
page: this.page,
pagesize: this.pageSize
}).then(json => {
this.networkAcls = json.listnetworkacllistsresponse.networkacllist
this.itemCounts.networkAcls = json.listnetworkacllistsresponse.count
if (this.modals.gateway === true) {
this.$nextTick(() => {
this.gatewayForm.setFieldsValue({ acl: this.networkAcls[0].id })
})
}
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
})
},
fetchPhysicalNetworks () {
this.modals.gatewayLoading = true
api('listPhysicalNetworks', { zoneid: this.resource.zoneid }).then(json => {
this.physicalnetworks = json.listphysicalnetworksresponse.physicalnetwork
if (this.modals.gateway === true) {
this.$nextTick(() => {
this.gatewayForm.setFieldsValue({ physicalnetwork: this.physicalnetworks[0].id })
})
}
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.modals.gatewayLoading = false
})
},
fetchVpnCustomerGateways () {
this.modals.vpnConnectionLoading = true
api('listVpnCustomerGateways', { listAll: true }).then(json => {
this.vpncustomergateways = json.listvpncustomergatewaysresponse.vpncustomergateway
if (this.modals.vpnConnection === true) {
this.$nextTick(() => {
this.vpnConnectionForm.setFieldsValue({ vpncustomergateway: this.vpncustomergateways[0].id })
})
}
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.modals.vpnConnectionLoading = false
})
},
handleOpenModals (e) {
switch (e) {
case 'privateGateways':
this.modals.gateway = true
this.gatewayForm.resetFields()
this.fetchAclList()
this.fetchPhysicalNetworks()
break
case 'vpnConnection':
this.modals.vpnConnection = true
this.vpnConnectionForm.resetFields()
this.fetchVpnCustomerGateways()
this.fetchVpnGateways()
break
case 'networkAcl':
this.modals.networkAcl = true
this.networkAclForm.resetFields()
break
}
},
handleGatewayFormSubmit () {
this.modals.gatewayLoading = true
this.gatewayForm.validateFields(errors => {
if (errors) {
this.modals.gatewayLoading = false
return
}
const data = this.gatewayForm.getFieldsValue()
api('createPrivateGateway', {
sourcenatsupported: data.nat,
physicalnetworkid: data.physicalnetwork,
vpcid: this.resource.id,
ipaddress: data.ipaddress,
gateway: data.gateway,
netmask: data.netmask,
vlan: data.vlan,
aclid: data.acl
}).then(response => {
this.$store.dispatch('AddAsyncJob', {
title: `Successfully added Private Gateway`,
jobid: response.createprivategatewayresponse.jobid,
status: 'progress'
})
this.$pollJob({
jobId: response.createprivategatewayresponse.jobid,
successMethod: () => {
this.modals.gateway = false
this.handleFetchData()
},
errorMessage: 'Adding Private Gateway failed',
errorMethod: () => {
this.modals.gateway = false
this.handleFetchData()
},
loadingMessage: `Adding Private Gateway...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.modals.gateway = false
this.handleFetchData()
}
})
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.modals.gatewayLoading = false
this.modals.gateway = false
this.handleFetchData()
})
})
},
handleAcquireNewIp () {
this.fetchLoading = true
api('associateIpAddress', { vpcid: this.resource.id }).then(response => {
this.$store.dispatch('AddAsyncJob', {
title: `Successfully acquired new IP`,
jobid: response.associateipaddressresponse.jobid,
status: 'progress'
})
this.$pollJob({
jobId: response.associateipaddressresponse.jobid,
successMethod: () => {
this.fetchPublicIpAddresses()
},
errorMessage: 'Failed to acquire new IP',
errorMethod: () => {
this.fetchPublicIpAddresses()
},
loadingMessage: `Acquiring new IP...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.fetchPublicIpAddresses()
}
})
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
this.fetchPublicIpAddresses()
})
},
handleVpnConnectionFormSubmit () {
this.fetchLoading = true
this.modals.vpnConnection = false
this.vpnConnectionForm.validateFields((errors, values) => {
if (errors) {
this.fetchLoading = false
return
}
api('createVpnConnection', {
s2svpngatewayid: this.vpnGateways[0].id,
s2scustomergatewayid: values.vpncustomergateway,
passive: values.passive ? values.passive : false
}).then(response => {
this.$store.dispatch('AddAsyncJob', {
title: `VPN Connection`,
jobid: response.createvpnconnectionresponse.jobid,
status: 'progress'
})
this.$pollJob({
jobId: response.createvpnconnectionresponse.jobid,
successMethod: () => {
this.fetchVpnConnections()
this.fetchLoading = false
},
errorMessage: 'Adding VPN Connection failed',
errorMethod: () => {
this.fetchVpnConnections()
this.fetchLoading = false
},
loadingMessage: `Adding VPN Connection...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.fetchVpnConnections()
this.fetchLoading = false
}
})
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchVpnConnections()
this.fetchLoading = false
})
})
},
handleNetworkAclFormSubmit () {
this.fetchLoading = true
this.modals.networkAcl = false
this.networkAclForm.validateFields((errors, values) => {
if (errors) {
this.fetchLoading = false
}
api('createNetworkACLList', {
name: values.name,
description: values.description,
vpcid: this.resource.id
}).then(response => {
this.$store.dispatch('AddAsyncJob', {
title: `Successfully added Network ACL List`,
jobid: response.createnetworkacllistresponse.jobid,
status: 'progress'
})
this.$pollJob({
jobId: response.createnetworkacllistresponse.jobid,
successMethod: () => {
this.fetchLoading = false
},
errorMessage: 'Adding Network ACL List failed',
errorMethod: () => {
this.fetchLoading = false
},
loadingMessage: `Adding Network ACL List...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.fetchLoading = false
}
})
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
this.fetchAclList()
})
})
},
handleCreateVpnGateway () {
this.fetchLoading = true
api('createVpnGateway', {
vpcid: this.resource.id
}).then(response => {
this.$store.dispatch('AddAsyncJob', {
title: `Successfully added VPN Gateway`,
jobid: response.createvpngatewayresponse.jobid,
status: 'progress'
})
this.$pollJob({
jobId: response.createvpngatewayresponse.jobid,
successMethod: () => {
this.fetchLoading = false
},
errorMessage: 'Adding VPN Gateway failed',
errorMethod: () => {
this.fetchLoading = false
},
loadingMessage: `Adding VPN Gateway...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.fetchLoading = false
}
})
}).catch(error => {
this.$notification.error({
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).finally(() => {
this.fetchLoading = false
this.handleFetchData()
})
},
changePage (page, pageSize) {
this.page = page
this.pageSize = pageSize
this.handleFetchData()
},
changePageSize (currentPage, pageSize) {
this.page = currentPage
this.pageSize = pageSize
this.handleFetchData()
}
}
}
</script>
<style lang="scss" scoped>
.list {
&__item,
&__row {
display: flex;
flex-wrap: wrap;
width: 100%;
}
&__item {
margin-bottom: -20px;
}
&__col {
flex: 1;
margin-right: 20px;
margin-bottom: 20px;
}
&__label {
font-weight: bold;
}
}
.pagination {
margin-top: 20px;
}
.table {
margin-top: 20px;
overflow-y: auto;
}
</style>

View File

@ -24,10 +24,36 @@
<div class="list__item-container">
<div class="list__col">
<div class="list__label">
<router-link :to="{ path: '/guestnetwork/' + network.id }">{{ network.name }}</router-link>
{{ $t('name') }}
</div>
<div>
<router-link :to="{ path: '/guestnetwork/' + network.id }">{{ network.name }} </router-link>
<a-tag v-if="network.broadcasturi">{{ network.broadcasturi }}</a-tag>
</div>
<div>CIDR: {{ network.cidr }}</div>
</div>
<div class="list__col">
<div class="list__label">{{ $t('state') }}</div>
<div><status :text="network.state" displayText></status></div>
</div>
<div class="list__col">
<div class="list__label">
{{ $t('CIDR') }}
</div>
<div>{{ network.cidr }}</div>
</div>
<div class="list__col">
<div class="list__label">
{{ $t('aclid') }}
</div>
<div>
<router-link :to="{ path: '/acllist/' + network.aclid }">
{{ network.aclid }}
</router-link>
</div>
</div>
</div>
<div class="list__item-container">
<div class="list__col">
<a-button icon="share-alt">
<router-link :to="{ path: '/ilb?networkid=' + network.id }"> Internal LB</router-link>
@ -50,20 +76,8 @@
</div>
</div>
</div>
<div slot="actions">
<a-popconfirm
:title="`${$t('label.delete')}?`"
@confirm="handleDelete(item)"
okText="Yes"
cancelText="No"
placement="top"
>
<a-button icon="delete" type="danger" shape="round"></a-button>
</a-popconfirm>
</div>
</a-list-item>
</a-list>
</a-spin>
</template>