/***************************************************************************
* Copyright (c) 2012-2015 VMware, Inc. All Rights Reserved.
* Licensed 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 com.vmware.bdd.entity;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Cascade;
import com.vmware.bdd.apitypes.NetworkDnsType;
import com.vmware.bdd.dal.impl.IpBlockDAO.EqualBlockTypePredicate;
import com.vmware.bdd.exception.NetworkException;
import com.vmware.bdd.utils.AuAssert;
import com.vmware.bdd.utils.ConfigInfo;
import com.vmware.bdd.utils.IpAddressUtil;
import org.hibernate.annotations.CascadeType;
@Entity
@SequenceGenerator(name = "IdSequence", sequenceName = "network_seq", allocationSize = 1)
@Table(name = "network")
public class NetworkEntity extends EntityBase implements Comparable<NetworkEntity> {
public enum AllocType {
DHCP, IP_POOL
}
private static final Logger logger = Logger.getLogger(NetworkEntity.class);
@Column(name = "name", unique = true, nullable = false)
private String name;
@Column(name = "port_group", nullable = false)
private String portGroup;
/**
* Use cascade save to simplify the code. Since we almost always need to
* update this when network is being modified, there is little overhead.
*/
@OneToMany(mappedBy = "network", fetch = FetchType.LAZY)
@Cascade({ CascadeType.SAVE_UPDATE, CascadeType.REMOVE })
private List<IpBlockEntity> ipBlocks;
@OneToMany(mappedBy = "networkEntity", fetch = FetchType.LAZY)
private Set<NicEntity> nics;
/**
* Related clusters which have assigned IPs, the relationship is only used
* for 'show details' of a network, and is built at the cluster creation side
* instead of inside alloc method. So this class does not guarantee that the
* cluster list exactly matches the list contained in IpBlockEntity list
* (though the cluster class should guarantee the correctness).
*/
@Enumerated(EnumType.STRING)
@Column(name = "alloc_type", nullable = false)
private AllocType allocType;
@Column(name = "netmask")
private String netmask;
@Column(name = "gateway")
private String gateway;
@Column(name = "dns1")
private String dns1;
@Column(name = "dns2")
private String dns2;
@Column(name = "total")
private Long total;
@Column(name = "free")
private Long free;
@Enumerated(EnumType.STRING)
@Column(name = "dns_type", nullable = false)
private NetworkDnsType dnsType;
@Column(name = "is_generate_hostname", nullable = false)
private Boolean isGenerateHostname;
public NetworkEntity() {
}
public NetworkEntity(String name, String portGroup,
AllocType allocType, String netmask, String gateway, String dns1, String dns2, NetworkDnsType dnsType) {
this.name = name;
this.portGroup = portGroup;
this.ipBlocks = new ArrayList<IpBlockEntity>();
this.allocType = allocType;
this.netmask = netmask;
this.gateway = gateway;
this.dns1 = dns1;
this.dns2 = dns2;
this.total = 0L;
this.free = 0L;
setDnsType(dnsType);
validate();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPortGroup() {
return portGroup;
}
public void setPortGroup(String portGroup) {
this.portGroup = portGroup;
}
public List<IpBlockEntity> getIpBlocks() {
return ipBlocks;
}
public void setIpBlocks(List<IpBlockEntity> ipBlocks) {
this.total = IpBlockEntity.count(ipBlocks);
this.free = IpBlockEntity.count(IpBlockEntity.filter(ipBlocks,
EqualBlockTypePredicate.IS_FREE));
this.ipBlocks = ipBlocks;
}
/*
public List<ClusterEntity> getClusters() {
return clusters;
}
public void setClusters(List<ClusterEntity> clusters) {
this.clusters = clusters;
}
*/
public AllocType getAllocType() {
return allocType;
}
public void setAllocType(AllocType allocType) {
this.allocType = allocType;
}
public String getNetmask() {
return netmask;
}
public void setNetmask(String netmask) {
this.netmask = netmask;
}
public String getGateway() {
return gateway;
}
public void setGateway(String gateway) {
this.gateway = gateway;
}
public String getDns1() {
return dns1;
}
public void setDns1(String dns1) {
this.dns1 = dns1;
}
public String getDns2() {
return dns2;
}
public void setDns2(String dns2) {
this.dns2 = dns2;
}
public Set<NicEntity> getNics() {
return nics;
}
public void setNics(Set<NicEntity> nics) {
this.nics = nics;
}
@Override
public int compareTo(NetworkEntity o) {
return getName().compareTo(o.getName());
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof NetworkEntity && this.compareTo((NetworkEntity) o) == 0;
}
public void validate() {
// validate the rest api layer parameter check
if (ConfigInfo.isDebugEnabled()) {
AuAssert.check(getPortGroup() != null);
AuAssert.check(getAllocType() != null);
if (getAllocType() == AllocType.DHCP) {
AuAssert.check(getNetmask() == null);
AuAssert.check(getGateway() == null);
AuAssert.check(getDns1() == null);
AuAssert.check(getDns2() == null);
} else {
AuAssert.check(getNetmask() != null);
try {
InetAddress.getByName(getNetmask());
if (getGateway() != null) {
InetAddress.getByName(getGateway());
}
InetAddress.getByName(getDns1());
InetAddress.getByName(getDns2());
} catch (UnknownHostException e) {
AuAssert.unreachable();
}
}
}
if (getAllocType() == AllocType.IP_POOL && getGateway() != null) {
long netmask = IpAddressUtil.getAddressAsLong(this.getNetmask());
long gateway = IpAddressUtil.getAddressAsLong(this.getGateway());
if (ConfigInfo.isDebugEnabled()) {
AuAssert.check(IpAddressUtil.isValidNetmask(netmask));
AuAssert.check(IpAddressUtil.isValidIp(this.getGateway()));
}
long networkAddr = netmask & gateway;
for (IpBlockEntity blk : getIpBlocks()) {
if (!IpAddressUtil.networkContains(networkAddr, netmask, blk.getBeginIp())) {
logger.error("ip block is not in the range of the network: " + blk);
throw NetworkException.IP_OUT_OF_RANGE(blk.getBeginAddress());
};
if (!IpAddressUtil.networkContains(networkAddr, netmask, blk.getEndIp())) {
logger.error("ip block is not in the range of the network: " + blk);
throw NetworkException.IP_OUT_OF_RANGE(blk.getEndAddress());
};
if (gateway >= blk.getBeginIp() && gateway <= blk.getEndIp()) {
logger.error("ip block overlaps with gateway: " + blk);
throw NetworkException.IP_BLOCK_CONTAINS_GATEWAY(blk);
}
}
}
}
@Override
public String toString() {
return "NetworkEntity [getPortGroup()=" + getPortGroup() + ", getIpBlocks()="
+ getIpBlocks() + ", getAllocType()=" + getAllocType() + ", getNetmask()="
+ getNetmask() + ", getGateway()=" + getGateway() + ", getDns1()="
+ getDns1() + ", getDns2()=" + getDns2() + "]";
}
public long getTotal() {
AuAssert.check(getAllocType() == AllocType.IP_POOL,
"should not be called when IP pool is not used");
return this.total;
}
public long getFree() {
AuAssert.check(getAllocType() == AllocType.IP_POOL,
"should not be called when IP pool is not used");
return this.free;
}
public long getAssigned() {
AuAssert.check(getAllocType() == AllocType.IP_POOL,
"should not be called when IP pool is not used");
return this.total - this.free;
}
public NetworkDnsType getDnsType() {
return dnsType;
}
public void setDnsType(NetworkDnsType dnsType) {
this.dnsType = dnsType;
if (NetworkDnsType.isOthers(dnsType) || NetworkDnsType.isDynamic(dnsType)) {
this.isGenerateHostname = true;
} else {
this.isGenerateHostname = false;
}
}
public Boolean getIsGenerateHostname() {
return isGenerateHostname;
}
public void setIsGenerateHostname(Boolean isGenerateHostname) {
this.isGenerateHostname = isGenerateHostname;
}
}