mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
network: Egress, PF, FW, VPN, LB tabs (#84)
Implements the egress, pf, fw, vpn and lb tabs for a guest network (ip). Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com> Co-authored-by: Rohit Yadav <rohit@apache.org>
This commit is contained in:
parent
759921ee11
commit
f3858e5297
@ -2,24 +2,16 @@ addNetworkServiceProvider
|
|||||||
addResourceDetail
|
addResourceDetail
|
||||||
addTrafficType
|
addTrafficType
|
||||||
assignCertToLoadBalancer
|
assignCertToLoadBalancer
|
||||||
assignToLoadBalancerRule
|
|
||||||
authorizeSamlSso
|
authorizeSamlSso
|
||||||
authorizeSecurityGroupEgress
|
|
||||||
authorizeSecurityGroupIngress
|
|
||||||
configureInternalLoadBalancerElement
|
configureInternalLoadBalancerElement
|
||||||
configureVirtualRouterElement
|
configureVirtualRouterElement
|
||||||
createEgressFirewallRule
|
|
||||||
createFirewallRule
|
|
||||||
createLBHealthCheckPolicy
|
createLBHealthCheckPolicy
|
||||||
createLBStickinessPolicy
|
|
||||||
createLoadBalancer
|
createLoadBalancer
|
||||||
createLoadBalancerRule
|
|
||||||
createManagementNetworkIpRange
|
createManagementNetworkIpRange
|
||||||
createNetworkACL
|
createNetworkACL
|
||||||
createNetworkACLList
|
createNetworkACLList
|
||||||
createPhysicalNetwork
|
createPhysicalNetwork
|
||||||
createPortableIpRange
|
createPortableIpRange
|
||||||
createPortForwardingRule
|
|
||||||
createPrivateGateway
|
createPrivateGateway
|
||||||
createSecondaryStagingStore
|
createSecondaryStagingStore
|
||||||
createSnapshotFromVMSnapshot
|
createSnapshotFromVMSnapshot
|
||||||
@ -30,25 +22,17 @@ createVpnConnection
|
|||||||
createVpnGateway
|
createVpnGateway
|
||||||
dedicateGuestVlanRange
|
dedicateGuestVlanRange
|
||||||
dedicatePublicIpRange
|
dedicatePublicIpRange
|
||||||
deleteAccountFromProject
|
|
||||||
deleteEgressFirewallRule
|
|
||||||
deleteFirewallRule
|
|
||||||
deleteLBHealthCheckPolicy
|
deleteLBHealthCheckPolicy
|
||||||
deleteLBStickinessPolicy
|
|
||||||
deleteLdapConfiguration
|
|
||||||
deleteLoadBalancer
|
deleteLoadBalancer
|
||||||
deleteLoadBalancerRule
|
|
||||||
deleteManagementNetworkIpRange
|
deleteManagementNetworkIpRange
|
||||||
deleteNetworkACL
|
deleteNetworkACL
|
||||||
deleteNetworkACLList
|
deleteNetworkACLList
|
||||||
deleteNetworkServiceProvider
|
deleteNetworkServiceProvider
|
||||||
deletePhysicalNetwork
|
deletePhysicalNetwork
|
||||||
deletePortableIpRange
|
deletePortableIpRange
|
||||||
deletePortForwardingRule
|
|
||||||
deletePrivateGateway
|
deletePrivateGateway
|
||||||
deleteProjectInvitation
|
deleteProjectInvitation
|
||||||
deleteSecondaryStagingStore
|
deleteSecondaryStagingStore
|
||||||
deleteSnapshotPolicies
|
|
||||||
deleteStaticRoute
|
deleteStaticRoute
|
||||||
deleteStorageNetworkIpRange
|
deleteStorageNetworkIpRange
|
||||||
deleteVlanIpRange
|
deleteVlanIpRange
|
||||||
@ -57,74 +41,47 @@ deleteVpnGateway
|
|||||||
findStoragePoolsForMigration
|
findStoragePoolsForMigration
|
||||||
importLdapUsers
|
importLdapUsers
|
||||||
ldapCreateAccount
|
ldapCreateAccount
|
||||||
linkDomainToLdap
|
|
||||||
listAffinityGroupTypes
|
listAffinityGroupTypes
|
||||||
listAndSwitchSamlAccount
|
listAndSwitchSamlAccount
|
||||||
listCapabilities
|
|
||||||
listDedicatedClusters
|
listDedicatedClusters
|
||||||
listDedicatedGuestVlanRanges
|
listDedicatedGuestVlanRanges
|
||||||
listDedicatedHosts
|
listDedicatedHosts
|
||||||
listDedicatedPods
|
listDedicatedPods
|
||||||
listDedicatedZones
|
listDedicatedZones
|
||||||
listDeploymentPlanners
|
listDeploymentPlanners
|
||||||
listEgressFirewallRules
|
|
||||||
listFirewallRules
|
|
||||||
listHostHAProviders
|
listHostHAProviders
|
||||||
listHostTags
|
listHostTags
|
||||||
listHypervisors
|
|
||||||
listIdps
|
listIdps
|
||||||
listInternalLoadBalancerElements
|
listInternalLoadBalancerElements
|
||||||
listInternalLoadBalancerVMs
|
listInternalLoadBalancerVMs
|
||||||
listLBHealthCheckPolicies
|
listLBHealthCheckPolicies
|
||||||
listLBStickinessPolicies
|
|
||||||
listLdapUsers
|
listLdapUsers
|
||||||
listLoadBalancerRuleInstances
|
|
||||||
listLoadBalancerRules
|
|
||||||
listLoadBalancers
|
listLoadBalancers
|
||||||
listNetworkACLLists
|
|
||||||
listNetworkACLs
|
listNetworkACLs
|
||||||
listNetworkServiceProviders
|
listNetworkServiceProviders
|
||||||
listOsCategories
|
listOsCategories
|
||||||
listPortableIpRanges
|
listPortableIpRanges
|
||||||
listPortForwardingRules
|
|
||||||
listPrivateGateways
|
|
||||||
listProjectAccounts
|
|
||||||
listProjectInvitations
|
|
||||||
listRegisteredServicePackages
|
listRegisteredServicePackages
|
||||||
listRemoteAccessVpns
|
|
||||||
listResourceLimits
|
|
||||||
listSamlAuthorization
|
listSamlAuthorization
|
||||||
listSecondaryStagingStores
|
listSecondaryStagingStores
|
||||||
listSnapshotPolicies
|
|
||||||
listStaticRoutes
|
listStaticRoutes
|
||||||
listStorageNetworkIpRange
|
listStorageNetworkIpRange
|
||||||
listStorageProviders
|
listStorageProviders
|
||||||
listStorageTags
|
listStorageTags
|
||||||
listSupportedNetworkServices
|
listSupportedNetworkServices
|
||||||
listTemplateOvfProperties
|
listTemplateOvfProperties
|
||||||
listTemplatePermissions
|
|
||||||
listTrafficTypes
|
listTrafficTypes
|
||||||
listVirtualRouterElements
|
listVirtualRouterElements
|
||||||
listVlanIpRanges
|
listVlanIpRanges
|
||||||
listVmwareDcs
|
listVmwareDcs
|
||||||
listVpnConnections
|
|
||||||
listVpnGateways
|
|
||||||
moveNetworkAclItem
|
moveNetworkAclItem
|
||||||
releaseDedicatedGuestVlanRange
|
releaseDedicatedGuestVlanRange
|
||||||
releasePublicIpRange
|
releasePublicIpRange
|
||||||
removeFromLoadBalancerRule
|
|
||||||
replaceNetworkACLList
|
|
||||||
resetVpnConnection
|
resetVpnConnection
|
||||||
revokeSecurityGroupEgress
|
|
||||||
revokeSecurityGroupIngress
|
|
||||||
startInternalLoadBalancerVM
|
startInternalLoadBalancerVM
|
||||||
stopInternalLoadBalancerVM
|
stopInternalLoadBalancerVM
|
||||||
updateLoadBalancerRule
|
|
||||||
updateNetworkACLItem
|
updateNetworkACLItem
|
||||||
updateNetworkACLList
|
updateNetworkACLList
|
||||||
updateNetworkServiceProvider
|
updateNetworkServiceProvider
|
||||||
updatePhysicalNetwork
|
updatePhysicalNetwork
|
||||||
updateProjectInvitation
|
|
||||||
updateResourceLimit
|
|
||||||
updateTrafficType
|
updateTrafficType
|
||||||
updateVpnCustomerGateway
|
|
||||||
|
|||||||
@ -13,8 +13,8 @@ var loadLabel = function (allFields, fieldDict, prefix) {
|
|||||||
allFields[fieldId].components.push(prefix)
|
allFields[fieldId].components.push(prefix)
|
||||||
} else {
|
} else {
|
||||||
allFields[fieldId] = {
|
allFields[fieldId] = {
|
||||||
'labels': [fieldDict[fieldId].label],
|
labels: [fieldDict[fieldId].label],
|
||||||
'components': [prefix]
|
components: [prefix]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cols = cols + "'" + fieldId + "', "
|
cols = cols + "'" + fieldId + "', "
|
||||||
@ -28,8 +28,8 @@ var loadLabel = function (allFields, fieldDict, prefix) {
|
|||||||
allFields[colId].components.push(prefix)
|
allFields[colId].components.push(prefix)
|
||||||
} else {
|
} else {
|
||||||
allFields[colId] = {
|
allFields[colId] = {
|
||||||
'labels': [columns[colId].label],
|
labels: [columns[colId].label],
|
||||||
'components': [prefix]
|
components: [prefix]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -63,9 +63,9 @@ var loadFields = function (data, prefix) {
|
|||||||
var curActions = []
|
var curActions = []
|
||||||
$.each(Object.keys(acVal), function (idx, acKey) {
|
$.each(Object.keys(acVal), function (idx, acKey) {
|
||||||
if (acVal[acKey].createForm) {
|
if (acVal[acKey].createForm) {
|
||||||
curActions.push({ 'action': acKey, 'label': acVal[acKey].label, 'keys': acVal[acKey].createForm.fields })
|
curActions.push({ action: acKey, label: acVal[acKey].label, keys: acVal[acKey].createForm.fields })
|
||||||
} else {
|
} else {
|
||||||
curActions.push({ 'action': acKey, 'label': acVal[acKey].label })
|
curActions.push({ action: acKey, label: acVal[acKey].label })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
countActions = countActions + curActions.length
|
countActions = countActions + curActions.length
|
||||||
@ -77,5 +77,5 @@ var loadFields = function (data, prefix) {
|
|||||||
$.extend(actions, recRes.actions)
|
$.extend(actions, recRes.actions)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return { 'allFields': allFields, 'columnsOrder': columnsOrder, 'actions': actions }
|
return { allFields: allFields, columnsOrder: columnsOrder, actions: actions }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<slot name="name">
|
<slot name="name">
|
||||||
<h4 class="name">
|
<h4 class="name">
|
||||||
{{ resource.displayname || resource.name }}
|
{{ resource.displayname || resource.name || resource.displaytext || resource.hostname || resource.username || resource.ipaddress }}
|
||||||
</h4>
|
</h4>
|
||||||
<console style="margin-left: 10px" :resource="resource" size="default" v-if="resource.id" />
|
<console style="margin-left: 10px" :resource="resource" size="default" v-if="resource.id" />
|
||||||
</slot>
|
</slot>
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
v-for="tab in tabs"
|
v-for="tab in tabs"
|
||||||
:tab="$t(tab.name)"
|
:tab="$t(tab.name)"
|
||||||
:key="tab.name"
|
:key="tab.name"
|
||||||
v-if="'show' in tab ? tab.show(resource, $route, $store.getters.userInfo) : true">
|
v-if="showHideTab(tab)">
|
||||||
<component :is="tab.component" :resource="resource" :loading="loading" :tab="activeTab" />
|
<component :is="tab.component" :resource="resource" :loading="loading" :tab="activeTab" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
@ -49,6 +49,7 @@
|
|||||||
import DetailsTab from '@/components/view/DetailsTab'
|
import DetailsTab from '@/components/view/DetailsTab'
|
||||||
import InfoCard from '@/components/view/InfoCard'
|
import InfoCard from '@/components/view/InfoCard'
|
||||||
import ResourceLayout from '@/layouts/ResourceLayout'
|
import ResourceLayout from '@/layouts/ResourceLayout'
|
||||||
|
import { api } from '@/api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ResourceView',
|
name: 'ResourceView',
|
||||||
@ -77,12 +78,45 @@ export default {
|
|||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
activeTab: ''
|
activeTab: '',
|
||||||
|
networkService: null,
|
||||||
|
vpnEnabled: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resource: function (newItem, oldItem) {
|
||||||
|
this.resource = newItem
|
||||||
|
if (newItem.id === oldItem.id) return
|
||||||
|
|
||||||
|
if (this.resource.associatednetworkid) {
|
||||||
|
api('listNetworks', { id: this.resource.associatednetworkid }).then(response => {
|
||||||
|
this.networkService = response.listnetworksresponse.network[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.resource.id && this.resource.ipaddress) {
|
||||||
|
api('listRemoteAccessVpns', {
|
||||||
|
publicipid: this.resource.id,
|
||||||
|
listAll: true
|
||||||
|
}).then(response => {
|
||||||
|
this.vpnEnabled = response.listremoteaccessvpnsresponse.remoteaccessvpn && response.listremoteaccessvpnsresponse.remoteaccessvpn.length > 0
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onTabChange (key) {
|
onTabChange (key) {
|
||||||
this.activeTab = key
|
this.activeTab = key
|
||||||
|
},
|
||||||
|
showHideTab (tab) {
|
||||||
|
if ('networkServiceFilter' in tab) {
|
||||||
|
return this.networkService && this.networkService.service &&
|
||||||
|
tab.networkServiceFilter(this.networkService.service)
|
||||||
|
} else if ('show' in tab) {
|
||||||
|
return tab.show(this.resource, this.$route, this.$store.getters.userInfo)
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,8 +45,9 @@ export default {
|
|||||||
name: 'details',
|
name: 'details',
|
||||||
component: () => import('@/components/view/DetailsTab.vue')
|
component: () => import('@/components/view/DetailsTab.vue')
|
||||||
}, {
|
}, {
|
||||||
name: 'egress-rules',
|
name: 'Egress Rules',
|
||||||
component: () => import('@/views/network/EgressConfigure.vue')
|
component: () => import('@/views/network/EgressConfigure.vue'),
|
||||||
|
show: () => true
|
||||||
}],
|
}],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
@ -227,14 +228,23 @@ export default {
|
|||||||
columns: ['ipaddress', 'state', 'associatednetworkname', 'virtualmachinename', 'allocated', 'account', 'zonename'],
|
columns: ['ipaddress', 'state', 'associatednetworkname', 'virtualmachinename', 'allocated', 'account', 'zonename'],
|
||||||
details: ['ipaddress', 'id', 'associatednetworkname', 'virtualmachinename', 'networkid', 'issourcenat', 'isstaticnat', 'virtualmachinename', 'vmipaddress', 'vlan', 'allocated', 'account', 'zonename'],
|
details: ['ipaddress', 'id', 'associatednetworkname', 'virtualmachinename', 'networkid', 'issourcenat', 'isstaticnat', 'virtualmachinename', 'vmipaddress', 'vlan', 'allocated', 'account', 'zonename'],
|
||||||
tabs: [{
|
tabs: [{
|
||||||
name: 'configure',
|
|
||||||
component: () => import('@/views/network/IpConfigure.vue')
|
|
||||||
}, {
|
|
||||||
name: 'vpn',
|
|
||||||
component: () => import('@/views/network/VpnDetails.vue')
|
|
||||||
}, {
|
|
||||||
name: 'details',
|
name: 'details',
|
||||||
component: () => import('@/components/view/DetailsTab.vue')
|
component: () => import('@/components/view/DetailsTab.vue')
|
||||||
|
}, {
|
||||||
|
name: 'Firewall',
|
||||||
|
component: () => import('@/views/network/FirewallRules.vue'),
|
||||||
|
networkServiceFilter: networkService => networkService.filter(x => x.name === 'Firewall').length > 0
|
||||||
|
}, {
|
||||||
|
name: 'Port Forwarding',
|
||||||
|
component: () => import('@/views/network/PortForwarding.vue'),
|
||||||
|
networkServiceFilter: networkService => networkService.filter(x => x.name === 'PortForwarding').length > 0
|
||||||
|
}, {
|
||||||
|
name: 'Load Balancing',
|
||||||
|
component: () => import('@/views/network/LoadBalancing.vue'),
|
||||||
|
networkServiceFilter: networkService => networkService.filter(x => x.name === 'Lb').length > 0
|
||||||
|
}, {
|
||||||
|
name: 'VPN',
|
||||||
|
component: () => import('@/views/network/VpnDetails.vue')
|
||||||
}],
|
}],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
@ -244,39 +254,6 @@ export default {
|
|||||||
listView: true,
|
listView: true,
|
||||||
args: ['networkid']
|
args: ['networkid']
|
||||||
},
|
},
|
||||||
{
|
|
||||||
api: 'createRemoteAccessVpn',
|
|
||||||
icon: 'link',
|
|
||||||
label: 'Enable Remote Access VPN',
|
|
||||||
dataView: true,
|
|
||||||
args: ['publicipid', 'domainid', 'account'],
|
|
||||||
mapping: {
|
|
||||||
publicipid: {
|
|
||||||
value: (record) => { return record.id }
|
|
||||||
},
|
|
||||||
domainid: {
|
|
||||||
value: (record) => { return record.domainid }
|
|
||||||
},
|
|
||||||
account: {
|
|
||||||
value: (record) => { return record.account }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
api: 'deleteRemoteAccessVpn',
|
|
||||||
icon: 'disconnect',
|
|
||||||
label: 'Disable Remove Access VPN',
|
|
||||||
dataView: true,
|
|
||||||
args: ['publicipid', 'domainid'],
|
|
||||||
mapping: {
|
|
||||||
publicipid: {
|
|
||||||
value: (record) => { return record.id }
|
|
||||||
},
|
|
||||||
domainid: {
|
|
||||||
value: (record) => { return record.domainid }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
api: 'enableStaticNat',
|
api: 'enableStaticNat',
|
||||||
icon: 'plus-circle',
|
icon: 'plus-circle',
|
||||||
@ -306,7 +283,7 @@ export default {
|
|||||||
{
|
{
|
||||||
api: 'disassociateIpAddress',
|
api: 'disassociateIpAddress',
|
||||||
icon: 'delete',
|
icon: 'delete',
|
||||||
label: 'Delete IP',
|
label: 'Release IP',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
show: (record) => { return !record.issourcenat }
|
show: (record) => { return !record.issourcenat }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"Accounts": "Accounts",
|
"Accounts": "Accounts",
|
||||||
"Affinity Groups": "Affinity Groups",
|
"Affinity Groups": "Affinity Groups",
|
||||||
"Alerts": "Alerts",
|
"Alerts": "Alerts",
|
||||||
|
"cancel": "Cancel",
|
||||||
"CPU Sockets": "CPU Sockets",
|
"CPU Sockets": "CPU Sockets",
|
||||||
"Cloudian Storage": "Cloudian Storage",
|
"Cloudian Storage": "Cloudian Storage",
|
||||||
"Clusters": "Clusters",
|
"Clusters": "Clusters",
|
||||||
@ -13,6 +14,7 @@
|
|||||||
"Dashboard": "Dashboard",
|
"Dashboard": "Dashboard",
|
||||||
"Disk Offerings": "Disk Offerings",
|
"Disk Offerings": "Disk Offerings",
|
||||||
"Domains": "Domains",
|
"Domains": "Domains",
|
||||||
|
"done": "Done",
|
||||||
"Events": "Events",
|
"Events": "Events",
|
||||||
"Global Settings": "Global Settings",
|
"Global Settings": "Global Settings",
|
||||||
"Hosts": "Hosts",
|
"Hosts": "Hosts",
|
||||||
@ -77,6 +79,7 @@
|
|||||||
"agentUsername": "Agent Username",
|
"agentUsername": "Agent Username",
|
||||||
"agentstate": "Agent State",
|
"agentstate": "Agent State",
|
||||||
"algorithm": "Algorithm",
|
"algorithm": "Algorithm",
|
||||||
|
"all": "All",
|
||||||
"allocatediops": "IOPS Allocated",
|
"allocatediops": "IOPS Allocated",
|
||||||
"allocationstate": "Allocation State",
|
"allocationstate": "Allocation State",
|
||||||
"annotation": "Annotation",
|
"annotation": "Annotation",
|
||||||
@ -256,6 +259,7 @@
|
|||||||
"hypervisortype": "Hypervisor",
|
"hypervisortype": "Hypervisor",
|
||||||
"hypervisorversion": "Hypervisor version",
|
"hypervisorversion": "Hypervisor version",
|
||||||
"hypervnetworklabel": "HyperV Traffic Label",
|
"hypervnetworklabel": "HyperV Traffic Label",
|
||||||
|
"icmp": "ICMP",
|
||||||
"icmpcode": "ICMP Code",
|
"icmpcode": "ICMP Code",
|
||||||
"icmptype": "ICMP Type",
|
"icmptype": "ICMP Type",
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
@ -340,6 +344,7 @@
|
|||||||
"label.action.cancel.maintenance.mode": "Cancel Maintenance Mode",
|
"label.action.cancel.maintenance.mode": "Cancel Maintenance Mode",
|
||||||
"label.action.change.password": "Change Password",
|
"label.action.change.password": "Change Password",
|
||||||
"label.action.configure.samlauthorization": "Configure SAML SSO Authorization",
|
"label.action.configure.samlauthorization": "Configure SAML SSO Authorization",
|
||||||
|
"label.action.configure.stickiness": "Stickiness",
|
||||||
"label.action.copy.ISO": "Copy ISO",
|
"label.action.copy.ISO": "Copy ISO",
|
||||||
"label.action.copy.template": "Copy Template",
|
"label.action.copy.template": "Copy Template",
|
||||||
"label.action.create.volume": "Create Volume",
|
"label.action.create.volume": "Create Volume",
|
||||||
@ -430,6 +435,8 @@
|
|||||||
"label.add.OpenDaylight.device": "Add OpenDaylight Controller",
|
"label.add.OpenDaylight.device": "Add OpenDaylight Controller",
|
||||||
"label.add.PA.device": "Add Palo Alto device",
|
"label.add.PA.device": "Add Palo Alto device",
|
||||||
"label.add.SRX.device": "Add SRX device",
|
"label.add.SRX.device": "Add SRX device",
|
||||||
|
"label.add.VM": "Add VM",
|
||||||
|
"label.add.VMs": "Add VMs",
|
||||||
"label.add.VM.to.tier": "Add VM to tier",
|
"label.add.VM.to.tier": "Add VM to tier",
|
||||||
"label.add.account": "Add Account",
|
"label.add.account": "Add Account",
|
||||||
"label.add.acl.list": "Add ACL List",
|
"label.add.acl.list": "Add ACL List",
|
||||||
@ -460,8 +467,10 @@
|
|||||||
"label.add.primary.storage": "Add Primary Storage",
|
"label.add.primary.storage": "Add Primary Storage",
|
||||||
"label.add.region": "Add Region",
|
"label.add.region": "Add Region",
|
||||||
"label.add.role": "Add Role",
|
"label.add.role": "Add Role",
|
||||||
|
"label.add.rule": "Add Rule",
|
||||||
"label.add.secondary.storage": "Add Secondary Storage",
|
"label.add.secondary.storage": "Add Secondary Storage",
|
||||||
"label.add.security.group": "Add Security Group",
|
"label.add.security.group": "Add Security Group",
|
||||||
|
"label.add.setting": "Add Setting",
|
||||||
"label.add.system.service.offering": "Add System Service Offering",
|
"label.add.system.service.offering": "Add System Service Offering",
|
||||||
"label.add.ucs.manager": "Add UCS Manager",
|
"label.add.ucs.manager": "Add UCS Manager",
|
||||||
"label.add.user": "Add User",
|
"label.add.user": "Add User",
|
||||||
@ -840,6 +849,7 @@
|
|||||||
"secretkey": "Secret Key",
|
"secretkey": "Secret Key",
|
||||||
"securityGroups": "Security Groups",
|
"securityGroups": "Security Groups",
|
||||||
"securitygroup": "Security Group",
|
"securitygroup": "Security Group",
|
||||||
|
"select": "Select",
|
||||||
"sent": "Date",
|
"sent": "Date",
|
||||||
"sentbytes": "Bytes Sent",
|
"sentbytes": "Bytes Sent",
|
||||||
"server": "Server",
|
"server": "Server",
|
||||||
@ -872,6 +882,7 @@
|
|||||||
"snmpCommunity": "SNMP Community",
|
"snmpCommunity": "SNMP Community",
|
||||||
"snmpPort": "SNMP Port",
|
"snmpPort": "SNMP Port",
|
||||||
"sockettimeout": "Socket Timeout",
|
"sockettimeout": "Socket Timeout",
|
||||||
|
"sourcecidr": "Source CIDR",
|
||||||
"sourceNat": "Source NAT",
|
"sourceNat": "Source NAT",
|
||||||
"sourceipaddress": "Source IP Address",
|
"sourceipaddress": "Source IP Address",
|
||||||
"sourceport": "Source Port",
|
"sourceport": "Source Port",
|
||||||
@ -905,6 +916,7 @@
|
|||||||
"systemvmtype": "System VM Type",
|
"systemvmtype": "System VM Type",
|
||||||
"tags": "Tags",
|
"tags": "Tags",
|
||||||
"tariffValue": "Tariff Value",
|
"tariffValue": "Tariff Value",
|
||||||
|
"tcp": "TCP",
|
||||||
"template": "Select a template",
|
"template": "Select a template",
|
||||||
"templateFileUpload": "Local file",
|
"templateFileUpload": "Local file",
|
||||||
"templateLimit": "Template Limits",
|
"templateLimit": "Template Limits",
|
||||||
@ -926,6 +938,7 @@
|
|||||||
"traffictype": "Traffic Type",
|
"traffictype": "Traffic Type",
|
||||||
"transportzoneuuid": "Transport Zone Uuid",
|
"transportzoneuuid": "Transport Zone Uuid",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
|
"udp": "UDP",
|
||||||
"unit": "Usage Unit",
|
"unit": "Usage Unit",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"usageName": "Usage Type",
|
"usageName": "Usage Type",
|
||||||
@ -964,6 +977,7 @@
|
|||||||
"vlanRange": "VLAN/VNI Range",
|
"vlanRange": "VLAN/VNI Range",
|
||||||
"vlanname": "VLAN",
|
"vlanname": "VLAN",
|
||||||
"vlanrange": "VLAN/VNI Range",
|
"vlanrange": "VLAN/VNI Range",
|
||||||
|
"vm": "VM",
|
||||||
"vmLimit": "Instance Limits",
|
"vmLimit": "Instance Limits",
|
||||||
"vmTotal": "Instances",
|
"vmTotal": "Instances",
|
||||||
"vmdisplayname": "VM display name",
|
"vmdisplayname": "VM display name",
|
||||||
|
|||||||
@ -45,6 +45,6 @@ export const deviceEnquire = function (callback) {
|
|||||||
// screen and (max-width: 1087.99px)
|
// screen and (max-width: 1087.99px)
|
||||||
enquireJs
|
enquireJs
|
||||||
.register('screen and (max-width: 576px)', matchMobile)
|
.register('screen and (max-width: 576px)', matchMobile)
|
||||||
.register('screen and (min-width: 576px) and (max-width: 1366px)', matchTablet)
|
.register('screen and (min-width: 576px) and (max-width: 1280px)', matchTablet)
|
||||||
.register('screen and (min-width: 1367px)', matchDesktop)
|
.register('screen and (min-width: 1281px)', matchDesktop)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,24 +17,287 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
TODO: Egress view for isolated network
|
<div>
|
||||||
|
<div class="form">
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">Source CIDR</div>
|
||||||
|
<a-input v-model="newRule.cidrlist"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">Destination CIDR</div>
|
||||||
|
<a-input v-model="newRule.destcidrlist"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">Protocol</div>
|
||||||
|
<a-select v-model="newRule.protocol" style="width: 100%;" @change="resetRulePorts">
|
||||||
|
<a-select-option value="tcp">TCP</a-select-option>
|
||||||
|
<a-select-option value="udp">UDP</a-select-option>
|
||||||
|
<a-select-option value="icmp">ICMP</a-select-option>
|
||||||
|
<a-select-option value="all">All</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
|
||||||
|
<div class="form__label">Start Port</div>
|
||||||
|
<a-input v-model="newRule.startport"></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
|
||||||
|
<div class="form__label">End Port</div>
|
||||||
|
<a-input v-model="newRule.endport"></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'icmp'" class="form__item">
|
||||||
|
<div class="form__label">ICMP Type</div>
|
||||||
|
<a-input v-model="newRule.icmptype"></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'icmp'" class="form__item">
|
||||||
|
<div class="form__label">ICMP Code</div>
|
||||||
|
<a-input v-model="newRule.icmpcode"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="form__item">
|
||||||
|
<a-button type="primary" icon="plus" @click="addRule">{{ $t('add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider/>
|
||||||
|
|
||||||
|
<a-list :loading="loading" style="min-height: 25px;">
|
||||||
|
<a-list-item v-for="rule in egressRules" :key="rule.id" class="rule">
|
||||||
|
<div class="rule-container">
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">Source CIDR</div>
|
||||||
|
<div>{{ rule.cidrlist }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">Destination CIDR</div>
|
||||||
|
<div>{{ rule.destcidrlist }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">Protocol</div>
|
||||||
|
<div>{{ rule.protocol | capitalise }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ rule.protocol === 'icmp' ? 'ICMP Type' : 'Start Port' }}</div>
|
||||||
|
<div>{{ rule.icmptype || rule.startport >= 0 ? rule.icmptype || rule.startport : 'All' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ rule.protocol === 'icmp' ? 'ICMP Code' : 'End Port' }}</div>
|
||||||
|
<div>{{ rule.icmpcode || rule.endport >= 0 ? rule.icmpcode || rule.endport : 'All' }}</div>
|
||||||
|
</div>
|
||||||
|
<div slot="actions">
|
||||||
|
<a-button shape="round" type="danger" icon="delete" @click="deleteRule(rule)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { api } from '@/api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: '',
|
props: {
|
||||||
components: {
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
loading: true,
|
||||||
|
egressRules: [],
|
||||||
|
newRule: {
|
||||||
|
protocol: 'tcp',
|
||||||
|
cidrlist: null,
|
||||||
|
destcidrlist: null,
|
||||||
|
networkid: this.resource.id,
|
||||||
|
icmptype: null,
|
||||||
|
icmpcode: null,
|
||||||
|
startport: null,
|
||||||
|
endport: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
capitalise: val => {
|
||||||
|
if (val === 'all') return 'All'
|
||||||
|
return val.toUpperCase()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resource: function (newItem, oldItem) {
|
||||||
|
if (!newItem || !newItem.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resource = newItem
|
||||||
|
this.fetchData()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
api('listEgressFirewallRules', {
|
||||||
|
listAll: true,
|
||||||
|
networkid: this.resource.id
|
||||||
|
}).then(response => {
|
||||||
|
this.egressRules = response.listegressfirewallrulesresponse.firewallrule
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteRule (rule) {
|
||||||
|
this.loading = true
|
||||||
|
api('deleteEgressFirewallRule', { id: rule.id }).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.deleteegressfirewallruleresponse.jobid,
|
||||||
|
successMessage: `Successfully removed Egress rule`,
|
||||||
|
successMethod: () => this.fetchData(),
|
||||||
|
errorMessage: 'Removing Egress rule failed',
|
||||||
|
errorMethod: () => this.fetchData(),
|
||||||
|
loadingMessage: `Deleting Egress rule...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => this.fetchData()
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.fetchData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addRule () {
|
||||||
|
this.loading = true
|
||||||
|
api('createEgressFirewallRule', { ...this.newRule }).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.createegressfirewallruleresponse.jobid,
|
||||||
|
successMessage: `Successfully added new Egress rule`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
errorMessage: 'Adding new Egress rule failed',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
loadingMessage: `Adding new Egress rule...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.createegressfirewallruleresponse.errortext
|
||||||
|
})
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetAllRules () {
|
||||||
|
this.newRule.protocol = 'tcp'
|
||||||
|
this.newRule.cidrlist = null
|
||||||
|
this.newRule.destcidrlist = null
|
||||||
|
this.newRule.networkid = this.resource.id
|
||||||
|
this.resetRulePorts()
|
||||||
|
},
|
||||||
|
resetRulePorts () {
|
||||||
|
this.newRule.icmptype = null
|
||||||
|
this.newRule.icmpcode = null
|
||||||
|
this.newRule.startport = null
|
||||||
|
this.newRule.endport = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
|
.rule {
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
.ant-select {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
476
ui/src/views/network/FirewallRules.vue
Normal file
476
ui/src/views/network/FirewallRules.vue
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
// 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>
|
||||||
|
<div>
|
||||||
|
<div class="form">
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">{{ $t('sourcecidr') }}</div>
|
||||||
|
<a-input v-model="newRule.cidrlist"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">{{ $t('protocol') }}</div>
|
||||||
|
<a-select v-model="newRule.protocol" style="width: 100%;" @change="resetRulePorts">
|
||||||
|
<a-select-option value="tcp">{{ $t('tcp') }}</a-select-option>
|
||||||
|
<a-select-option value="udp">{{ $t('udp') }}</a-select-option>
|
||||||
|
<a-select-option value="icmp">{{ $t('icmp') }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
|
||||||
|
<div class="form__label">{{ $t('startport') }}</div>
|
||||||
|
<a-input v-model="newRule.startport"></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
|
||||||
|
<div class="form__label">{{ $t('endport') }}</div>
|
||||||
|
<a-input v-model="newRule.endport"></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'icmp'" class="form__item">
|
||||||
|
<div class="form__label">{{ $t('icmptype') }}</div>
|
||||||
|
<a-input v-model="newRule.icmptype"></a-input>
|
||||||
|
</div>
|
||||||
|
<div v-show="newRule.protocol === 'icmp'" class="form__item">
|
||||||
|
<div class="form__label">{{ $t('icmpcode') }}</div>
|
||||||
|
<a-input v-model="newRule.icmpcode"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="form__item" style="margin-left: auto;">
|
||||||
|
<a-button type="primary" @click="addRule">{{ $t('add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider/>
|
||||||
|
|
||||||
|
<a-list :loading="loading" style="min-height: 25px;">
|
||||||
|
<a-list-item v-for="rule in firewallRules" :key="rule.id" class="rule">
|
||||||
|
<div class="rule-container">
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('sourcecidr') }}</div>
|
||||||
|
<div>{{ rule.cidrlist }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('protocol') }}</div>
|
||||||
|
<div>{{ rule.protocol | capitalise }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ rule.protocol === 'icmp' ? $t('icmptype') : $t('startport') }}</div>
|
||||||
|
<div>{{ rule.icmptype || rule.startport >= 0 ? rule.icmptype || rule.startport : $t('all') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ rule.protocol === 'icmp' ? 'ICMP Code' : 'End Port' }}</div>
|
||||||
|
<div>{{ rule.icmpcode || rule.endport >= 0 ? rule.icmpcode || rule.endport : $t('all') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('state') }}</div>
|
||||||
|
<div>{{ rule.state }}</div>
|
||||||
|
</div>
|
||||||
|
<div slot="actions">
|
||||||
|
<a-button shape="round" icon="tag" class="rule-action" @click="() => openTagsModal(rule.id)" />
|
||||||
|
<a-button shape="round" type="danger" icon="delete" class="rule-action" @click="deleteRule(rule)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
|
||||||
|
<a-modal title="Edit Tags" v-model="tagsModalVisible" :footer="null" :afterClose="closeModal">
|
||||||
|
<div class="add-tags">
|
||||||
|
<div class="add-tags__input">
|
||||||
|
<p class="add-tags__label">{{ $t('key') }}</p>
|
||||||
|
<a-input v-model="newTag.key"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="add-tags__input">
|
||||||
|
<p class="add-tags__label">{{ $t('value') }}</p>
|
||||||
|
<a-input v-model="newTag.value"></a-input>
|
||||||
|
</div>
|
||||||
|
<a-button type="primary" @click="() => handleAddTag()">{{ $t('add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider></a-divider>
|
||||||
|
|
||||||
|
<div class="tags-container">
|
||||||
|
<div class="tags" v-for="(tag, index) in tags" :key="index">
|
||||||
|
<a-tag :key="index" :closable="true" :afterClose="() => handleDeleteTag(tag)">
|
||||||
|
{{ tag.key }} = {{ tag.value }}
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-button class="add-tags-done" @click="tagsModalVisible = false" type="primary">{{ $t('done') }}</a-button>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { api } from '@/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inject: ['parentFetchData', 'parentToggleLoading'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
firewallRules: [],
|
||||||
|
newRule: {
|
||||||
|
protocol: 'tcp',
|
||||||
|
cidrlist: null,
|
||||||
|
ipaddressid: this.resource.id,
|
||||||
|
icmptype: null,
|
||||||
|
icmpcode: null,
|
||||||
|
startport: null,
|
||||||
|
endport: null
|
||||||
|
},
|
||||||
|
tagsModalVisible: false,
|
||||||
|
selectedRule: null,
|
||||||
|
tags: [],
|
||||||
|
newTag: {
|
||||||
|
key: null,
|
||||||
|
value: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
capitalise: val => {
|
||||||
|
if (val === 'all') return 'All'
|
||||||
|
return val.toUpperCase()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resource: function (newItem, oldItem) {
|
||||||
|
if (!newItem || !newItem.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resource = newItem
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
api('listFirewallRules', {
|
||||||
|
listAll: true,
|
||||||
|
ipaddressid: this.resource.id
|
||||||
|
}).then(response => {
|
||||||
|
this.firewallRules = response.listfirewallrulesresponse.firewallrule
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteRule (rule) {
|
||||||
|
this.loading = true
|
||||||
|
api('deleteFirewallRule', { id: rule.id }).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.deletefirewallruleresponse.jobid,
|
||||||
|
successMessage: `Successfully removed Firewall rule`,
|
||||||
|
successMethod: () => this.fetchData(),
|
||||||
|
errorMessage: 'Removing Firewall rule failed',
|
||||||
|
errorMethod: () => this.fetchData(),
|
||||||
|
loadingMessage: `Deleting Firewall rule...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => this.fetchData()
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.fetchData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addRule () {
|
||||||
|
this.loading = true
|
||||||
|
api('createFirewallRule', { ...this.newRule }).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.createfirewallruleresponse.jobid,
|
||||||
|
successMessage: `Successfully added new Firewall rule`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
errorMessage: 'Adding new Firewall rule failed',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
loadingMessage: `Adding new Firewall rule...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.createfirewallruleresponse.errortext
|
||||||
|
})
|
||||||
|
this.resetAllRules()
|
||||||
|
this.fetchData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetAllRules () {
|
||||||
|
this.newRule.protocol = 'tcp'
|
||||||
|
this.newRule.cidrlist = null
|
||||||
|
this.newRule.networkid = this.resource.id
|
||||||
|
this.resetRulePorts()
|
||||||
|
},
|
||||||
|
resetRulePorts () {
|
||||||
|
this.newRule.icmptype = null
|
||||||
|
this.newRule.icmpcode = null
|
||||||
|
this.newRule.startport = null
|
||||||
|
this.newRule.endport = null
|
||||||
|
},
|
||||||
|
closeModal () {
|
||||||
|
this.selectedRule = null
|
||||||
|
this.tagsModalVisible = false
|
||||||
|
this.newTag.key = null
|
||||||
|
this.newTag.value = null
|
||||||
|
},
|
||||||
|
openTagsModal (id) {
|
||||||
|
this.selectedRule = id
|
||||||
|
this.tagsModalVisible = true
|
||||||
|
api('listTags', {
|
||||||
|
resourceId: id,
|
||||||
|
resourceType: 'FirewallRule',
|
||||||
|
listAll: true
|
||||||
|
}).then(response => {
|
||||||
|
this.tags = response.listtagsresponse.tag
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleAddTag () {
|
||||||
|
api('createTags', {
|
||||||
|
'tags[0].key': this.newTag.key,
|
||||||
|
'tags[0].value': this.newTag.value,
|
||||||
|
resourceIds: this.selectedRule,
|
||||||
|
resourceType: 'FirewallRule'
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.createtagsresponse.jobid,
|
||||||
|
successMessage: `Successfully added tag`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.openTagsModal(this.selectedRule)
|
||||||
|
},
|
||||||
|
errorMessage: 'Failed to add new tag',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
},
|
||||||
|
loadingMessage: `Adding tag...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.createtagsresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDeleteTag (tag) {
|
||||||
|
api('deleteTags', {
|
||||||
|
'tags[0].key': tag.key,
|
||||||
|
'tags[0].value': tag.value,
|
||||||
|
resourceIds: this.selectedRule,
|
||||||
|
resourceType: 'FirewallRule'
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.deletetagsresponse.jobid,
|
||||||
|
successMessage: `Successfully removed tag`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.openTagsModal(this.selectedRule)
|
||||||
|
},
|
||||||
|
errorMessage: 'Failed to remove tag',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
},
|
||||||
|
loadingMessage: `Removing tag...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.deletetagsresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.rule {
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-right: -20px;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/*flex: 1;*/
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
.ant-select {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-action {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-tags-done {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -107,7 +107,7 @@
|
|||||||
okText="Yes"
|
okText="Yes"
|
||||||
cancelText="No"
|
cancelText="No"
|
||||||
>
|
>
|
||||||
<a-button shape="round" type="danger" icon="close-circle" class="rule-action" />
|
<a-button shape="round" type="danger" icon="delete" class="rule-action" />
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</div>
|
</div>
|
||||||
</a-list-item>
|
</a-list-item>
|
||||||
|
|||||||
@ -1,40 +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>
|
|
||||||
<div>
|
|
||||||
TODO: IP configure view: firewall, pf, lb
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: '',
|
|
||||||
components: {
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
</style>
|
|
||||||
1373
ui/src/views/network/LoadBalancing.vue
Normal file
1373
ui/src/views/network/LoadBalancing.vue
Normal file
File diff suppressed because it is too large
Load Diff
675
ui/src/views/network/PortForwarding.vue
Normal file
675
ui/src/views/network/PortForwarding.vue
Normal file
@ -0,0 +1,675 @@
|
|||||||
|
// 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>
|
||||||
|
<div>
|
||||||
|
<div class="form">
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">{{ $t('privateport') }}</div>
|
||||||
|
<a-input-group class="form__item__input-container" compact>
|
||||||
|
<a-input
|
||||||
|
v-model="newRule.privateport"
|
||||||
|
placeholder="Start"
|
||||||
|
style="border-right: 0; width: 60px; margin-right: 0;"></a-input>
|
||||||
|
<a-input
|
||||||
|
placeholder="-"
|
||||||
|
disabled
|
||||||
|
style="width: 30px; border-left: 0; border-right: 0; pointer-events: none; backgroundColor: #fff; text-align:
|
||||||
|
center; margin-right: 0;"></a-input>
|
||||||
|
<a-input
|
||||||
|
v-model="newRule.privateendport"
|
||||||
|
placeholder="End"
|
||||||
|
style="border-left: 0; width: 60px; text-align: right; margin-right: 0;"></a-input>
|
||||||
|
</a-input-group>
|
||||||
|
</div>
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">{{ $t('publicport') }}</div>
|
||||||
|
<a-input-group class="form__item__input-container" compact>
|
||||||
|
<a-input
|
||||||
|
v-model="newRule.publicport"
|
||||||
|
placeholder="Start"
|
||||||
|
style="border-right: 0; width: 60px; margin-right: 0;"></a-input>
|
||||||
|
<a-input
|
||||||
|
placeholder="-"
|
||||||
|
disabled
|
||||||
|
style="width: 30px; border-left: 0; border-right: 0; pointer-events: none; backgroundColor: #fff;
|
||||||
|
text-align: center; margin-right: 0;"></a-input>
|
||||||
|
<a-input
|
||||||
|
v-model="newRule.publicendport"
|
||||||
|
placeholder="End"
|
||||||
|
style="border-left: 0; width: 60px; text-align: right; margin-right: 0;"></a-input>
|
||||||
|
</a-input-group>
|
||||||
|
</div>
|
||||||
|
<div class="form__item">
|
||||||
|
<div class="form__label">{{ $t('protocol') }}</div>
|
||||||
|
<a-select v-model="newRule.protocol" style="width: 100%;">
|
||||||
|
<a-select-option value="tcp">{{ $t('tcp') }}</a-select-option>
|
||||||
|
<a-select-option value="udp">{{ $t('udp') }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<div class="form__item" style="margin-left: auto;">
|
||||||
|
<div class="form__label">{{ $t('label.add.VM') }}</div>
|
||||||
|
<a-button type="primary" @click="openAddVMModal">{{ $t('add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider/>
|
||||||
|
|
||||||
|
<a-list :loading="loading" style="min-height: 25px;">
|
||||||
|
<a-list-item v-for="rule in portForwardRules" :key="rule.id" class="rule">
|
||||||
|
<div class="rule-container">
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('privateport') }}</div>
|
||||||
|
<div>{{ rule.privateport }} - {{ rule.privateendport }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('publicport') }}</div>
|
||||||
|
<div>{{ rule.publicport }} - {{ rule.publicendport }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('protocol') }}</div>
|
||||||
|
<div>{{ rule.protocol | capitalise }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('state') }}</div>
|
||||||
|
<div>{{ rule.state }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule__item">
|
||||||
|
<div class="rule__title">{{ $t('vm') }}</div>
|
||||||
|
<div class="rule__title"></div>
|
||||||
|
<div><a-icon type="desktop"/> <router-link :to="{ path: '/vm/' + rule.virtualmachineid }">{{ rule.virtualmachinename }}</router-link> ({{ rule.vmguestip }})</div>
|
||||||
|
</div>
|
||||||
|
<div slot="actions">
|
||||||
|
<a-button shape="round" icon="tag" class="rule-action" @click="() => openTagsModal(rule.id)" />
|
||||||
|
<a-button shape="round" type="danger" icon="delete" class="rule-action" @click="deleteRule(rule)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
|
||||||
|
<a-modal title="Edit Tags" v-model="tagsModalVisible" :footer="null" :afterClose="closeModal">
|
||||||
|
<span v-show="tagsModalLoading" class="tags-modal-loading">
|
||||||
|
<a-icon type="loading"></a-icon>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="add-tags">
|
||||||
|
<div class="add-tags__input">
|
||||||
|
<p class="add-tags__label">{{ $t('key') }}</p>
|
||||||
|
<a-input v-model="newTag.key"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="add-tags__input">
|
||||||
|
<p class="add-tags__label">{{ $t('value') }}</p>
|
||||||
|
<a-input v-model="newTag.value"></a-input>
|
||||||
|
</div>
|
||||||
|
<a-button type="primary" @click="() => handleAddTag()">{{ $t('label.add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-divider></a-divider>
|
||||||
|
|
||||||
|
<div v-show="!tagsModalLoading" class="tags-container">
|
||||||
|
<div class="tags" v-for="(tag, index) in tags" :key="index">
|
||||||
|
<a-tag :key="index" :closable="true" :afterClose="() => handleDeleteTag(tag)">
|
||||||
|
{{ tag.key }} = {{ tag.value }}
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-button class="add-tags-done" @click="tagsModalVisible = false" type="primary">{{ $t('done') }}</a-button>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
title="Add VM"
|
||||||
|
v-model="addVmModalVisible"
|
||||||
|
class="vm-modal"
|
||||||
|
width="60vw"
|
||||||
|
@ok="addRule"
|
||||||
|
:okButtonProps="{ props:
|
||||||
|
{disabled: newRule.virtualmachineid === null } }"
|
||||||
|
@cancel="closeModal"
|
||||||
|
>
|
||||||
|
|
||||||
|
<a-icon v-if="addVmModalLoading" type="loading"></a-icon>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div class="vm-modal__header">
|
||||||
|
<span style="min-width: 200px;">{{ $t('name') }}</span>
|
||||||
|
<span>{{ $t('instancename') }}</span>
|
||||||
|
<span>{{ $t('displayname') }}</span>
|
||||||
|
<span>{{ $t('ip') }}</span>
|
||||||
|
<span>{{ $t('account') }}</span>
|
||||||
|
<span>{{ $t('zone') }}</span>
|
||||||
|
<span>{{ $t('state') }}</span>
|
||||||
|
<span>{{ $t('select') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-radio-group v-model="newRule.virtualmachineid" style="width: 100%;" @change="fetchNics">
|
||||||
|
<div v-for="(vm, index) in vms" :key="index" class="vm-modal__item">
|
||||||
|
|
||||||
|
<span style="min-width: 200px;">
|
||||||
|
<span>
|
||||||
|
{{ vm.name }}
|
||||||
|
</span>
|
||||||
|
<a-icon v-if="addVmModalNicLoading" type="loading"></a-icon>
|
||||||
|
<a-select
|
||||||
|
v-else-if="!addVmModalNicLoading && newRule.virtualmachineid === vm.id"
|
||||||
|
v-model="newRule.vmguestip">
|
||||||
|
<a-select-option v-for="(nic, nicIndex) in nics" :key="nic" :value="nic">
|
||||||
|
{{ nic }}{{ nicIndex === 0 ? ' (Primary)' : null }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</span>
|
||||||
|
<span>{{ vm.instancename }}</span>
|
||||||
|
<span>{{ vm.displayname }}</span>
|
||||||
|
<span></span>
|
||||||
|
<span>{{ vm.account }}</span>
|
||||||
|
<span>{{ vm.zonename }}</span>
|
||||||
|
<span>{{ vm.state }}</span>
|
||||||
|
<a-radio :value="vm.id" />
|
||||||
|
</div>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { api } from '@/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inject: ['parentFetchData', 'parentToggleLoading'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
portForwardRules: [],
|
||||||
|
newRule: {
|
||||||
|
protocol: 'tcp',
|
||||||
|
privateport: null,
|
||||||
|
privateendport: null,
|
||||||
|
publicport: null,
|
||||||
|
publicendport: null,
|
||||||
|
openfirewall: false,
|
||||||
|
vmguestip: null,
|
||||||
|
virtualmachineid: null
|
||||||
|
},
|
||||||
|
tagsModalVisible: false,
|
||||||
|
selectedRule: null,
|
||||||
|
tags: [],
|
||||||
|
newTag: {
|
||||||
|
key: null,
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
tagsModalLoading: false,
|
||||||
|
addVmModalVisible: false,
|
||||||
|
addVmModalLoading: false,
|
||||||
|
addVmModalNicLoading: false,
|
||||||
|
vms: [],
|
||||||
|
nics: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resource: function (newItem, oldItem) {
|
||||||
|
if (!newItem || !newItem.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resource = newItem
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
capitalise: val => {
|
||||||
|
if (val === 'all') return 'All'
|
||||||
|
return val.toUpperCase()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
api('listPortForwardingRules', {
|
||||||
|
listAll: true,
|
||||||
|
ipaddressid: this.resource.id
|
||||||
|
}).then(response => {
|
||||||
|
this.portForwardRules = response.listportforwardingrulesresponse.portforwardingrule
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteRule (rule) {
|
||||||
|
this.loading = true
|
||||||
|
api('deletePortForwardingRule', { id: rule.id }).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.deleteportforwardingruleresponse.jobid,
|
||||||
|
successMessage: `Successfully removed Port Forwarding rule`,
|
||||||
|
successMethod: () => this.fetchData(),
|
||||||
|
errorMessage: 'Removing Port Forwarding rule failed',
|
||||||
|
errorMethod: () => this.fetchData(),
|
||||||
|
loadingMessage: `Deleting Port Forwarding rule...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => this.fetchData()
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.fetchData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addRule () {
|
||||||
|
this.loading = true
|
||||||
|
this.addVmModalVisible = false
|
||||||
|
api('createPortForwardingRule', {
|
||||||
|
...this.newRule,
|
||||||
|
ipaddressid: this.resource.id,
|
||||||
|
networkid: this.resource.associatednetworkid
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.createportforwardingruleresponse.jobid,
|
||||||
|
successMessage: `Successfully added new Port Forwarding rule`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.closeModal()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
errorMessage: 'Adding new Port Forwarding rule failed',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.closeModal()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
loadingMessage: `Adding new Port Forwarding rule...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.closeModal()
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.createportforwardingruleresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
this.fetchData()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetAllRules () {
|
||||||
|
this.newRule.protocol = 'tcp'
|
||||||
|
this.newRule.privateport = null
|
||||||
|
this.newRule.privateendport = null
|
||||||
|
this.newRule.publicport = null
|
||||||
|
this.newRule.publicendport = null
|
||||||
|
this.newRule.openfirewall = false
|
||||||
|
this.newRule.vmguestip = null
|
||||||
|
this.newRule.virtualmachineid = null
|
||||||
|
},
|
||||||
|
resetTagInputs () {
|
||||||
|
this.newTag.key = null
|
||||||
|
this.newTag.value = null
|
||||||
|
},
|
||||||
|
closeModal () {
|
||||||
|
this.selectedRule = null
|
||||||
|
this.tagsModalVisible = false
|
||||||
|
this.addVmModalVisible = false
|
||||||
|
this.newRule.virtualmachineid = null
|
||||||
|
this.addVmModalLoading = false
|
||||||
|
this.addVmModalNicLoading = false
|
||||||
|
this.nics = []
|
||||||
|
this.resetTagInputs()
|
||||||
|
this.resetAllRules()
|
||||||
|
},
|
||||||
|
openTagsModal (id) {
|
||||||
|
this.tagsModalLoading = true
|
||||||
|
this.selectedRule = id
|
||||||
|
this.tagsModalVisible = true
|
||||||
|
this.tags = []
|
||||||
|
this.resetTagInputs()
|
||||||
|
api('listTags', {
|
||||||
|
resourceId: id,
|
||||||
|
resourceType: 'PortForwardingRule',
|
||||||
|
listAll: true
|
||||||
|
}).then(response => {
|
||||||
|
this.tags = response.listtagsresponse.tag
|
||||||
|
this.tagsModalLoading = false
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleAddTag () {
|
||||||
|
this.tagsModalLoading = true
|
||||||
|
api('createTags', {
|
||||||
|
'tags[0].key': this.newTag.key,
|
||||||
|
'tags[0].value': this.newTag.value,
|
||||||
|
resourceIds: this.selectedRule,
|
||||||
|
resourceType: 'PortForwardingRule'
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.createtagsresponse.jobid,
|
||||||
|
successMessage: `Successfully added tag`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.openTagsModal(this.selectedRule)
|
||||||
|
},
|
||||||
|
errorMessage: 'Failed to add new tag',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
},
|
||||||
|
loadingMessage: `Adding tag...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.createtagsresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDeleteTag (tag) {
|
||||||
|
this.tagsModalLoading = true
|
||||||
|
api('deleteTags', {
|
||||||
|
'tags[0].key': tag.key,
|
||||||
|
'tags[0].value': tag.value,
|
||||||
|
resourceIds: this.selectedRule,
|
||||||
|
resourceType: 'PortForwardingRule'
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.deletetagsresponse.jobid,
|
||||||
|
successMessage: `Successfully removed tag`,
|
||||||
|
successMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.openTagsModal(this.selectedRule)
|
||||||
|
},
|
||||||
|
errorMessage: 'Failed to remove tag',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
},
|
||||||
|
loadingMessage: `Removing tag...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.deletetagsresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openAddVMModal () {
|
||||||
|
this.addVmModalVisible = true
|
||||||
|
this.addVmModalLoading = true
|
||||||
|
api('listVirtualMachines', {
|
||||||
|
listAll: true,
|
||||||
|
page: 1,
|
||||||
|
pagesize: 500,
|
||||||
|
networkid: this.resource.associatednetworkid,
|
||||||
|
account: this.resource.account,
|
||||||
|
domainid: this.resource.domainid
|
||||||
|
}).then(response => {
|
||||||
|
this.vms = response.listvirtualmachinesresponse.virtualmachine
|
||||||
|
this.addVmModalLoading = false
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchNics (e) {
|
||||||
|
this.addVmModalNicLoading = true
|
||||||
|
api('listNics', {
|
||||||
|
virtualmachineid: e.target.value,
|
||||||
|
networkid: this.resource.associatednetworkid
|
||||||
|
}).then(response => {
|
||||||
|
if (!response.listnicsresponse.nic || response.listnicsresponse.nic.length < 1) return
|
||||||
|
const nic = response.listnicsresponse.nic[0]
|
||||||
|
this.nics.push(nic.ipaddress)
|
||||||
|
if (nic.secondaryip && nic.secondaryip.length > 0) {
|
||||||
|
this.nics.push(...nic.secondaryip.map(ip => ip.ipaddress))
|
||||||
|
}
|
||||||
|
this.newRule.vmguestip = this.nics[0]
|
||||||
|
this.addVmModalNicLoading = false
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.closeModal()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.rule {
|
||||||
|
|
||||||
|
&-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/*flex: 1;*/
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
@media (min-width: 760px) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
.ant-select {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input-container {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
input {
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-action {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-tags-done {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-modal-loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
z-index: 1;
|
||||||
|
color: #1890ff;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vm-modal {
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
span,
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -16,25 +16,190 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="remoteAccessVpn">
|
||||||
TODO: VPN configure/detail tab view
|
<div>
|
||||||
|
<p>Your Remote Access VPN is currently enabled and can be accessed via the IP <strong>{{ remoteAccessVpn.publicip }}</strong></p>
|
||||||
|
<p>Your IPSec pre-shared key is <strong>{{ remoteAccessVpn.presharedkey }}</strong></p>
|
||||||
|
<a-divider/>
|
||||||
|
<a-button><router-link :to="{ path: '/vpnuser'}">Manage VPN Users</router-link></a-button>
|
||||||
|
<a-button style="margin-left: 10px" type="danger" @click="disableVpn = true">Disable VPN</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-modal v-model="disableVpn" :footer="null" oncancel="disableVpn = false" title="Disable Remove Access VPN">
|
||||||
|
<p>Are you sure you want to disable VPN?</p>
|
||||||
|
|
||||||
|
<a-divider></a-divider>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<a-button @click="() => disableVpn = false">Cancel</a-button>
|
||||||
|
<a-button type="primary" @click="handleDisableVpn">Yes</a-button>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<a-button type="primary" @click="enableVpn = true">Enable VPN</a-button>
|
||||||
|
|
||||||
|
<a-modal v-model="enableVpn" :footer="null" onCancel="enableVpn = false" title="Enable Remote Access VPN">
|
||||||
|
<p>Please confirm that you want Remote Access VPN enabled for this IP address.</p>
|
||||||
|
|
||||||
|
<a-divider></a-divider>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<a-button @click="() => enableVpn = false">Cancel</a-button>
|
||||||
|
<a-button type="primary" @click="handleCreateVpn">Yes</a-button>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { api } from '@/api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: '',
|
props: {
|
||||||
components: {
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
remoteAccessVpn: null,
|
||||||
|
enableVpn: false,
|
||||||
|
disableVpn: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inject: ['parentFetchData', 'parentToggleLoading'],
|
||||||
|
mounted () {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resource: function (newItem, oldItem) {
|
||||||
|
if (!newItem || !newItem.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resource = newItem
|
||||||
|
this.fetchData()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
api('listRemoteAccessVpns', {
|
||||||
|
publicipid: this.resource.id,
|
||||||
|
listAll: true
|
||||||
|
}).then(response => {
|
||||||
|
this.remoteAccessVpn = response.listremoteaccessvpnsresponse.remoteaccessvpn
|
||||||
|
? response.listremoteaccessvpnsresponse.remoteaccessvpn[0] : null
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleCreateVpn () {
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.enableVpn = false
|
||||||
|
api('createRemoteAccessVpn', {
|
||||||
|
publicipid: this.resource.id,
|
||||||
|
domainid: this.resource.domainid,
|
||||||
|
account: this.resource.account
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.createremoteaccessvpnresponse.jobid,
|
||||||
|
successMethod: result => {
|
||||||
|
const res = result.jobresult.remoteaccessvpn
|
||||||
|
this.$notification.success({
|
||||||
|
message: 'Status',
|
||||||
|
description:
|
||||||
|
`Your Remote Access VPN is currently enabled and can be accessed via the IP ${res.publicip}. Your IPSec pre-shared key is ${res.presharedkey}`,
|
||||||
|
duration: 0
|
||||||
|
})
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
},
|
||||||
|
errorMessage: 'Failed to enable VPN',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
},
|
||||||
|
loadingMessage: `Enabling VPN...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.createremoteaccessvpnresponse
|
||||||
|
? error.response.data.createremoteaccessvpnresponse.errortext : error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDisableVpn () {
|
||||||
|
this.parentToggleLoading()
|
||||||
|
this.disableVpn = false
|
||||||
|
api('deleteRemoteAccessVpn', {
|
||||||
|
publicipid: this.resource.id,
|
||||||
|
domainid: this.resource.domainid
|
||||||
|
}).then(response => {
|
||||||
|
this.$pollJob({
|
||||||
|
jobId: response.deleteremoteaccessvpnresponse.jobid,
|
||||||
|
successMessage: 'Successfully disabled VPN',
|
||||||
|
successMethod: () => {
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
},
|
||||||
|
errorMessage: 'Failed to disable VPN',
|
||||||
|
errorMethod: () => {
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
},
|
||||||
|
loadingMessage: `Disabling VPN...`,
|
||||||
|
catchMessage: 'Error encountered while fetching async job result',
|
||||||
|
catchMethod: () => {
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: `Error ${error.response.status}`,
|
||||||
|
description: error.response.data.deleteremoteaccessvpnresponse
|
||||||
|
? error.response.data.deleteremoteaccessvpnresponse.errortext : error.response.data.errorresponse.errortext
|
||||||
|
})
|
||||||
|
this.fetchData()
|
||||||
|
this.parentFetchData()
|
||||||
|
this.parentToggleLoading()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
button {
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user