From e079a440a22442eba007b5eaabe2c6786e210c55 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Thu, 8 Jul 2021 23:58:03 -0700 Subject: [PATCH 01/10] Fix race condition in VPC Mgr delete subnet API --- .../subnet/controller/SubnetController.java | 24 ++++++------ ...t.java => HaveNonGatewayPortInSubnet.java} | 4 +- .../alcor/subnet/service/SubnetService.java | 2 +- .../service/implement/SubnetServiceImp.java | 23 +++++++----- .../vpcmanager/controller/VpcController.java | 37 ++++++------------- .../alcor/vpcmanager/dao/VpcRepository.java | 9 +++++ .../service/Impl/VpcDatabaseServiceImpl.java | 34 ++++++++++++++++- .../service/VpcDatabaseService.java | 1 + 8 files changed, 81 insertions(+), 53 deletions(-) rename services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/{HavePortInSubnet.java => HaveNonGatewayPortInSubnet.java} (91%) diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java index 049269cb2..cd0ac7304 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java @@ -518,18 +518,10 @@ public ResponseId deleteSubnetState(@PathVariable String projectId, @PathVariabl } String rangeId = null; - String ipV4RangeId = subnetEntity.getIpV4RangeId(); - String ipV6RangeId = subnetEntity.getIpV6RangeId(); - if (ipV4RangeId != null) { - rangeId = ipV4RangeId; + if (subnetEntity.getIpVersion() == 6) { + rangeId = subnetEntity.getIpV6RangeId(); } else { - rangeId = ipV6RangeId; - } - - // TODO: check if there is any gateway / non-gateway port for the subnet, waiting for PM new API - Boolean checkIfAnyNoneGatewayPortInSubnet = this.subnetService.checkIfAnyPortInSubnet(projectId, subnetId); - if (checkIfAnyNoneGatewayPortInSubnet) { - throw new HavePortInSubnet(); + rangeId = subnetEntity.getIpV4RangeId(); } // check if subnet bind any router @@ -545,7 +537,13 @@ public ResponseId deleteSubnetState(@PathVariable String projectId, @PathVariabl logger.warn(e.getMessage()); } - // TODO: delete gateway port in port manager. Temporary solution, need PM fix issue + // check if there is any non-gateway port for the subnet + Boolean checkIfAnyNoneGatewayPortInSubnet = this.subnetService.checkIfAnyNonGatewayPortInSubnet(projectId, subnetEntity); + if (checkIfAnyNoneGatewayPortInSubnet) { + throw new HaveNonGatewayPortInSubnet(); + } + + // delete gateway port in port manager GatewayPortDetail gatewayPortDetail = subnetEntity.getGatewayPortDetail(); if (gatewayPortDetail != null) { this.subnetToPortManagerService.deleteGatewayPort(projectId, gatewayPortDetail.getGatewayPortId()); @@ -559,7 +557,7 @@ public ResponseId deleteSubnetState(@PathVariable String projectId, @PathVariabl this.subnetDatabaseService.deleteSubnet(subnetId); - } catch (ParameterNullOrEmptyException | HavePortInSubnet | SubnetBindRouter e) { + } catch (ParameterNullOrEmptyException | HaveNonGatewayPortInSubnet | SubnetBindRouter e) { logger.error(e.getMessage()); throw new Exception(e); } diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/HavePortInSubnet.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/HaveNonGatewayPortInSubnet.java similarity index 91% rename from services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/HavePortInSubnet.java rename to services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/HaveNonGatewayPortInSubnet.java index 7fe245e09..b1f37f369 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/HavePortInSubnet.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/exception/HaveNonGatewayPortInSubnet.java @@ -18,6 +18,6 @@ free of charge, to any person obtaining a copy of this software and associated d import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; -@ResponseStatus(code= HttpStatus.CONFLICT, reason="There is some ports in the subnet, we can Not delete subnet") -public class HavePortInSubnet extends Exception { +@ResponseStatus(code= HttpStatus.CONFLICT, reason="There is some customer ports in the subnet, we can Not delete subnet") +public class HaveNonGatewayPortInSubnet extends Exception { } diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/SubnetService.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/SubnetService.java index 382880e8d..8d7c79639 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/SubnetService.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/SubnetService.java @@ -76,7 +76,7 @@ public void fallbackOperation (AtomicReference routeResponseAtomic public void deleteSubnetIdInVpc (String subnetId, String projectId, String vpcId) throws Exception; // check if there is any port in this subnet - public boolean checkIfAnyPortInSubnet (String projectId, String subnetId) throws SubnetIdIsNull; + public boolean checkIfAnyNonGatewayPortInSubnet(String projectId, SubnetEntity subnetEntity) throws SubnetIdIsNull; // check if subnet bind any routes public boolean checkIfSubnetBindAnyRouter(SubnetEntity subnetEntity); diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java index 85fa2f340..6088c18eb 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java @@ -40,6 +40,7 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.web.entity.route.*; import com.futurewei.alcor.web.entity.subnet.*; import com.futurewei.alcor.web.entity.vpc.VpcWebJson; +import io.netty.util.internal.StringUtil; import org.apache.commons.net.util.SubnetUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -388,13 +389,16 @@ public void deleteSubnetIdInVpc(String subnetId, String projectId, String vpcId) } @Override - public boolean checkIfAnyPortInSubnet(String projectId, String subnetId) throws SubnetIdIsNull { - if (subnetId == null) { + public boolean checkIfAnyNonGatewayPortInSubnet(String projectId, SubnetEntity subnetEntity) throws SubnetIdIsNull { + if (subnetEntity == null || StringUtil.isNullOrEmpty(subnetEntity.getId())) { throw new SubnetIdIsNull(); } - String portManagerServiceUrl = portUrl + "project/" + projectId + "/subnet-port-count/" + subnetId; - int portCount = restTemplate.getForObject(portManagerServiceUrl, Integer.class); - if (portCount == 0) { + + String portManagerServiceUrl = portUrl + "project/" + projectId + "/subnet-port-count/" + subnetEntity.getId(); + int portCount = restTemplate.getForObject(portManagerServiceUrl, Integer.class); + if (portCount == 0 && StringUtil.isNullOrEmpty(subnetEntity.getGatewayPortId())) { + return false; + } else if (portCount == 1 && !StringUtil.isNullOrEmpty(subnetEntity.getGatewayPortId())) { return false; } @@ -405,7 +409,7 @@ public boolean checkIfAnyPortInSubnet(String projectId, String subnetId) throws public boolean checkIfSubnetBindAnyRouter(SubnetEntity subnetEntity) { String attachedRouterId = subnetEntity.getAttachedRouterId(); - if (attachedRouterId == null || attachedRouterId.equals("")){ + if (attachedRouterId == null || attachedRouterId.equals("")) { return false; } @@ -414,7 +418,7 @@ public boolean checkIfSubnetBindAnyRouter(SubnetEntity subnetEntity) { @Override @DurationStatistics - public boolean checkIfCidrOverlap(String cidr,String projectId, String vpcId) throws FallbackException, ResourceNotFoundException, ResourcePersistenceException, CidrNotWithinNetworkCidr, CidrOverlapWithOtherSubnets { + public boolean checkIfCidrOverlap(String cidr, String projectId, String vpcId) throws FallbackException, ResourceNotFoundException, ResourcePersistenceException, CidrNotWithinNetworkCidr, CidrOverlapWithOtherSubnets { // get vpc and check with vpc cidr VpcWebJson vpcWebJson = verifyVpcId(projectId, vpcId); @@ -425,8 +429,7 @@ public boolean checkIfCidrOverlap(String cidr,String projectId, String vpcId) th throw new CidrNotWithinNetworkCidr(); } } - - + // get subnet list and check with subnets cidr List subnetIds = vpcWebJson.getNetwork().getSubnets(); for (String subnetId : subnetIds) { @@ -636,7 +639,7 @@ public void deleteIPRangeInPIM(String rangeId) { return; } - String ipManagerCreateRangeUrl = ipUrl + "range/"+ rangeId; + String ipManagerCreateRangeUrl = ipUrl + "range/" + rangeId; restTemplate.delete(ipManagerCreateRangeUrl); } diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java index 746d44731..a3d2c08de 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java @@ -68,7 +68,7 @@ public class VpcController { * @return vpc state * @throws Exception */ - @Rbac(resource ="vpc") + @Rbac(resource = "vpc") @FieldFilter(type = VpcEntity.class) @RequestMapping( method = GET, @@ -114,7 +114,7 @@ public VpcsWebJson createVpcStateBulk(@PathVariable String projectid, @RequestBo * @return vpc state * @throws Exception */ - @Rbac(resource ="vpc") + @Rbac(resource = "vpc") @RequestMapping( method = POST, value = {"/project/{projectid}/vpcs"}) @@ -194,7 +194,7 @@ public VpcWebJson createVpcState(@PathVariable String projectid, @RequestBody Vp * @return vpc state * @throws Exception */ - @Rbac(resource ="vpc") + @Rbac(resource = "vpc") @RequestMapping( method = PUT, value = {"/project/{projectid}/vpcs/{vpcid}"}) @@ -252,7 +252,7 @@ public VpcWebJson updateVpcStateByVpcId(@PathVariable String projectid, @PathVar * @return network id * @throws Exception */ - @Rbac(resource ="vpc") + @Rbac(resource = "vpc") @RequestMapping( method = DELETE, value = {"/project/{projectid}/vpcs/{vpcid}"}) @@ -290,7 +290,7 @@ public ResponseId deleteVpcStateByVpcId(@PathVariable String projectid, @PathVar * @return Map * @throws Exception */ - @Rbac(resource ="vpc") + @Rbac(resource = "vpc") @FieldFilter(type = VpcEntity.class) @RequestMapping( method = GET, @@ -298,8 +298,8 @@ public ResponseId deleteVpcStateByVpcId(@PathVariable String projectid, @PathVar @DurationStatistics public VpcsWebJson getVpcStatesByProjectId(@PathVariable String projectId) throws Exception { Map vpcStates = null; - Map requestParams = (Map)request.getAttribute(QUERY_ATTR_HEADER); - requestParams = requestParams == null ? request.getParameterMap():requestParams; + Map requestParams = (Map) request.getAttribute(QUERY_ATTR_HEADER); + requestParams = requestParams == null ? request.getParameterMap() : requestParams; Map queryParams = ControllerUtil.transformUrlPathParams(requestParams, VpcEntity.class); @@ -339,6 +339,7 @@ public Map getVpcCountAndAllVpcStates() throws CacheException { /** * Updates a network with subnet id + * * @param projectid * @param vpcid * @param subnetid @@ -381,11 +382,11 @@ public VpcWebJson addSubnetIdToVpcState(@PathVariable String projectid, @PathVar } return new VpcWebJson(inVpcState); - } /** * delete subnet id in a network + * * @param projectid * @param vpcid * @param subnetid @@ -398,35 +399,19 @@ public VpcWebJson addSubnetIdToVpcState(@PathVariable String projectid, @PathVar @DurationStatistics public VpcWebJson deleteSubnetIdInVpcState(@PathVariable String projectid, @PathVariable String vpcid, @PathVariable String subnetid) throws Exception { - VpcEntity inVpcState = new VpcEntity(); + VpcEntity inVpcState = null; try { RestPreconditionsUtil.verifyParameterNotNullorEmpty(projectid); RestPreconditionsUtil.verifyParameterNotNullorEmpty(vpcid); RestPreconditionsUtil.verifyParameterNotNullorEmpty(subnetid); - inVpcState = this.vpcDatabaseService.getByVpcId(vpcid); - if (inVpcState == null) { - throw new ResourceNotFoundException("Vpc not found : " + vpcid); - } - - List subnets = inVpcState.getSubnets(); - if (subnets == null || !subnets.contains(subnetid)) { - return new VpcWebJson(inVpcState); - } - subnets.remove(subnetid); - - inVpcState.setSubnets(subnets); - - this.vpcDatabaseService.addVpc(inVpcState); - - inVpcState = this.vpcDatabaseService.getByVpcId(vpcid); + inVpcState = this.vpcDatabaseService.deleteSubnetIdInVpc(vpcid, subnetid); } catch (ParameterNullOrEmptyException e) { throw new Exception(e); } return new VpcWebJson(inVpcState); - } } \ No newline at end of file diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/dao/VpcRepository.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/dao/VpcRepository.java index d02bc480e..b15491599 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/dao/VpcRepository.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/dao/VpcRepository.java @@ -18,6 +18,7 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.CacheException; import com.futurewei.alcor.common.db.CacheFactory; import com.futurewei.alcor.common.db.ICache; +import com.futurewei.alcor.common.db.Transaction; import com.futurewei.alcor.common.db.repo.ICacheRepository; import com.futurewei.alcor.common.logging.Logger; import com.futurewei.alcor.common.logging.LoggerFactory; @@ -43,6 +44,14 @@ public ICache getCache() { private ICache cache; + public Transaction startTransaction() throws CacheException { + return cache.getTransaction().start(); + } + + public void commitTransaction() throws CacheException { + cache.getTransaction().commit(); + } + @Autowired public VpcRepository(CacheFactory cacheFactory) { cache = cacheFactory.getCache(VpcEntity.class); diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java index 207188377..8368e7bca 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java @@ -18,15 +18,18 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.CacheException; import com.futurewei.alcor.common.db.ICache; import com.futurewei.alcor.common.exception.DatabasePersistenceException; +import com.futurewei.alcor.common.exception.ResourceNotFoundException; import com.futurewei.alcor.common.stats.DurationStatistics; import com.futurewei.alcor.vpcmanager.dao.VpcRepository; import com.futurewei.alcor.vpcmanager.service.VpcDatabaseService; import com.futurewei.alcor.web.entity.vpc.VpcEntity; +import com.futurewei.alcor.web.entity.vpc.VpcWebJson; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Map; @Service @@ -42,7 +45,7 @@ public class VpcDatabaseServiceImpl implements VpcDatabaseService { public VpcEntity getByVpcId(String vpcId) { try { return this.vpcRepository.findItem(vpcId); - }catch (Exception e) { + } catch (Exception e) { return null; } } @@ -75,6 +78,35 @@ public void deleteVpc(String id) throws CacheException { this.vpcRepository.deleteItem(id); } + @Override + public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws ResourceNotFoundException, DatabasePersistenceException, CacheException { + + VpcEntity currentVpcState = null; + + try { + this.vpcRepository.startTransaction(); + currentVpcState = getByVpcId(vpcId); + if (currentVpcState == null) { + throw new ResourceNotFoundException("Vpc not found : " + vpcId); + } + + List subnets = currentVpcState.getSubnets(); + if (subnets == null || !subnets.contains(subnetId)) { + return currentVpcState; + } + + subnets.remove(subnetId); + currentVpcState.setSubnets(subnets); + addVpc(currentVpcState); + } catch (ResourceNotFoundException | DatabasePersistenceException | CacheException e) { + throw e; + } finally { + this.vpcRepository.commitTransaction(); + } + + return currentVpcState; + } + @Override @DurationStatistics public ICache getCache() { diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java index 894b7dc4e..dba4a4a0c 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java @@ -31,6 +31,7 @@ public interface VpcDatabaseService { public Map getAllVpcs (Map queryParams) throws CacheException; public void addVpc (VpcEntity vpcState) throws DatabasePersistenceException; public void deleteVpc (String id) throws CacheException; + public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws ResourceNotFoundException, DatabasePersistenceException, CacheException; public ICache getCache (); } From 4831ad652004d1ae6777dd03003afabb76867ab4 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 00:15:56 -0700 Subject: [PATCH 02/10] Set subnset ip version as IPv4 --- .../java/com/futurewei/alcor/web/entity/subnet/SubnetEntity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/main/java/com/futurewei/alcor/web/entity/subnet/SubnetEntity.java b/web/src/main/java/com/futurewei/alcor/web/entity/subnet/SubnetEntity.java index 783db0a6f..75c99af2a 100644 --- a/web/src/main/java/com/futurewei/alcor/web/entity/subnet/SubnetEntity.java +++ b/web/src/main/java/com/futurewei/alcor/web/entity/subnet/SubnetEntity.java @@ -150,6 +150,7 @@ public SubnetEntity(String projectId, String vpcId, String id, String name, Stri super(projectId, id, name, null); this.vpcId = vpcId; this.cidr = cidr; + this.ipVersion = 4; } public SubnetEntity(String projectId, String id, String name, String description, String vpcId, From 4cb934ebb8f1cb5c7d7e3bb0ebf760212f2b5c80 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 08:42:52 -0700 Subject: [PATCH 03/10] Fix varible type --- .../com/futurewei/alcor/subnet/controller/SubnetController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java index 9571a6f98..a7e3aa1d8 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java @@ -487,7 +487,7 @@ public ResponseId deleteSubnetState(@PathVariable String projectId, @PathVariabl } // check if there is any non-gateway port for the subnet - Boolean checkIfAnyNoneGatewayPortInSubnet = this.subnetService.checkIfAnyNonGatewayPortInSubnet(projectId, subnetEntity); + boolean checkIfAnyNoneGatewayPortInSubnet = this.subnetService.checkIfAnyNonGatewayPortInSubnet(projectId, subnetEntity); if (checkIfAnyNoneGatewayPortInSubnet) { throw new HaveNonGatewayPortInSubnet(); } From ad62ef0dc3222fe47bb22f75e24b3c2dd49693f1 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 11:22:57 -0700 Subject: [PATCH 04/10] Add some logs --- .../alcor/subnet/service/implement/SubnetServiceImp.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java index 71fa6cb61..334248620 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java @@ -313,8 +313,10 @@ public boolean checkIfAnyNonGatewayPortInSubnet(String projectId, SubnetEntity s String portManagerServiceUrl = portUrl + "project/" + projectId + "/subnet-port-count/" + subnetEntity.getId(); int portCount = restTemplate.getForObject(portManagerServiceUrl, Integer.class); if (portCount == 0 && StringUtil.isNullOrEmpty(subnetEntity.getGatewayPortId())) { + logger.info("portCount == 0 && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); return false; } else if (portCount == 1 && !StringUtil.isNullOrEmpty(subnetEntity.getGatewayPortId())) { + logger.info("portCount == 1 && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); return false; } From f756eef3c53afbf27ba2d5703a48d59a877ddf92 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 11:25:44 -0700 Subject: [PATCH 05/10] Add more logs --- .../alcor/subnet/service/implement/SubnetServiceImp.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java index 334248620..b0e318bd5 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java @@ -320,6 +320,7 @@ public boolean checkIfAnyNonGatewayPortInSubnet(String projectId, SubnetEntity s return false; } + logger.info("portCount == " + portCount + " && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); return true; } From 8160d4a3ac12351990ab3db392faf8c52c239723 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 12:10:44 -0700 Subject: [PATCH 06/10] Revert the wrong fix to the non-gateway port count check --- .../alcor/subnet/service/implement/SubnetServiceImp.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java index b0e318bd5..1d1eae341 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/service/implement/SubnetServiceImp.java @@ -312,15 +312,12 @@ public boolean checkIfAnyNonGatewayPortInSubnet(String projectId, SubnetEntity s String portManagerServiceUrl = portUrl + "project/" + projectId + "/subnet-port-count/" + subnetEntity.getId(); int portCount = restTemplate.getForObject(portManagerServiceUrl, Integer.class); - if (portCount == 0 && StringUtil.isNullOrEmpty(subnetEntity.getGatewayPortId())) { - logger.info("portCount == 0 && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); - return false; - } else if (portCount == 1 && !StringUtil.isNullOrEmpty(subnetEntity.getGatewayPortId())) { - logger.info("portCount == 1 && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); + + logger.info("[checkIfAnyNonGatewayPortInSubnet]: portCount == " + portCount + " && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); + if (portCount == 0) { return false; } - logger.info("portCount == " + portCount + " && subnetEntity.getGatewayPortId() = " + subnetEntity.getGatewayPortId()); return true; } From 639a0cd1c5dc32a943ad99c7b1c488615769b092 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 16:10:30 -0700 Subject: [PATCH 07/10] Fix commit transaction from different thread issue --- .../alcor/vpcmanager/controller/VpcController.java | 2 +- .../service/Impl/VpcDatabaseServiceImpl.java | 14 +++++++++----- .../vpcmanager/service/VpcDatabaseService.java | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java index a3d2c08de..9e9541df5 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/controller/VpcController.java @@ -408,7 +408,7 @@ public VpcWebJson deleteSubnetIdInVpcState(@PathVariable String projectid, @Path inVpcState = this.vpcDatabaseService.deleteSubnetIdInVpc(vpcid, subnetid); - } catch (ParameterNullOrEmptyException e) { + } catch (Exception e) { throw new Exception(e); } diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java index 8368e7bca..17a89b713 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/Impl/VpcDatabaseServiceImpl.java @@ -17,6 +17,7 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.CacheException; import com.futurewei.alcor.common.db.ICache; +import com.futurewei.alcor.common.db.Transaction; import com.futurewei.alcor.common.exception.DatabasePersistenceException; import com.futurewei.alcor.common.exception.ResourceNotFoundException; import com.futurewei.alcor.common.stats.DurationStatistics; @@ -79,12 +80,12 @@ public void deleteVpc(String id) throws CacheException { } @Override - public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws ResourceNotFoundException, DatabasePersistenceException, CacheException { + public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws Exception { VpcEntity currentVpcState = null; - try { - this.vpcRepository.startTransaction(); + try (Transaction tx = this.vpcRepository.startTransaction()) { + currentVpcState = getByVpcId(vpcId); if (currentVpcState == null) { throw new ResourceNotFoundException("Vpc not found : " + vpcId); @@ -98,10 +99,13 @@ public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws Resou subnets.remove(subnetId); currentVpcState.setSubnets(subnets); addVpc(currentVpcState); + + tx.commit(); } catch (ResourceNotFoundException | DatabasePersistenceException | CacheException e) { throw e; - } finally { - this.vpcRepository.commitTransaction(); + } catch (Exception e) { + e.printStackTrace(); + throw e; } return currentVpcState; diff --git a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java index dba4a4a0c..f3c67de75 100644 --- a/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java +++ b/services/vpc_manager/src/main/java/com/futurewei/alcor/vpcmanager/service/VpcDatabaseService.java @@ -31,7 +31,7 @@ public interface VpcDatabaseService { public Map getAllVpcs (Map queryParams) throws CacheException; public void addVpc (VpcEntity vpcState) throws DatabasePersistenceException; public void deleteVpc (String id) throws CacheException; - public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws ResourceNotFoundException, DatabasePersistenceException, CacheException; + public VpcEntity deleteSubnetIdInVpc(String vpcId, String subnetId) throws Exception; public ICache getCache (); } From 85de8fbade8b33a4d70c5992431184b4f9bb84a8 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Fri, 9 Jul 2021 16:40:26 -0700 Subject: [PATCH 08/10] Update ignite config xml to support transaction in VpcRepository --- kubernetes/services/ignite_config.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kubernetes/services/ignite_config.xml b/kubernetes/services/ignite_config.xml index fb232be42..f89c32366 100644 --- a/kubernetes/services/ignite_config.xml +++ b/kubernetes/services/ignite_config.xml @@ -45,6 +45,15 @@ Copyright(c) 2020 Futurewei Cloud + + + + + + + + + From d6ed075881657ed5b4987e7a3bcaf4ebbfa4bab5 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Tue, 13 Jul 2021 12:00:09 -0700 Subject: [PATCH 09/10] Fix Ip mgr ignite misconfiguration --- kubernetes/services/ignite_ip_config.xml | 33 +++++++++++++++++++ .../subnet/controller/SubnetController.java | 10 ++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/kubernetes/services/ignite_ip_config.xml b/kubernetes/services/ignite_ip_config.xml index 6e66078cd..7d8ea3230 100644 --- a/kubernetes/services/ignite_ip_config.xml +++ b/kubernetes/services/ignite_ip_config.xml @@ -38,9 +38,42 @@ Copyright(c) 2020 Futurewei Cloud + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java index a7e3aa1d8..8e932ad79 100644 --- a/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java +++ b/services/subnet_manager/src/main/java/com/futurewei/alcor/subnet/controller/SubnetController.java @@ -243,8 +243,12 @@ public SubnetWebJson createSubnetState(@PathVariable String projectId, @RequestB // Synchronous blocking CompletableFuture allFuture = CompletableFuture.allOf(vpcFuture, ipFuture); allFuture.join(); + VpcWebJson vpcResponse = vpcFuture.join(); + String ipRangeId = ipFuture.join(); - logger.info("Total processing time:" + (System.currentTimeMillis() - start) + "ms"); + logger.info("[createSubnetState] Verified VPC id:" + vpcResponse.toString()); + logger.info("[createSubnetState] Allocated ip range:" + ipRangeId); + logger.info("[createSubnetState] Time to verify VPC id and allocate ip range:" + (System.currentTimeMillis() - start) + "ms"); this.subnetDatabaseService.addSubnet(inSubnetEntity); @@ -270,10 +274,10 @@ public SubnetWebJson createSubnetState(@PathVariable String projectId, @RequestB } if (Ipv4AddrUtil.formatCheck(gatewayIp)) { - inSubnetEntity.setIpV4RangeId(ipFuture.join()); + inSubnetEntity.setIpV4RangeId(ipRangeId); inSubnetEntity.setIpVersion(4); } else { - inSubnetEntity.setIpV6RangeId(ipFuture.join()); + inSubnetEntity.setIpV6RangeId(ipRangeId); inSubnetEntity.setIpVersion(6); } From 016aaf5d9de7b0115c79718e238a1ca4ce0cedf3 Mon Sep 17 00:00:00 2001 From: Liguang Xie Date: Wed, 21 Jul 2021 22:36:58 -0700 Subject: [PATCH 10/10] Add create ignite client with cache config and support in ip mgr --- .../common/config/IgniteConfiguration.java | 84 ----------------- .../alcor/common/db/CacheFactory.java | 5 ++ .../alcor/common/db/ICacheFactory.java | 8 ++ .../common/db/ignite/IgniteCacheFactory.java | 6 +- .../db/ignite/IgniteClientCacheFactory.java | 7 +- .../common/db/ignite/IgniteClientDbCache.java | 18 ++++ .../common/db/ignite/IgniteConfiguration.java | 9 +- .../alcor/common/db/ignite/IgniteDbCache.java | 39 +++++--- .../common/db/redis/RedisCacheFactory.java | 9 +- .../common/db/redis/RedisConfiguration.java | 4 - .../repo/IpAddrRangeRepo.java | 90 ++++++++++++++----- 11 files changed, 147 insertions(+), 132 deletions(-) delete mode 100644 lib/src/main/java/com/futurewei/alcor/common/config/IgniteConfiguration.java diff --git a/lib/src/main/java/com/futurewei/alcor/common/config/IgniteConfiguration.java b/lib/src/main/java/com/futurewei/alcor/common/config/IgniteConfiguration.java deleted file mode 100644 index 42bea39ab..000000000 --- a/lib/src/main/java/com/futurewei/alcor/common/config/IgniteConfiguration.java +++ /dev/null @@ -1,84 +0,0 @@ -/* -MIT License -Copyright(c) 2020 Futurewei Cloud - - Permission is hereby granted, - free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons - to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -package com.futurewei.alcor.common.config; - -import com.futurewei.alcor.common.logging.Logger; -import com.futurewei.alcor.common.logging.LoggerFactory; -import org.apache.ignite.Ignition; -import org.apache.ignite.client.ClientException; -import org.apache.ignite.client.IgniteClient; -import org.apache.ignite.configuration.ClientConfiguration; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.util.Assert; - -import java.util.logging.Level; - -//@Configuration -//@ComponentScan("com.futurewei.common.service") -//@EntityScan("com.futurewei.common.entity") -//@ConditionalOnProperty(prefix = "ignite", name = "host") -@Deprecated -public class IgniteConfiguration { - private static final Logger logger = LoggerFactory.getLogger(); - - @Value("${ignite.host}") - private String host; - - @Value("${ignite.port}") - private Integer port; - - @Value("${ignite.key-store-path:#{null}}") - private String keyStorePath; - - @Value("${ignite.key-store-password:#{null}}") - private String keyStorePassword; - - @Value("${ignite.trust-store-path:#{null}}") - private String trustStorePath; - - @Value("${ignite.trust-store-password:#{null}}") - private String trustStorePassword; - - @Bean - public IgniteClient igniteClientInstance() { - ClientConfiguration cfg = new ClientConfiguration() - .setAddresses(host + ":" + port); - - if (keyStorePath != null && keyStorePassword != null && - trustStorePath != null && trustStorePassword != null) { - cfg.setSslClientCertificateKeyStorePath(keyStorePath) - .setSslClientCertificateKeyStorePassword(keyStorePassword) - .setSslTrustCertificateKeyStorePath(trustStorePath) - .setSslTrustCertificateKeyStorePassword(trustStorePassword); - } - - IgniteClient igniteClient = null; - - try { - igniteClient = Ignition.startClient(cfg); - } catch (ClientException e) { - logger.log(Level.WARNING, "Start client failed:" + e.getMessage()); - } catch (Exception e) { - logger.log(Level.WARNING, "Unexpected failure:" + e.getMessage()); - } - - Assert.notNull(igniteClient, "IgniteClient is null"); - - return igniteClient; - } -} diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/CacheFactory.java b/lib/src/main/java/com/futurewei/alcor/common/db/CacheFactory.java index b546177b3..5008b7433 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/CacheFactory.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/CacheFactory.java @@ -21,6 +21,7 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.redis.RedisCacheFactory; import org.apache.ignite.Ignite; import org.apache.ignite.client.IgniteClient; +import org.apache.ignite.configuration.CacheConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; @@ -43,6 +44,10 @@ public ICache getCache(Class v, String cacheName) { return iCacheFactory.getCache(v, cacheName); } + public ICache getCache(Class v, CacheConfiguration cacheConfig) { + return iCacheFactory.getCache(v, cacheConfig); + } + public ICache getExpireCache(Class v, long timeout, TimeUnit timeUnit){ return iCacheFactory.getExpireCache(v, timeout, timeUnit); } diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ICacheFactory.java b/lib/src/main/java/com/futurewei/alcor/common/db/ICacheFactory.java index 5140d8aec..e5fb71505 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ICacheFactory.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ICacheFactory.java @@ -16,6 +16,8 @@ free of charge, to any person obtaining a copy of this software and associated d package com.futurewei.alcor.common.db; +import org.apache.ignite.configuration.CacheConfiguration; + import java.util.concurrent.TimeUnit; public interface ICacheFactory { @@ -34,6 +36,12 @@ public interface ICacheFactory { */ ICache getCache(Class v, String cacheName); + /** + * get a cache with cache name and configuration + * @return + */ + ICache getCache(Class v, CacheConfiguration cacheConfig); + /** * get a cache with auto set expire time * @return diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteCacheFactory.java b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteCacheFactory.java index d12c9d6f6..fda95f97e 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteCacheFactory.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteCacheFactory.java @@ -21,12 +21,12 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.IDistributedLock; import com.futurewei.alcor.common.db.Transaction; import org.apache.ignite.Ignite; +import org.apache.ignite.configuration.CacheConfiguration; import javax.cache.expiry.CreatedExpiryPolicy; import javax.cache.expiry.Duration; import javax.cache.expiry.ExpiryPolicy; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; public class IgniteCacheFactory implements ICacheFactory { @@ -50,6 +50,10 @@ public ICache getCache(Class v, String cacheName) { return new IgniteDbCache<>(ignite, cacheName); } + @Override + public ICache + getCache(Class v, CacheConfiguration cacheConfig) { return new IgniteDbCache<>(ignite, cacheConfig); } + @Override public ICache getExpireCache(Class v, long timeout, TimeUnit timeUnit) { ExpiryPolicy ep = CreatedExpiryPolicy.factoryOf(new Duration(timeUnit, timeout)).create(); diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientCacheFactory.java b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientCacheFactory.java index fa77ec7eb..f184aef55 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientCacheFactory.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientCacheFactory.java @@ -21,7 +21,7 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.IDistributedLock; import com.futurewei.alcor.common.db.Transaction; import org.apache.ignite.client.IgniteClient; -import org.apache.ignite.configuration.ClientConfiguration; +import org.apache.ignite.configuration.CacheConfiguration; import javax.cache.expiry.CreatedExpiryPolicy; import javax.cache.expiry.Duration; @@ -54,6 +54,11 @@ public ICache getCache(Class v, String cacheName) { return new IgniteClientDbCache<>(igniteClient, cacheName); } + @Override + public ICache getCache(Class v, CacheConfiguration cacheConfig) { + return new IgniteClientDbCache<>(igniteClient, cacheConfig); + } + @Override public ICache getExpireCache(Class v, long timeout, TimeUnit timeUnit) { ExpiryPolicy ep = CreatedExpiryPolicy.factoryOf(new Duration(timeUnit, timeout)).create(); diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientDbCache.java b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientDbCache.java index 52b160572..ac0b95508 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientDbCache.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteClientDbCache.java @@ -28,8 +28,10 @@ free of charge, to any person obtaining a copy of this software and associated d import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.ScanQuery; import org.apache.ignite.client.ClientCache; +import org.apache.ignite.client.ClientCacheConfiguration; import org.apache.ignite.client.ClientException; import org.apache.ignite.client.IgniteClient; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.lang.IgniteBiPredicate; import org.springframework.util.Assert; @@ -61,6 +63,22 @@ public IgniteClientDbCache(IgniteClient igniteClient, String name) { this.transaction = new IgniteClientTransaction(igniteClient); } + public IgniteClientDbCache(IgniteClient igniteClient, CacheConfiguration cacheConfig) { + try { + ClientCacheConfiguration clientCacheConfig = new ClientCacheConfiguration(); + clientCacheConfig.setName(cacheConfig.getName()); + clientCacheConfig.setAtomicityMode(cacheConfig.getAtomicityMode()); + logger.log(Level.INFO, "Getting or creating cache " + clientCacheConfig.getName() + " AtomicityMode is " + clientCacheConfig.getAtomicityMode()); + this.cache = igniteClient.getOrCreateCache(clientCacheConfig); + logger.log(Level.INFO, "Retrieved cache " + this.cache.getConfiguration().getName() + " AtomicityMode is " + this.cache.getConfiguration().getAtomicityMode()); + } catch (ClientException e) { + logger.log(Level.WARNING, "Create cache for client " + cacheConfig.getName() + " failed:" + e.getMessage()); + } + + Assert.notNull(this.cache, "Create cache for client " + cacheConfig.getName() + "failed"); + this.transaction = new IgniteClientTransaction(igniteClient); + } + public IgniteClientDbCache(IgniteClient igniteClient, String name, ExpiryPolicy ep) { try { this.cache = igniteClient.getOrCreateCache(name).withExpirePolicy(ep); diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java index 8d5dd3d0e..17fa9bd53 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java @@ -17,7 +17,6 @@ free of charge, to any person obtaining a copy of this software and associated d package com.futurewei.alcor.common.db.ignite; import com.futurewei.alcor.common.db.ICacheFactory; -import com.futurewei.alcor.common.db.IDistributedLockFactory; import com.futurewei.alcor.common.logging.Logger; import com.futurewei.alcor.common.logging.LoggerFactory; import org.apache.ignite.Ignite; @@ -81,8 +80,8 @@ public class IgniteConfiguration { @Bean @Primary - public ICacheFactory igniteClientFactoryInstance(){ - if(thinClientEnable){ + public ICacheFactory igniteClientFactoryInstance() { + if (thinClientEnable) { return new IgniteClientCacheFactory(this.getThinIgniteClient(), this.tryLockInterval, this.expireTime); @@ -145,10 +144,10 @@ private Ignite getIgniteClient(String instanceName) { SslContextFactory factory = new SslContextFactory(); factory.setKeyStoreFilePath(keyStorePath); factory.setKeyStorePassword(keyStorePassword.toCharArray()); - if(trustStorePath != null && trustStorePassword != null) { + if (trustStorePath != null && trustStorePassword != null) { factory.setTrustStoreFilePath(trustStorePath); factory.setTrustStorePassword(trustStorePassword.toCharArray()); - }else{ + } else { factory.setTrustManagers(SslContextFactory.getDisabledTrustManager()); } diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteDbCache.java b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteDbCache.java index b62820281..f7b7aa5a7 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteDbCache.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteDbCache.java @@ -17,7 +17,6 @@ free of charge, to any person obtaining a copy of this software and associated d package com.futurewei.alcor.common.db.ignite; import com.futurewei.alcor.common.db.CacheException; -import com.futurewei.alcor.common.db.ICache; import com.futurewei.alcor.common.db.Transaction; import com.futurewei.alcor.common.db.ignite.query.ScanQueryBuilder; import com.futurewei.alcor.common.db.ignite.query.MapPredicate; @@ -31,6 +30,7 @@ free of charge, to any person obtaining a copy of this software and associated d import org.apache.ignite.cache.query.Query; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.ScanQuery; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.lang.IgniteBiPredicate; import org.apache.ignite.transactions.TransactionException; import org.springframework.util.Assert; @@ -67,6 +67,21 @@ public IgniteDbCache(Ignite ignite, String name) { this.transaction = new IgniteTransaction(ignite); } + public IgniteDbCache(Ignite ignite, CacheConfiguration cfg) { + + try { + this.cache = ignite.getOrCreateCache(cfg); + } catch (javax.cache.CacheException e) { + this.cache = ignite.getOrCreateCache(cfg); + logger.log(Level.WARNING, "Create cache for client " + cfg + " failed:" + e.getMessage()); + } catch (Exception e) { + logger.log(Level.WARNING, "Unexpected failure:" + e.getMessage()); + } + + Assert.notNull(cache, "Create cache for client " + cfg + "failed"); + this.transaction = new IgniteTransaction(ignite); + } + public IgniteDbCache(Ignite client, String name, ExpiryPolicy ep) { try { @@ -162,19 +177,19 @@ public V get(IgniteBiPredicate igniteBiPredicate) throws CacheE QueryCursor> cursor = cache.withKeepBinary().query(ScanQueryBuilder.newScanQuery(igniteBiPredicate)); List> result = cursor.getAll(); - if(result.size() > 1){ + if (result.size() > 1) { throw new CacheException("more than one rows found!"); } - if(result.isEmpty()){ + if (result.isEmpty()) { return null; } E2 obj = result.get(0).getValue(); - if (obj instanceof BinaryObject){ - BinaryObject binaryObject = (BinaryObject)obj; + if (obj instanceof BinaryObject) { + BinaryObject binaryObject = (BinaryObject) obj; return binaryObject.deserialize(); - }else{ + } else { throw new CacheException("no support for object type:" + obj.getClass().getName()); } } @@ -190,16 +205,16 @@ public Map getAll(IgniteBiPredicate igniteBiPredicate) th QueryCursor> cursor = cache.withKeepBinary().query(ScanQueryBuilder.newScanQuery(igniteBiPredicate)); List> result = cursor.getAll(); - if(result.size() >= RESULT_THRESHOLD_SIZE){ + if (result.size() >= RESULT_THRESHOLD_SIZE) { throw new CacheException("too many rows found!"); } Map values = new HashMap<>(result.size()); - for(Cache.Entry entry: result){ + for (Cache.Entry entry : result) { E2 obj = entry.getValue(); - if (obj instanceof BinaryObject){ - BinaryObject binaryObject = (BinaryObject)obj; - values.put((K)entry.getKey(), binaryObject.deserialize()); - }else{ + if (obj instanceof BinaryObject) { + BinaryObject binaryObject = (BinaryObject) obj; + values.put((K) entry.getKey(), binaryObject.deserialize()); + } else { throw new CacheException("no support for object type:" + obj.getClass().getName()); } } diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisCacheFactory.java b/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisCacheFactory.java index 9ae4b842c..5881e67a9 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisCacheFactory.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisCacheFactory.java @@ -20,7 +20,7 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.ICacheFactory; import com.futurewei.alcor.common.db.IDistributedLock; import com.futurewei.alcor.common.db.Transaction; -import com.futurewei.alcor.common.entity.TokenEntity; +import org.apache.ignite.configuration.CacheConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; @@ -53,13 +53,18 @@ public ICache getCache(Class v, String cacheName) { return new RedisCache<>(template, cacheName); } + @Override + public ICache getCache(Class v, CacheConfiguration cacheConfig) { + return null; + } + @Override public ICache getExpireCache(Class v, long timeout, TimeUnit timeUnit) { RedisTemplate template = getRedisTemplate(v); return new RedisExpireCache<>(template, timeout, timeUnit); } - private RedisTemplate getRedisTemplate(Class v){ + private RedisTemplate getRedisTemplate(Class v) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(lettuceConnectionFactory); diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisConfiguration.java b/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisConfiguration.java index f24a56b1b..32d8e126e 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisConfiguration.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/redis/RedisConfiguration.java @@ -18,18 +18,14 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.common.db.ICacheFactory; -import com.futurewei.alcor.common.db.IDistributedLock; -import com.futurewei.alcor.common.db.IDistributedLockFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.StringRedisTemplate; @Configuration @ComponentScan("com.futurewei.alcor.common.db") diff --git a/services/private_ip_manager/src/main/java/com/futurewei/alcor/privateipmanager/repo/IpAddrRangeRepo.java b/services/private_ip_manager/src/main/java/com/futurewei/alcor/privateipmanager/repo/IpAddrRangeRepo.java index f6938bd5f..84e2f47de 100644 --- a/services/private_ip_manager/src/main/java/com/futurewei/alcor/privateipmanager/repo/IpAddrRangeRepo.java +++ b/services/private_ip_manager/src/main/java/com/futurewei/alcor/privateipmanager/repo/IpAddrRangeRepo.java @@ -29,6 +29,8 @@ free of charge, to any person obtaining a copy of this software and associated d import com.futurewei.alcor.web.entity.ip.IpAddrRequest; import com.futurewei.alcor.web.entity.ip.IpAddrUpdateRequest; import com.futurewei.alcor.web.entity.ip.IpVersion; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.configuration.CacheConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -149,7 +151,7 @@ private IpAddrAlloc doAllocateIpAddr(String vpcId, int ipVersion, String ipAddr) } IpAddrAlloc ipAddrAlloc = null; - for (String rangeId: vpcIpRange.getRanges()) { + for (String rangeId : vpcIpRange.getRanges()) { if (ipAddrAlloc != null) { break; } @@ -164,8 +166,12 @@ private IpAddrAlloc doAllocateIpAddr(String vpcId, int ipVersion, String ipAddr) } try { + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(rangeId)); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(rangeId)); + cacheFactory.getCache(IpAddrAlloc.class, cfg); ipAddrAlloc = ipAddrRange.allocate(ipAddrCache, ipAddr); } catch (Exception e) { LOG.warn("Allocate ip address from {} failed", ipAddrRange.getId()); @@ -184,6 +190,7 @@ private IpAddrAlloc doAllocateIpAddr(String vpcId, int ipVersion, String ipAddr) /** * Allocate a ip address from IpAddrRange repository + * * @param request Assign ip address request * @return Ip address assigned from ip range * @throws Exception Db operation or ip address assignment exception @@ -199,6 +206,7 @@ public synchronized IpAddrAlloc allocateIpAddr(IpAddrRequest request) throws Exc /** * Assign multiple ip addresses from IpAddrRange repository + * * @param requests The number of ip addresses that will be assigned from each ip range * @return Number of ip addresses assigned each ip range * @throws Exception Db operation or ip address assignment exception @@ -209,14 +217,18 @@ public synchronized Map> allocateIpAddrBulk(Map> result = new HashMap<>(); try (Transaction tx = ipAddrRangeCache.getTransaction().start()) { - for (Map.Entry entry: requests.entrySet()) { + for (Map.Entry entry : requests.entrySet()) { IpAddrRange ipAddrRange = ipAddrRangeCache.get(entry.getKey()); if (ipAddrRange == null) { throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(ipAddrRange.getId())); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(ipAddrRange.getId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); List ipAddrAllocs = ipAddrRange.allocateBulk(ipAddrCache, entry.getValue()); ipAddrRangeCache.put(ipAddrRange.getId(), ipAddrRange); @@ -236,8 +248,12 @@ private List doAllocateIpAddr(String rangeId, List i throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(rangeId)); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(rangeId)); + cacheFactory.getCache(IpAddrAlloc.class, cfg); List ips = ipRequests.stream() .map(IpAddrRequest::getIp) @@ -258,7 +274,7 @@ private List doAllocateIpAddr(String vpcId, int ipVersion, List requestIps = ips.subList(0, ips.size()); - for (String rangeId: vpcIpRange.getRanges()) { + for (String rangeId : vpcIpRange.getRanges()) { if (result.size() == ips.size()) { break; } @@ -272,9 +288,12 @@ private List doAllocateIpAddr(String vpcId, int ipVersion, List ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(rangeId)); + cacheFactory.getCache(IpAddrAlloc.class, cfg); List ipAddrAllocs = ipAddrRange.allocateBulk(ipAddrCache, requestIps); @@ -298,7 +317,7 @@ public synchronized List allocateIpAddrBulk(Map> vpcIpv6Requests) throws Exception { List result = new ArrayList<>(); try (Transaction tx = ipAddrRangeCache.getTransaction().start()) { - allocateIpAddrBulkMethod(rangeRequests,vpcIpv4Requests,vpcIpv6Requests,result); + allocateIpAddrBulkMethod(rangeRequests, vpcIpv4Requests, vpcIpv6Requests, result); tx.commit(); } @@ -313,8 +332,12 @@ public synchronized void modifyIpAddrState(String rangeId, String ipAddr, String throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(rangeId)); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(ipAddrRange.getId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); ipAddrRange.modifyIpAddrState(ipAddrCache, ipAddr, state); ipAddrRangeCache.put(ipAddrRange.getId(), ipAddrRange); @@ -326,7 +349,7 @@ public synchronized void modifyIpAddrState(String rangeId, String ipAddr, String @DurationStatistics public synchronized void releaseIpAddr(String rangeId, String ipAddr) throws Exception { try (Transaction tx = ipAddrRangeCache.getTransaction().start()) { - releaseIpAddrMethod(rangeId,ipAddr); + releaseIpAddrMethod(rangeId, ipAddr); tx.commit(); } } @@ -346,8 +369,12 @@ public synchronized IpAddrAlloc getIpAddr(String rangeId, String ipAddr) throws throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(rangeId)); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(ipAddrRange.getId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); return ipAddrRange.getIpAddr(ipAddrCache, ipAddr); } @@ -359,8 +386,12 @@ public synchronized Collection getIpAddrBulk(String rangeId) throws throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(rangeId)); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(ipAddrRange.getId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); return ipAddrRange.getIpAddrBulk(ipAddrCache); } @@ -437,8 +468,8 @@ public synchronized IpAddrRange getIpAddrRange(String rangeId) throws Exception } @DurationStatistics - public synchronized List updateIpAddr(IpAddrUpdateRequest request,Map> rangeToIpAddrList,Map> rangeRequests, - Map> vpcIpv4Requests,Map> vpcIpv6Requests) throws Exception { + public synchronized List updateIpAddr(IpAddrUpdateRequest request, Map> rangeToIpAddrList, Map> rangeRequests, + Map> vpcIpv4Requests, Map> vpcIpv6Requests) throws Exception { List result = null; try (Transaction tx = ipAddrRangeCache.getTransaction().start()) { @@ -452,7 +483,7 @@ public synchronized List updateIpAddr(IpAddrUpdateRequest request,M if (request.getNewIpAddrRequests().size() > 0) { result = new ArrayList<>(); if (request.getNewIpAddrRequests().size() > 1) { - allocateIpAddrBulkMethod(rangeRequests, vpcIpv4Requests, vpcIpv6Requests,result); + allocateIpAddrBulkMethod(rangeRequests, vpcIpv4Requests, vpcIpv6Requests, result); } else { IpAddrAlloc ipAddrAlloc = allocateIpAddrMethod(request.getNewIpAddrRequests().get(0)); result.add(ipAddrAlloc); @@ -463,15 +494,19 @@ public synchronized List updateIpAddr(IpAddrUpdateRequest request,M return result; } - private void releaseIpAddrBulkMethod(Map> requests) throws Exception{ - for (Map.Entry> entry: requests.entrySet()) { + private void releaseIpAddrBulkMethod(Map> requests) throws Exception { + for (Map.Entry> entry : requests.entrySet()) { IpAddrRange ipAddrRange = ipAddrRangeCache.get(entry.getKey()); if (ipAddrRange == null) { throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(ipAddrRange.getId())); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(ipAddrRange.getId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); ipAddrRange.releaseBulk(ipAddrCache, entry.getValue()); ipAddrRangeCache.put(ipAddrRange.getId(), ipAddrRange); @@ -484,8 +519,12 @@ private void releaseIpAddrMethod(String rangeId, String ipAddr) throws Exception throw new IpRangeNotFoundException(); } + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(rangeId)); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(ipAddrRange.getId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); ipAddrRange.release(ipAddrCache, ipAddr); ipAddrRangeCache.put(ipAddrRange.getId(), ipAddrRange); @@ -494,11 +533,11 @@ private void releaseIpAddrMethod(String rangeId, String ipAddr) throws Exception private void allocateIpAddrBulkMethod(Map> rangeRequests, Map> vpcIpv4Requests, Map> vpcIpv6Requests, List result) throws Exception { - for (Map.Entry> entry: rangeRequests.entrySet()) { + for (Map.Entry> entry : rangeRequests.entrySet()) { result.addAll(doAllocateIpAddr(entry.getKey(), entry.getValue())); } - for (Map.Entry> entry: vpcIpv4Requests.entrySet()) { + for (Map.Entry> entry : vpcIpv4Requests.entrySet()) { result.addAll(doAllocateIpAddr(entry.getKey(), IpVersion.IPV4.getVersion(), entry.getValue().stream() @@ -506,7 +545,7 @@ private void allocateIpAddrBulkMethod(Map> rangeRequ .collect(Collectors.toList()))); } - for (Map.Entry> entry: vpcIpv6Requests.entrySet()) { + for (Map.Entry> entry : vpcIpv6Requests.entrySet()) { result.addAll(doAllocateIpAddr(entry.getKey(), IpVersion.IPV6.getVersion(), entry.getValue().stream() @@ -525,8 +564,13 @@ private IpAddrAlloc allocateIpAddrMethod(IpAddrRequest request) throws Exception if (ipAddrRange == null) { throw new IpRangeNotFoundException(); } + + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(getIpAddrCacheName(ipAddrRange.getId())); + cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ICache ipAddrCache = - cacheFactory.getCache(IpAddrAlloc.class, getIpAddrCacheName(request.getRangeId())); + cacheFactory.getCache(IpAddrAlloc.class, cfg); ipAddrAlloc = ipAddrRange.allocate(ipAddrCache, request.getIp()); ipAddrRangeCache.put(ipAddrRange.getId(), ipAddrRange);