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

Reply via email to