Introducing concept of domain VPCs (#7153)

Co-authored-by: Gabriel Ortiga Fernandes <gabriel.fernandes@scclouds.com.br>
Co-authored-by: Lopez <rodrigo@scclouds.com.br>
This commit is contained in:
GaOrtiga 2023-07-29 15:06:49 -03:00 committed by GitHub
parent a738204e8a
commit 0bab0db881
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 85 additions and 63 deletions

View File

@ -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);

View File

@ -103,4 +103,5 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long> {
List<UserVmVO> findByUserDataId(long userdataId);
List<UserVmVO> listByIds(List<Long> ids);
}

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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>();

View File

@ -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

View File

@ -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) {

View File

@ -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>

View File

@ -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'))),

View File

@ -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

View File

@ -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 || []

View File

@ -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