| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| package org.apache.cloudstack.network.contrail.model; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import net.juniper.contrail.api.ApiConnector; |
| import net.juniper.contrail.api.ObjectReference; |
| import net.juniper.contrail.api.types.NetworkIpam; |
| import net.juniper.contrail.api.types.Project; |
| import net.juniper.contrail.api.types.SubnetType; |
| import net.juniper.contrail.api.types.VirtualNetwork; |
| import net.juniper.contrail.api.types.VirtualNetworkPolicyType; |
| import net.juniper.contrail.api.types.VnSubnetsType; |
| |
| import org.apache.cloudstack.network.contrail.management.ContrailManager; |
| import org.apache.log4j.Logger; |
| |
| import com.cloud.dc.VlanVO; |
| import com.cloud.dc.dao.VlanDao; |
| import com.cloud.exception.InternalErrorException; |
| import com.cloud.network.Network; |
| import com.cloud.network.Networks.TrafficType; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.utils.net.NetUtils; |
| |
| public class VirtualNetworkModel extends ModelObjectBase { |
| private static final Logger s_logger = Logger.getLogger(VirtualNetworkModel.class); |
| |
| private String _uuid; |
| private long _id; |
| private final TrafficType _trafficType; |
| |
| /* |
| * current state for object properties |
| */ |
| private boolean _initialized; |
| private String _name; |
| private String _prefix; |
| private String _gateway; |
| private String _projectId; |
| |
| /* |
| * cached API server objects |
| */ |
| private VirtualNetwork _vn; |
| private NetworkIpam _ipam; |
| |
| private FloatingIpPoolModel _fipPoolModel; |
| private NetworkPolicyModel _policyModel; |
| |
| public VirtualNetworkModel(Network network, String uuid, String name, TrafficType trafficType) { |
| _uuid = uuid; |
| _name = name; |
| _trafficType = trafficType; |
| if (network != null) { |
| _id = network.getId(); |
| } |
| |
| if (isDynamicNetwork()) { |
| assert _uuid != null : "uuid is must for dynamic networks"; |
| } else { |
| assert _name != null : "name is must for static networks"; |
| } |
| } |
| |
| /* |
| * Resynchronize internal state from the cloudstack DB object. |
| */ |
| public void build(ModelController controller, Network network) { |
| setProperties(controller, network); |
| } |
| |
| /** |
| * Determine whether this network is dynamically created by cloudstack or is created by default by the contrail |
| * API server. |
| * |
| * @return |
| */ |
| boolean isDynamicNetwork() { |
| return (_trafficType == TrafficType.Guest) || (_trafficType == TrafficType.Public); |
| } |
| |
| @Override |
| public int compareTo(ModelObject o) { |
| VirtualNetworkModel other; |
| try { |
| other = (VirtualNetworkModel)o; |
| } catch (ClassCastException ex) { |
| String clsname = o.getClass().getName(); |
| return VirtualNetworkModel.class.getName().compareTo(clsname); |
| } |
| |
| if (!isDynamicNetwork()) { |
| if (!other.isDynamicNetwork()) { |
| // name is not unique since both management and storage networks may map to ip-fabric |
| int cmp = _name.compareTo(other.getName()); |
| if (cmp != 0) { |
| return cmp; |
| } |
| return _trafficType.compareTo(other._trafficType); |
| } |
| return -1; |
| } else if (!other.isDynamicNetwork()) { |
| return 1; |
| } |
| |
| return _uuid.compareTo(other._uuid); |
| } |
| |
| @Override |
| public void delete(ModelController controller) throws IOException { |
| ApiConnector api = controller.getApiAccessor(); |
| for (ModelObject successor : successors()) { |
| successor.delete(controller); |
| } |
| |
| if (_policyModel != null) { |
| _policyModel.removeSuccessor(this); |
| } |
| |
| try { |
| api.delete(VirtualNetwork.class, _uuid); |
| } catch (IOException ex) { |
| s_logger.warn("virtual-network delete", ex); |
| } |
| } |
| |
| @Override |
| public void destroy(ModelController controller) throws IOException { |
| delete(controller); |
| |
| for (ModelObject successor : successors()) { |
| successor.destroy(controller); |
| } |
| clearSuccessors(); |
| } |
| |
| public String getName() { |
| return _name; |
| } |
| |
| public String getUuid() { |
| return _uuid; |
| } |
| |
| public VirtualNetwork getVirtualNetwork() { |
| return _vn; |
| } |
| |
| /** |
| * Initialize the object properties based on the DB object. |
| * Common code between plugin calls and DBSync. |
| */ |
| public void setProperties(ModelController controller, Network network) { |
| ContrailManager manager = controller.getManager(); |
| _name = manager.getCanonicalName(network); |
| _prefix = network.getCidr(); |
| _gateway = network.getGateway(); |
| |
| // For non-cloudstack managed network, find the uuid at this stage. |
| if (!isDynamicNetwork()) { |
| try { |
| _uuid = manager.findVirtualNetworkId(network); |
| } catch (IOException ex) { |
| s_logger.warn("Unable to read virtual-network", ex); |
| } |
| } |
| |
| _id = network.getId(); |
| |
| try { |
| _projectId = manager.getProjectId(network.getDomainId(), network.getAccountId()); |
| } catch (IOException ex) { |
| s_logger.warn("project read", ex); |
| throw new CloudRuntimeException(ex); |
| } |
| |
| _initialized = true; |
| } |
| |
| @Override |
| public void update(ModelController controller) throws InternalErrorException, IOException { |
| |
| assert _initialized; |
| |
| ApiConnector api = controller.getApiAccessor(); |
| VlanDao vlanDao = controller.getVlanDao(); |
| VirtualNetwork vn = _vn; |
| |
| if (!isDynamicNetwork()) { |
| _vn = (VirtualNetwork)controller.getApiAccessor().findById(VirtualNetwork.class, _uuid); |
| return; |
| } |
| |
| assert _uuid != null : "uuid is not set"; |
| |
| if (_vn == null) { |
| vn = _vn = (VirtualNetwork)controller.getApiAccessor().findById(VirtualNetwork.class, _uuid); |
| if (vn == null) { |
| vn = new VirtualNetwork(); |
| if (_projectId != null) { |
| Project project; |
| try { |
| project = (Project)api.findById(Project.class, _projectId); |
| } catch (IOException ex) { |
| s_logger.debug("project read", ex); |
| throw new CloudRuntimeException("Failed to read project", ex); |
| } |
| vn.setParent(project); |
| } |
| vn.setName(_name); |
| vn.setUuid(_uuid); |
| } |
| } |
| |
| if (_policyModel == null) { |
| vn.clearNetworkPolicy(); |
| } else if (!_policyModel.hasPolicyRules()) { |
| vn.clearNetworkPolicy(); |
| _policyModel.removeSuccessor(this); |
| } else { |
| vn.setNetworkPolicy(_policyModel.getPolicy(), new VirtualNetworkPolicyType( |
| new VirtualNetworkPolicyType.SequenceType(1, 0), null)); |
| } |
| |
| if (_ipam == null) { |
| NetworkIpam ipam = null; |
| try { |
| String ipam_id = api.findByName(NetworkIpam.class, null, "default-network-ipam"); |
| if (ipam_id == null) { |
| s_logger.debug("could not find default-network-ipam"); |
| return; |
| } |
| ipam = (NetworkIpam)api.findById(NetworkIpam.class, ipam_id); |
| if (ipam == null) { |
| s_logger.debug("could not find NetworkIpam with ipam_id: " + ipam_id); |
| return; |
| } |
| } catch (IOException ex) { |
| s_logger.error(ex); |
| return; |
| } |
| _ipam = ipam; |
| } |
| |
| if (_prefix != null) { |
| VnSubnetsType subnet = new VnSubnetsType(); |
| String[] addr_pair = _prefix.split("\\/"); |
| subnet.addIpamSubnets(new SubnetType(addr_pair[0], Integer.parseInt(addr_pair[1])), _gateway); |
| vn.setNetworkIpam(_ipam, subnet); |
| } else if (_trafficType == TrafficType.Public) { |
| vn.clearNetworkIpam(); |
| /* Subnet information for Public is stored in the vlan table */ |
| List<VlanVO> vlan_list = vlanDao.listVlansByNetworkId(_id); |
| for (VlanVO vlan : vlan_list) { |
| String cidr = NetUtils.ipAndNetMaskToCidr(vlan.getVlanGateway(), vlan.getVlanNetmask()); |
| int slash = cidr.indexOf('/'); |
| String ip_addr = cidr.substring(0, slash); |
| int plen = Integer.parseInt(cidr.substring(slash + 1)); |
| VnSubnetsType subnet = new VnSubnetsType(); |
| subnet.addIpamSubnets(new SubnetType(ip_addr, plen), vlan.getVlanGateway()); |
| vn.addNetworkIpam(_ipam, subnet); |
| } |
| } |
| |
| if (_vn == null) { |
| try { |
| api.create(vn); |
| } catch (Exception ex) { |
| s_logger.debug("virtual-network create", ex); |
| throw new CloudRuntimeException("Failed to create virtual-network", ex); |
| } |
| _vn = vn; |
| } else { |
| try { |
| api.update(vn); |
| } catch (IOException ex) { |
| s_logger.warn("virtual-network update", ex); |
| throw new CloudRuntimeException("Unable to update virtual-network object", ex); |
| } |
| } |
| |
| for (ModelObject successor : successors()) { |
| successor.update(controller); |
| } |
| } |
| |
| public void read(ModelController controller) { |
| ApiConnector api = controller.getApiAccessor(); |
| VlanDao vlanDao = controller.getVlanDao(); |
| try { |
| _vn = (VirtualNetwork)api.findById(VirtualNetwork.class, _uuid); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| if (_vn == null) { |
| return; |
| } |
| if (_ipam == null) { |
| NetworkIpam ipam = null; |
| try { |
| String ipam_id = api.findByName(NetworkIpam.class, null, "default-network-ipam"); |
| if (ipam_id == null) { |
| s_logger.debug("could not find default-network-ipam"); |
| return; |
| } |
| ipam = (NetworkIpam)api.findById(NetworkIpam.class, ipam_id); |
| if (ipam == null) { |
| s_logger.debug("could not find NetworkIpam with ipam_id: " + ipam_id); |
| return; |
| } |
| } catch (IOException ex) { |
| s_logger.error(ex); |
| return; |
| } |
| _ipam = ipam; |
| } |
| |
| if (_prefix != null) { |
| VnSubnetsType subnet = new VnSubnetsType(); |
| String[] addr_pair = _prefix.split("\\/"); |
| subnet.addIpamSubnets(new SubnetType(addr_pair[0], Integer.parseInt(addr_pair[1])), _gateway); |
| _vn.setNetworkIpam(_ipam, subnet); |
| } else if (_trafficType == TrafficType.Public) { |
| _vn.clearNetworkIpam(); |
| /* Subnet information for Public is stored in the vlan table */ |
| List<VlanVO> vlan_list = vlanDao.listVlansByNetworkId(_id); |
| for (VlanVO vlan : vlan_list) { |
| String cidr = NetUtils.ipAndNetMaskToCidr(vlan.getVlanGateway(), vlan.getVlanNetmask()); |
| int slash = cidr.indexOf('/'); |
| String ip_addr = cidr.substring(0, slash); |
| int plen = Integer.parseInt(cidr.substring(slash + 1)); |
| VnSubnetsType subnet = new VnSubnetsType(); |
| subnet.addIpamSubnets(new SubnetType(ip_addr, plen), vlan.getVlanGateway()); |
| _vn.addNetworkIpam(_ipam, subnet); |
| } |
| } |
| return; |
| } |
| |
| @Override |
| public boolean verify(ModelController controller) { |
| assert _initialized : "initialized is false"; |
| assert _uuid != null : "uuid is not set"; |
| |
| ApiConnector api = controller.getApiAccessor(); |
| VlanDao vlanDao = controller.getVlanDao(); |
| |
| try { |
| _vn = (VirtualNetwork)api.findById(VirtualNetwork.class, _uuid); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| |
| if (_vn == null) { |
| return false; |
| } |
| |
| if (!isDynamicNetwork()) { |
| return true; |
| } |
| |
| List<String> dbSubnets = new ArrayList<String>(); |
| if (_trafficType == TrafficType.Public) { |
| List<VlanVO> vlan_list = vlanDao.listVlansByNetworkId(_id); |
| for (VlanVO vlan : vlan_list) { |
| String cidr = NetUtils.ipAndNetMaskToCidr(vlan.getVlanGateway(), vlan.getVlanNetmask()); |
| dbSubnets.add(vlan.getVlanGateway() + cidr); |
| } |
| } else { |
| dbSubnets.add(_gateway + _prefix); |
| } |
| |
| List<ObjectReference<VnSubnetsType>> ipamRefs = _vn.getNetworkIpam(); |
| List<String> vncSubnets = new ArrayList<String>(); |
| |
| if (ipamRefs == null && !dbSubnets.isEmpty()) { |
| return false; |
| } |
| |
| if (ipamRefs != null) { |
| for (ObjectReference<VnSubnetsType> ref : ipamRefs) { |
| VnSubnetsType vnSubnetType = ref.getAttr(); |
| if (vnSubnetType != null) { |
| List<VnSubnetsType.IpamSubnetType> subnets = vnSubnetType.getIpamSubnets(); |
| if (subnets != null && !subnets.isEmpty()) { |
| VnSubnetsType.IpamSubnetType ipamSubnet = subnets.get(0); |
| vncSubnets.add(ipamSubnet.getDefaultGateway() + ipamSubnet.getSubnet().getIpPrefix() + "/" + ipamSubnet.getSubnet().getIpPrefixLen()); |
| } |
| } |
| } |
| } |
| // unordered, no duplicates hence perform negation operation as set |
| Set<String> diff = new HashSet<String>(dbSubnets); |
| diff.removeAll(vncSubnets); |
| |
| if (!diff.isEmpty()) { |
| s_logger.debug("Subnets changed, network: " + _name + "; db: " + dbSubnets + ", vnc: " + vncSubnets + ", diff: " + diff); |
| return false; |
| } |
| |
| List<ObjectReference<VirtualNetworkPolicyType>> policyRefs = _vn.getNetworkPolicy(); |
| if ((policyRefs == null || policyRefs.isEmpty()) && _policyModel != null) { |
| return false; |
| } |
| |
| if ((policyRefs != null && !policyRefs.isEmpty()) && _policyModel == null) { |
| return false; |
| } |
| |
| if (policyRefs != null && !policyRefs.isEmpty() && _policyModel != null) { |
| ObjectReference<VirtualNetworkPolicyType> ref = policyRefs.get(0); |
| if (!ref.getUuid().equals(_policyModel.getUuid())) { |
| return false; |
| } |
| } |
| |
| for (ModelObject successor : successors()) { |
| if (!successor.verify(controller)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean compare(ModelController controller, ModelObject o) { |
| VirtualNetworkModel latest; |
| assert _vn != null : "vnc virtual network current is not initialized"; |
| |
| try { |
| latest = (VirtualNetworkModel)o; |
| } catch (ClassCastException ex) { |
| s_logger.warn("Invalid model object is passed to cast to VirtualNetworkModel"); |
| return false; |
| } |
| |
| try { |
| latest.read(controller); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| return false; |
| } |
| assert latest._vn != null : "vnc virtual network new is not initialized"; |
| |
| List<ObjectReference<VnSubnetsType>> currentIpamRefs = _vn.getNetworkIpam(); |
| List<ObjectReference<VnSubnetsType>> newIpamRefs = latest._vn.getNetworkIpam(); |
| List<String> currentSubnets = new ArrayList<String>(); |
| List<String> newSubnets = new ArrayList<String>(); |
| |
| if ((currentIpamRefs == null && newIpamRefs != null) || (currentIpamRefs != null && newIpamRefs == null)) { //Check for existence only |
| s_logger.debug("ipams differ: current=" + currentIpamRefs + ", new=" + newIpamRefs); |
| return false; |
| } |
| if (currentIpamRefs == null) { |
| return true; |
| } |
| |
| for (ObjectReference<VnSubnetsType> ref : currentIpamRefs) { |
| VnSubnetsType vnSubnetType = ref.getAttr(); |
| if (vnSubnetType != null) { |
| List<VnSubnetsType.IpamSubnetType> subnets = vnSubnetType.getIpamSubnets(); |
| if (subnets != null && !subnets.isEmpty()) { |
| VnSubnetsType.IpamSubnetType ipamSubnet = subnets.get(0); |
| currentSubnets.add(ipamSubnet.getDefaultGateway() + ipamSubnet.getSubnet().getIpPrefix() + "/" + ipamSubnet.getSubnet().getIpPrefixLen()); |
| } |
| } |
| } |
| |
| for (ObjectReference<VnSubnetsType> ref : newIpamRefs) { |
| VnSubnetsType vnSubnetType = ref.getAttr(); |
| if (vnSubnetType != null) { |
| List<VnSubnetsType.IpamSubnetType> subnets = vnSubnetType.getIpamSubnets(); |
| if (subnets != null && !subnets.isEmpty()) { |
| VnSubnetsType.IpamSubnetType ipamSubnet = subnets.get(0); |
| newSubnets.add(ipamSubnet.getDefaultGateway() + ipamSubnet.getSubnet().getIpPrefix() + "/" + ipamSubnet.getSubnet().getIpPrefixLen()); |
| } |
| } |
| } |
| |
| Set<String> diff = new HashSet<String>(currentSubnets); |
| diff.removeAll(newSubnets); |
| |
| if (!diff.isEmpty()) { |
| s_logger.debug("Subnets differ, network: " + _name + "; db: " + currentSubnets + ", vnc: " + newSubnets + ", diff: " + diff); |
| return false; |
| } |
| |
| List<ObjectReference<VirtualNetworkPolicyType>> currentPolicyRefs = _vn.getNetworkPolicy(); |
| List<ObjectReference<VirtualNetworkPolicyType>> latestPolicyRefs = latest._vn.getNetworkPolicy(); |
| |
| if (currentPolicyRefs == null && latestPolicyRefs == null) { |
| return true; |
| } |
| |
| if ((currentPolicyRefs == null && latestPolicyRefs != null) || (currentPolicyRefs != null |
| && latestPolicyRefs == null)) { |
| return false; |
| } |
| |
| if ((currentPolicyRefs != null && latestPolicyRefs != null) && (currentPolicyRefs.size() != latestPolicyRefs.size())) { |
| return false; |
| } |
| |
| if ((currentPolicyRefs != null && latestPolicyRefs != null) && currentPolicyRefs.isEmpty() |
| && latestPolicyRefs.isEmpty()) { |
| return true; |
| } |
| |
| //both must be non empty lists |
| ObjectReference<VirtualNetworkPolicyType> ref1 = null; |
| |
| if (currentPolicyRefs != null) { |
| ref1 = currentPolicyRefs.get(0); |
| } |
| |
| ObjectReference<VirtualNetworkPolicyType> ref2 = null; |
| |
| if (latestPolicyRefs != null) { |
| ref2 = latestPolicyRefs.get(0); |
| } |
| |
| if (ref1 == null && ref2 == null) { |
| return true; |
| } |
| |
| if ((ref1 != null && ref2 == null) || (ref1 == null && ref2 != null)) { |
| return false; |
| } |
| |
| if ((ref1 != null && ref2 != null) && ((ref1.getUuid() != null && ref2.getUuid() == null) |
| || (ref1.getUuid() == null && ref2.getUuid() != null))) { |
| return false; |
| } |
| if ((ref1 != null && ref2 != null) && (ref1.getUuid() == null && ref2.getUuid() == null)) { |
| return true; |
| } |
| if ((ref1 != null && ref2 != null) && !ref1.getUuid().equals(ref2.getUuid())) { |
| return false; |
| } |
| return true; |
| } |
| |
| public FloatingIpPoolModel getFipPoolModel() { |
| return _fipPoolModel; |
| } |
| |
| public void setFipPoolModel(FloatingIpPoolModel fipPoolModel) { |
| _fipPoolModel = fipPoolModel; |
| } |
| |
| public NetworkPolicyModel getNetworkPolicyModel() { |
| return _policyModel; |
| } |
| |
| public void addToNetworkPolicy(NetworkPolicyModel policyModel) { |
| if (_policyModel != null) { |
| _policyModel.removeSuccessor(this); |
| } |
| _policyModel = policyModel; |
| if (_policyModel != null) { |
| _policyModel.addSuccessor(this); |
| } |
| } |
| } |