diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java index b86f8cd317adafb137a89d0a72f590ca72559b21..4ec1e94ce514bc5597a6c9a973d6f1d11f821473 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java @@ -1427,8 +1427,6 @@ public class VmInstanceManagerImpl extends AbstractService implements String hostname = VmSystemTags.HOSTNAME.getTokenByTag(sysTag, VmSystemTags.HOSTNAME_TOKEN); validateHostname(sysTag, hostname); - List l3NetworkUuids = msg.getL3NetworkUuids(); - l3NetworkUuids.forEach(it->validateHostNameOnDefaultL3Network(sysTag, hostname, it)); } else if (VmSystemTags.STATIC_IP.isMatch(sysTag)) { validateStaticIp(sysTag); } @@ -1500,8 +1498,6 @@ public class VmInstanceManagerImpl extends AbstractService implements q.select(VmInstanceVO_.defaultL3NetworkUuid); q.add(VmInstanceVO_.uuid, Op.EQ, resourceUuid); String defaultL3Uuid = q.findValue(); - - validateHostNameOnDefaultL3Network(systemTag, hostname, defaultL3Uuid); } else if (VmSystemTags.STATIC_IP.isMatch(systemTag)) { validateStaticIp(systemTag); } else if (VmSystemTags.BOOT_ORDER.isMatch(systemTag)) { diff --git a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java index 15587b41676abb133ca52bb10558a7471349f109..da49ab667eb6fccfc49f05c940854df5d19eb938 100644 --- a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java +++ b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java @@ -431,6 +431,8 @@ public class SugonSdnController implements TfSdnController, SdnController { // 设置可分配IP池范围 AllocationPoolType allocationPoolType = new AllocationPoolType(startIp,endIp); ipamSubnetType.addAllocationPools(allocationPoolType); + // 设置分配IP从小到大 + ipamSubnetType.setAddrFromStart(true); // 封装实体 -> ObjectReference IpamSubnets ipamSubnets = new IpamSubnets(); ipamSubnets.addSubnets(ipamSubnetType); diff --git a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortClient.java b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortClient.java index 18be6e2e75692ce811000db7141cb5552ed72dfe..ad4e7a0455ffb404405aac6f754643eed8b08aa8 100644 --- a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortClient.java +++ b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortClient.java @@ -3,12 +3,18 @@ package org.zstack.sugonSdnController.controller.neutronClient; import org.apache.commons.collections.CollectionUtils; import org.bouncycastle.util.IPAddress; import org.zstack.core.db.Q; +import org.zstack.header.network.l3.L3NetworkVO; +import org.zstack.header.network.l3.L3NetworkVO_; import org.zstack.sdnController.header.SdnControllerConstant; import org.zstack.sdnController.header.SdnControllerVO; import org.zstack.sdnController.header.SdnControllerVO_; import org.zstack.sugonSdnController.controller.SugonSdnControllerGlobalProperty; -import org.zstack.sugonSdnController.controller.api.*; +import org.zstack.sugonSdnController.controller.api.ApiConnector; +import org.zstack.sugonSdnController.controller.api.ApiConnectorFactory; +import org.zstack.sugonSdnController.controller.api.ApiPropertyBase; +import org.zstack.sugonSdnController.controller.api.ObjectReference; import org.zstack.sugonSdnController.controller.api.types.*; +import org.zstack.utils.StringDSL; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; @@ -28,7 +34,7 @@ public class TfPortClient { return apiConnector; } - public TfPortResponse createPort(String l2Id, String l3Id, String mac, String ip, String tenantId, String vmInventeryId,String tfPortUuid) { + public TfPortResponse createPort(String l2Id, String l3Id, String mac, String ip, String tenantId, String vmInventeryId, String tfPortUuid) { TfPortRequestBody portRequestBodyEO = new TfPortRequestBody(); TfPortRequestData portRequestDataEO = new TfPortRequestData(); TfPortRequestContext portRequestContextEO = new TfPortRequestContext(); @@ -100,7 +106,7 @@ public class TfPortClient { // initialize port object VirtualMachineInterface port; try { - port = portNeutronToVnc(requestPortResourceEntity, netObj , tfPortUuid); + port = portNeutronToVnc(requestPortResourceEntity, netObj, tfPortUuid); } catch (IOException e) { throw new RuntimeException(e); } @@ -269,13 +275,13 @@ public class TfPortClient { } } - private VirtualMachineInterface portNeutronToVnc(TfPortRequestResource requestPortResourceEntity, VirtualNetwork virtualNetwork,String tfPortUUid) throws IOException { + private VirtualMachineInterface portNeutronToVnc(TfPortRequestResource requestPortResourceEntity, VirtualNetwork virtualNetwork, String tfPortUUid) throws IOException { String projectId = requestPortResourceEntity.getTenantId(); Project projectObj = getProjectObj(requestPortResourceEntity); IdPermsType idPermsType = new IdPermsType(); idPermsType.setEnable(true); String portUuid = String.valueOf(UUID.randomUUID()); - if(Objects.nonNull(tfPortUUid)){ + if (Objects.nonNull(tfPortUUid)){ portUuid = tfPortUUid; } VirtualMachineInterface portObj = new VirtualMachineInterface(); @@ -355,7 +361,7 @@ public class TfPortClient { return portObj; } - private boolean ipAddrInNetId(String ipAddr, String netId) throws IOException { + public boolean ipAddrInNetId(String ipAddr, String netId) throws IOException { ApiConnector apiConnector = getApiConnector(); VirtualNetwork virtualNetwork = null; @@ -537,8 +543,8 @@ public class TfPortClient { // disassociate any floating IP used by instance List> fipBackRefs = portObj.getFloatingIpBackRefs(); - if (CollectionUtils.isNotEmpty(fipBackRefs)){ - for (ObjectReference fipBackRef : fipBackRefs){ + if (CollectionUtils.isNotEmpty(fipBackRefs)) { + for (ObjectReference fipBackRef : fipBackRefs) { try { floatingipUpdate(fipBackRef.getUuid()); } catch (IOException e) { @@ -582,10 +588,10 @@ public class TfPortClient { if (CollectionUtils.isEmpty(portRefs)){ fipObj.setFixedIpAddress(null); } else { - VirtualMachineInterface portObj = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, portRefs.get(0).getUuid()); + VirtualMachineInterface portObj = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, portRefs.get(0).getUuid()); List> iipRefs = portObj.getInstanceIpBackRefs(); - if (CollectionUtils.isNotEmpty(iipRefs) && iipRefs.size() > 1){ - String msg = "Port "+ portObj.getUuid() + " has multiple fixed IP addresses. Must provide a specific IP address when assigning a floating IP."; + if (CollectionUtils.isNotEmpty(iipRefs) && iipRefs.size() > 1) { + String msg = "Port " + portObj.getUuid() + " has multiple fixed IP addresses. Must provide a specific IP address when assigning a floating IP."; throw new RuntimeException(msg); } if (CollectionUtils.isNotEmpty(iipRefs)){ @@ -601,20 +607,117 @@ public class TfPortClient { // check if port already has floating ip associated List> fipRefs = portObj.getFloatingIpBackRefs(); List fipIds = new ArrayList<>(); - if (CollectionUtils.isNotEmpty(fipRefs)){ - for (ObjectReference ref : fipRefs){ - if (!Objects.equals(fipObj.getUuid(), ref.getUuid())){ + if (CollectionUtils.isNotEmpty(fipRefs)) { + for (ObjectReference ref : fipRefs) { + if (!Objects.equals(fipObj.getUuid(), ref.getUuid())) { fipIds.add(ref.getUuid()); } } } - if (CollectionUtils.isNotEmpty(fipIds)){ + if (CollectionUtils.isNotEmpty(fipIds)) { for (String fipId : fipIds) { FloatingIp fipInstance = (FloatingIp) apiConnector.findById(FloatingIp.class, fipId); - if (fipInstance.getFixedIpAddress().equals(address)){ + if (fipInstance.getFixedIpAddress().equals(address)) { throw new RuntimeException("FloatingIPPortAlreadyAssociated: " + fipInstance.getAddress() + " && " + portObj); } } } } + + /** + * 检查ip是否在已经被占用 + * + * @param ipAddr IPv4地址 + * @param subnetId (三层网络)的UUID + * @return 占用-true; 未占用-false + */ + public boolean checkTfIpAvailability(String ipAddr, String subnetId) throws IOException { + ApiConnector apiConnector = getApiConnector(); + VirtualNetwork virtualNetwork = null; + L3NetworkVO l3Network = Q.New(L3NetworkVO.class).eq(L3NetworkVO_.uuid, subnetId).find(); + virtualNetwork = (VirtualNetwork) apiConnector.findById(VirtualNetwork.class, StringDSL.transToTfUuid(l3Network.getL2NetworkUuid())); + List> instanceIpBackRefs = null; + List> subnetListRefs = null; + if (Objects.nonNull(virtualNetwork)) { + instanceIpBackRefs = virtualNetwork.getInstanceIpBackRefs(); + subnetListRefs = virtualNetwork.getNetworkIpam(); + } + + if (Objects.nonNull(virtualNetwork.getRouterExternal()) && virtualNetwork.getRouterExternal()) { + // if external network, floating ips. + List> floatingIpPools = virtualNetwork.getFloatingIpPools(); + if (CollectionUtils.isNotEmpty(floatingIpPools)) { + for (ObjectReference floatingIpPool : floatingIpPools) { + FloatingIpPool floatingIpPoolObj = (FloatingIpPool) apiConnector.findById(FloatingIpPool.class, floatingIpPool.getUuid()); + List> floatingIps = floatingIpPoolObj.getFloatingIps(); + if (CollectionUtils.isNotEmpty(floatingIps)) { + for (ObjectReference fip : floatingIps) { + FloatingIp fipObj = (FloatingIp) apiConnector.findById(FloatingIp.class, fip.getUuid()); + if (fipObj.getAddress().equals(ipAddr)) { + return true; + } + } + } + } + } + } else { // else instance ips. + List ipObjects = null; + if (Objects.nonNull(apiConnector) && CollectionUtils.isNotEmpty(instanceIpBackRefs)) { + ipObjects = (List) apiConnector.getObjects(InstanceIp.class, instanceIpBackRefs); + } + // check all instance ips. + if (CollectionUtils.isNotEmpty(ipObjects)) { + for (InstanceIp ipObj : ipObjects) { + if (ipObj.getAddress().equals(ipAddr)) { + return true; + } + } + } + } + + // check all subnets' gateway/dns service address/host routes/dhcp relay servers .eg + if (CollectionUtils.isNotEmpty(subnetListRefs)) { + for (ObjectReference subnetListRef : subnetListRefs) { + List ipamSubnets = subnetListRef.getAttr().getIpamSubnets(); + if (CollectionUtils.isNotEmpty(ipamSubnets)) { + for (IpamSubnetType ipamSubnet : ipamSubnets) { + List ipamSubnetIpUseList = new ArrayList<>(); + ipamSubnetIpUseList.add(ipamSubnet.getDefaultGateway()); + ipamSubnetIpUseList.add(ipamSubnet.getDnsServerAddress()); + List dnsNameservers = ipamSubnet.getDnsNameservers(); + if (CollectionUtils.isNotEmpty(dnsNameservers)) { + ipamSubnetIpUseList.addAll(dnsNameservers); + } + List dhcpRelayServer = ipamSubnet.getDhcpRelayServer(); + if (CollectionUtils.isNotEmpty(dhcpRelayServer)) { + ipamSubnetIpUseList.addAll(dhcpRelayServer); + } + RouteTableType routeTableType = ipamSubnet.getHostRoutes(); + if (Objects.nonNull(routeTableType)) { + List routeTypes = routeTableType.getRoute(); + if (CollectionUtils.isNotEmpty(routeTypes)) { + for (RouteType routeType : routeTypes) { + String ip = routeType.getNextHop(); + if (Objects.nonNull(ip)) { + ipamSubnetIpUseList.add(ip); + } + } + } + } + if (ipamSubnetIpUseList.contains(ipAddr)) { + return true; + } + } + } + } + } + return false; + } + + public List listUsedIps(String networkUuid, String SubnetUuid) { + List tfPortIpEntityList = new ArrayList<>(); + + + return tfPortIpEntityList; + } } diff --git a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortIpEntity.java b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortIpEntity.java index cdb7710e7b4fdb22cc39e446e08ff38244929be9..0808ccd6090acb14eed8b80f59154a9350daf540 100644 --- a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortIpEntity.java +++ b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/neutronClient/TfPortIpEntity.java @@ -10,6 +10,16 @@ public class TfPortIpEntity { @SerializedName("ip_address") private String ipAddress; + private String workType; + + public String getWorkType() { + return workType; + } + + public void setWorkType(String workType) { + this.workType = workType; + } + public String getSubnetId() { return subnetId; } diff --git a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/network/TfL3Network.java b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/network/TfL3Network.java index 4f24bb472a1fc72bfbfa9aa26bd5d7e0ab651536..23ce7911ba7e4898b0f56aa4d83f985363e88d27 100644 --- a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/network/TfL3Network.java +++ b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/network/TfL3Network.java @@ -5,8 +5,6 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.Platform; import org.zstack.core.db.DatabaseFacade; -import org.zstack.sugonSdnController.controller.SugonSdnController; -import org.zstack.sugonSdnController.controller.SugonSdnControllerConstant; import org.zstack.core.db.Q; import org.zstack.header.core.Completion; import org.zstack.header.errorcode.ErrorCode; @@ -18,11 +16,14 @@ import org.zstack.sdnController.SdnController; import org.zstack.sdnController.SdnControllerManager; import org.zstack.sdnController.header.SdnControllerVO; import org.zstack.sdnController.header.SdnControllerVO_; +import org.zstack.sugonSdnController.controller.SugonSdnController; +import org.zstack.sugonSdnController.controller.SugonSdnControllerConstant; +import org.zstack.sugonSdnController.controller.neutronClient.TfPortClient; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import org.zstack.utils.network.IPv6Constants; import org.zstack.utils.network.NetworkUtils; - +import java.io.IOException; import static org.zstack.core.Platform.err; import static org.zstack.utils.network.NetworkUtils.getSubnetInfo; @@ -61,11 +62,31 @@ public class TfL3Network extends L3BasicNetwork { handle((APIAddHostRouteToL3NetworkMsg) msg); } else if (msg instanceof APIRemoveHostRouteFromL3NetworkMsg) { handle((APIRemoveHostRouteFromL3NetworkMsg) msg); + } else if (msg instanceof APICheckIpAvailabilityMsg) { + handle((APICheckIpAvailabilityMsg) msg); } else { super.handleMessage(msg); } } + private void handle(APICheckIpAvailabilityMsg msg) { + APICheckIpAvailabilityReply reply = new APICheckIpAvailabilityReply(); + CheckIpAvailabilityReply r = new CheckIpAvailabilityReply(); + TfPortClient tfPortClient = new TfPortClient(); + try { + boolean availability = tfPortClient.checkTfIpAvailability(msg.getIp(), msg.getL3NetworkUuid()); + r.setAvailable(!availability); + if (availability){ + r.setReason("IP address is already in use."); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + reply.setAvailable(r.isAvailable()); + reply.setReason(r.getReason()); + bus.reply(msg, reply); + } + private void handle(APIDeleteL3NetworkMsg msg){ APIDeleteL3NetworkEvent evt = new APIDeleteL3NetworkEvent(msg.getId()); // Get L3 Network from zstack db