This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 0bab0db881b Introducing concept of domain VPCs (#7153)
0bab0db881b is described below
commit 0bab0db881b2e085a472c167d0fed0048ceca559
Author: GaOrtiga <[email protected]>
AuthorDate: Sat Jul 29 15:06:49 2023 -0300
Introducing concept of domain VPCs (#7153)
Co-authored-by: Gabriel Ortiga Fernandes <[email protected]>
Co-authored-by: Lopez <[email protected]>
---
.../api/command/user/network/ListNetworksCmd.java | 8 ++---
.../src/main/java/com/cloud/vm/dao/UserVmDao.java | 1 +
.../main/java/com/cloud/vm/dao/UserVmDaoImpl.java | 12 +++++++
.../main/java/com/cloud/api/ApiResponseHelper.java | 37 ++++++++++++++--------
.../com/cloud/network/IpAddressManagerImpl.java | 35 ++++++++++----------
.../network/lb/LoadBalancingRulesManagerImpl.java | 2 +-
.../java/com/cloud/network/vpc/VpcManagerImpl.java | 21 ++++++++----
ui/src/components/view/ListView.vue | 5 ++-
ui/src/config/section/network.js | 4 +--
ui/src/views/network/EnableStaticNat.vue | 7 +---
ui/src/views/network/LoadBalancing.vue | 7 ++--
ui/src/views/network/PortForwarding.vue | 9 ++----
12 files changed, 85 insertions(+), 63 deletions(-)
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
index f370c037814..c1e85a9b4c3 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
@@ -235,11 +235,11 @@ public class ListNetworksCmd extends
BaseListRetrieveOnlyResourceCountCmd implem
private void updateNetworkResponse(List<NetworkResponse> response) {
for (NetworkResponse networkResponse : response) {
ResourceIcon resourceIcon =
resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Network,
networkResponse.getId());
- if (resourceIcon == null) {
+ if (resourceIcon == null && networkResponse.getVpcId() != null) {
resourceIcon =
resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Vpc,
networkResponse.getVpcId());
- if (resourceIcon == null) {
- continue;
- }
+ }
+ if (resourceIcon == null) {
+ continue;
}
ResourceIconResponse iconResponse =
_responseGenerator.createResourceIconResponse(resourceIcon);
networkResponse.setResourceIconResponse(iconResponse);
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
index abc8d80fbb2..39c65866658 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
@@ -103,4 +103,5 @@ public interface UserVmDao extends GenericDao<UserVmVO,
Long> {
List<UserVmVO> findByUserDataId(long userdataId);
+ List<UserVmVO> listByIds(List<Long> ids);
}
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
index 8a1039e83be..01439da24c5 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
@@ -71,6 +71,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO,
Long> implements Use
protected SearchBuilder<UserVmVO> RunningSearch;
protected SearchBuilder<UserVmVO> StateChangeSearch;
protected SearchBuilder<UserVmVO> AccountHostSearch;
+ protected SearchBuilder<UserVmVO> IdsSearch;
protected SearchBuilder<UserVmVO> DestroySearch;
protected SearchBuilder<UserVmVO> AccountDataCenterVirtualSearch;
@@ -135,6 +136,10 @@ public class UserVmDaoImpl extends
GenericDaoBase<UserVmVO, Long> implements Use
AccountSearch.and("account", AccountSearch.entity().getAccountId(),
SearchCriteria.Op.EQ);
AccountSearch.done();
+ IdsSearch = createSearchBuilder();
+ IdsSearch.and("ids", IdsSearch.entity().getId(), SearchCriteria.Op.IN);
+ IdsSearch.done();
+
HostSearch = createSearchBuilder();
HostSearch.and("host", HostSearch.entity().getHostId(),
SearchCriteria.Op.EQ);
HostSearch.done();
@@ -778,4 +783,11 @@ public class UserVmDaoImpl extends
GenericDaoBase<UserVmVO, Long> implements Use
sc.setParameters("userDataId", userdataId);
return listBy(sc);
}
+
+ @Override
+ public List<UserVmVO> listByIds(List<Long> ids) {
+ SearchCriteria<UserVmVO> sc = IdsSearch.create();
+ sc.setParameters("ids", ids.toArray());
+ return listBy(sc);
+ }
}
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 517ee8dd71c..568625c856b 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -33,6 +33,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -1019,13 +1020,9 @@ public class ApiResponseHelper implements
ResponseGenerator {
}
}
- if (ipAddr.getVpcId() != null) {
- Vpc vpc = ApiDBUtils.findVpcById(ipAddr.getVpcId());
- if (vpc != null) {
- ipResponse.setVpcId(vpc.getUuid());
- ipResponse.setVpcName(vpc.getName());
- }
- }
+
+ setVpcIdInResponse(ipAddr.getVpcId(), ipResponse::setVpcId,
ipResponse::setVpcName);
+
// Network id the ip is associated with (if associated networkId is
// null, try to get this information from vlan)
@@ -1095,6 +1092,22 @@ public class ApiResponseHelper implements
ResponseGenerator {
return ipResponse;
}
+
+ private void setVpcIdInResponse(Long vpcId, Consumer<String>
vpcUuidSetter, Consumer<String> vpcNameSetter) {
+ if (vpcId != null) {
+ Vpc vpc = ApiDBUtils.findVpcById(vpcId);
+ if (vpc != null) {
+ try {
+
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false,
vpc);
+ vpcUuidSetter.accept(vpc.getUuid());
+ } catch (PermissionDeniedException e) {
+ s_logger.debug("Not setting the vpcId to the response
because the caller does not have access to the VPC");
+ }
+ vpcNameSetter.accept(vpc.getName());
+ }
+ }
+ }
+
private void showVmInfoForSharedNetworks(boolean forVirtualNetworks,
IpAddress ipAddr, IPAddressResponse ipResponse) {
if (!forVirtualNetworks) {
NicVO nic =
ApiDBUtils.findByIp4AddressAndNetworkId(ipAddr.getAddress().toString(),
ipAddr.getNetworkId());
@@ -2565,13 +2578,9 @@ public class ApiResponseHelper implements
ResponseGenerator {
}
response.setSpecifyIpRanges(network.getSpecifyIpRanges());
- if (network.getVpcId() != null) {
- Vpc vpc = ApiDBUtils.findVpcById(network.getVpcId());
- if (vpc != null) {
- response.setVpcId(vpc.getUuid());
- response.setVpcName(vpc.getName());
- }
- }
+
+
+ setVpcIdInResponse(network.getVpcId(), response::setVpcId,
response::setVpcName);
setResponseAssociatedNetworkInformation(response, network.getId());
diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
index 8fae26eacf6..1352393be50 100644
--- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
@@ -1471,15 +1471,7 @@ public class IpAddressManagerImpl extends ManagerBase
implements IpAddressManage
throw new InvalidParameterValueException("Ip address can be
associated to the network with trafficType " + TrafficType.Guest);
}
- // Check that network belongs to IP owner - skip this check
- // - if zone is basic zone as there is just one guest network,
- // - if shared network in Advanced zone
- // - and it belongs to the system
- if (network.getAccountId() != owner.getId()) {
- if (zone.getNetworkType() != NetworkType.Basic &&
!(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() ==
Network.GuestType.Shared)) {
- throw new InvalidParameterValueException("The owner of the
network is not the same as owner of the IP");
- }
- }
+ validateNetworkAndIpOwnership(owner, ipToAssoc, network, zone);
if (zone.getNetworkType() == NetworkType.Advanced) {
// In Advance zone allow to do IP assoc only for Isolated networks
with source nat service enabled
@@ -1543,6 +1535,21 @@ public class IpAddressManagerImpl extends ManagerBase
implements IpAddressManage
}
}
+ /**
+ * Check that network belongs to IP owner - skip this check
+ * - if the IP belongs to the same VPC as the network
+ * - if zone is basic zone as there is just one guest network,
+ * - if shared network in Advanced zone
+ * - and it belongs to the system
+ */
+ private static void validateNetworkAndIpOwnership(Account owner,
IPAddressVO ipToAssoc, Network network, DataCenter zone) {
+ if (network.getAccountId() != owner.getId()) {
+ if (!network.getVpcId().equals(ipToAssoc.getVpcId()) &&
zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() !=
GuestType.Shared) {
+ throw new InvalidParameterValueException("The owner of the
network is not the same as owner of the IP");
+ }
+ }
+ }
+
/**
* Prevents associating an IP address to an allocated (unimplemented
network) network, throws an Exception otherwise
* @param owner Used to check if the user belongs to the Network
@@ -1625,15 +1632,7 @@ public class IpAddressManagerImpl extends ManagerBase
implements IpAddressManage
DataCenter zone = _entityMgr.findById(DataCenter.class,
network.getDataCenterId());
- // Check that network belongs to IP owner - skip this check
- // - if zone is basic zone as there is just one guest network,
- // - if shared network in Advanced zone
- // - and it belongs to the system
- if (network.getAccountId() != owner.getId()) {
- if (zone.getNetworkType() != NetworkType.Basic &&
!(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() ==
Network.GuestType.Shared)) {
- throw new InvalidParameterValueException("The owner of the
network is not the same as owner of the IP");
- }
- }
+ validateNetworkAndIpOwnership(owner, ipToAssoc, network, zone);
// Check if IP has any services (rules) associated in the network
List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
diff --git
a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index 3c51e1210b8..c9c0e83131a 100644
---
a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++
b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -2351,7 +2351,7 @@ public class LoadBalancingRulesManagerImpl<Type> extends
ManagerBase implements
}
}
- List<UserVmVO> userVms =
_vmDao.listVirtualNetworkInstancesByAcctAndNetwork(loadBalancer.getAccountId(),
loadBalancer.getNetworkId());
+ List<UserVmVO> userVms = _vmDao.listByIds(appliedInstanceIdList);
for (UserVmVO userVm : userVms) {
// if the VM is destroyed, being expunged, in an error state, or in
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 5de05a12d18..4456f10b546 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1855,10 +1855,8 @@ public class VpcManagerImpl extends ManagerBase
implements VpcManager, VpcProvis
}
}
- // 4) vpc and network should belong to the same owner
- if (vpc.getAccountId() != networkOwner.getId()) {
- throw new InvalidParameterValueException("Vpc " + vpc
+ " owner is different from the network owner " + networkOwner);
- }
+ // 4) Vpc's account should be able to access network
owner's account
+ CheckAccountsAccess(vpc, networkOwner);
// 5) network domain should be the same as VPC's
if
(!networkDomain.equalsIgnoreCase(vpc.getNetworkDomain())) {
@@ -1877,6 +1875,17 @@ public class VpcManagerImpl extends ManagerBase
implements VpcManager, VpcProvis
});
}
+ private void CheckAccountsAccess(Vpc vpc, Account networkAccount) {
+ Account vpcaccount = _accountMgr.getAccount(vpc.getAccountId());
+ try {
+ _accountMgr.checkAccess(vpcaccount, null, false, networkAccount);
+ }
+ catch (PermissionDeniedException e) {
+ s_logger.error(e.getMessage());
+ throw new InvalidParameterValueException(String.format("VPC owner
does not have access to account [%s].", networkAccount.getAccountName()));
+ }
+ }
+
public List<VpcProvider> getVpcElements() {
if (vpcElements == null) {
vpcElements = new ArrayList<VpcProvider>();
@@ -2879,11 +2888,11 @@ public class VpcManagerImpl extends ManagerBase
implements VpcManager, VpcProvis
}
// check permissions
- _accountMgr.checkAccess(caller, null, true, owner, vpc);
+ _accountMgr.checkAccess(caller, null, false, owner, vpc);
s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);
- final boolean isSourceNatFinal =
isSrcNatIpRequired(vpc.getVpcOfferingId()) &&
getExistingSourceNatInVpc(owner.getId(), vpcId) == null;
+ final boolean isSourceNatFinal =
isSrcNatIpRequired(vpc.getVpcOfferingId()) &&
getExistingSourceNatInVpc(vpc.getAccountId(), vpcId) == null;
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus
status) {
diff --git a/ui/src/components/view/ListView.vue
b/ui/src/components/view/ListView.vue
index 78d312e4e93..69dc3a1c559 100644
--- a/ui/src/components/view/ListView.vue
+++ b/ui/src/components/view/ListView.vue
@@ -216,7 +216,10 @@
<router-link :to="{ path: '/guestnetwork/' + record.associatednetworkid
}">{{ text }}</router-link>
</template>
<template v-if="column.key === 'vpcname'">
- <router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text
}}</router-link>
+ <a v-if="record.vpcid">
+ <router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text
}}</router-link>
+ </a>
+ <span v-else>{{ text }}</span>
</template>
<template v-if="column.key === 'hostname'">
<router-link v-if="record.hostid" :to="{ path: '/host/' + record.hostid
}">{{ text }}</router-link>
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index 26cd469a920..b5ebc0f8694 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -60,7 +60,7 @@ export default {
}, {
name: 'egress.rules',
component: shallowRef(defineAsyncComponent(() =>
import('@/views/network/EgressRulesTab.vue'))),
- show: (record, route, user) => { return record.type === 'Isolated' &&
!('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis &&
(['Admin', 'DomainAdmin'].includes(user.roletype) || record.account ===
user.account || record.projectid) }
+ show: (record, route, user) => { return record.type === 'Isolated' &&
!('vpcname' in record) && 'listEgressFirewallRules' in store.getters.apis &&
(['Admin', 'DomainAdmin'].includes(user.roletype) || record.account ===
user.account || record.projectid) }
}, {
name: 'ip.v6.firewall',
component: shallowRef(defineAsyncComponent(() =>
import('@/views/network/Ipv6FirewallRulesTab.vue'))),
@@ -68,7 +68,7 @@ export default {
}, {
name: 'public.ip.addresses',
component: shallowRef(defineAsyncComponent(() =>
import('@/views/network/IpAddressesTab.vue'))),
- show: (record, route, user) => { return 'listPublicIpAddresses' in
store.getters.apis && (record.type === 'Shared' || (record.type === 'Isolated'
&& !('vpcid' in record) && (['Admin', 'DomainAdmin'].includes(user.roletype) ||
record.account === user.account || record.projectid))) }
+ show: (record, route, user) => { return 'listPublicIpAddresses' in
store.getters.apis && (record.type === 'Shared' || (record.type === 'Isolated'
&& !('vpcname' in record) && (['Admin', 'DomainAdmin'].includes(user.roletype)
|| record.account === user.account || record.projectid))) }
}, {
name: 'virtual.routers',
component: shallowRef(defineAsyncComponent(() =>
import('@/views/network/RoutersTab.vue'))),
diff --git a/ui/src/views/network/EnableStaticNat.vue
b/ui/src/views/network/EnableStaticNat.vue
index 03bfc87828d..51d3e8f971b 100644
--- a/ui/src/views/network/EnableStaticNat.vue
+++ b/ui/src/views/network/EnableStaticNat.vue
@@ -191,8 +191,6 @@ export default {
pageSize: this.pageSize,
listAll: true,
networkid: this.resource.associatednetworkid,
- account: this.resource.account,
- domainid: this.resource.domainid,
keyword: this.searchQuery
}).then(response => {
this.vmCount = response.listvirtualmachinesresponse.count
@@ -210,8 +208,6 @@ export default {
pageSize: this.pageSize,
listAll: true,
networkid: e,
- account: this.resource.account,
- domainid: this.resource.domainid,
vpcid: this.resource.vpcid,
keyword: this.searchQuery
}).then(response => {
@@ -250,8 +246,7 @@ export default {
this.loading = true
api('listNetworks', {
vpcid: this.resource.vpcid,
- domainid: this.resource.domainid,
- account: this.resource.account,
+ isrecursive: true,
supportedservices: 'StaticNat'
}).then(response => {
this.networksList = response.listnetworksresponse.network
diff --git a/ui/src/views/network/LoadBalancing.vue
b/ui/src/views/network/LoadBalancing.vue
index a03bc38e71f..973a6240d10 100644
--- a/ui/src/views/network/LoadBalancing.vue
+++ b/ui/src/views/network/LoadBalancing.vue
@@ -875,9 +875,8 @@ export default {
this.tiers.loading = true
api('listNetworks', {
- account: this.resource.account,
- domainid: this.resource.domainid,
supportedservices: 'Lb',
+ isrecursive: true,
vpcid: this.resource.vpcid
}).then(json => {
this.tiers.data = json.listnetworksresponse.network || []
@@ -1475,9 +1474,7 @@ export default {
keyword: this.searchQuery,
page: this.vmPage,
pagesize: this.vmPageSize,
- networkid: networkId,
- account: this.resource.account,
- domainid: this.resource.domainid
+ networkid: networkId
}).then(response => {
this.vmCount = response.listvirtualmachinesresponse.count || 0
this.vms = response.listvirtualmachinesresponse.virtualmachine || []
diff --git a/ui/src/views/network/PortForwarding.vue
b/ui/src/views/network/PortForwarding.vue
index 22afcc3492f..d5362039874 100644
--- a/ui/src/views/network/PortForwarding.vue
+++ b/ui/src/views/network/PortForwarding.vue
@@ -499,10 +499,9 @@ export default {
this.selectedTier = null
this.tiers.loading = true
api('listNetworks', {
- account: this.resource.account,
- domainid: this.resource.domainid,
supportedservices: 'PortForwarding',
- vpcid: this.resource.vpcid
+ vpcid: this.resource.vpcid,
+ listall: this.resource.vpcid !== null
}).then(json => {
this.tiers.data = json.listnetworksresponse.network || []
if (this.tiers.data && this.tiers.data.length > 0) {
@@ -804,9 +803,7 @@ export default {
keyword: this.searchQuery,
page: this.vmPage,
pagesize: this.vmPageSize,
- networkid: networkId,
- account: this.resource.account,
- domainid: this.resource.domainid
+ networkid: networkId
}).then(response => {
this.vmCount = response.listvirtualmachinesresponse.count || 0
this.vms = response.listvirtualmachinesresponse.virtualmachine