blob: 7563714528bbfaef24a8aa5a56b5202238570b2e [file] [log] [blame]
// 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);
}
}
}