package io.fathom.cloud.compute.services;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.compute.api.os.model.actions.AddFloatingIpRequest;
import io.fathom.cloud.compute.api.os.model.actions.RemoveFloatingIpRequest;
import io.fathom.cloud.compute.networks.MappableIpNetworkPool;
import io.fathom.cloud.compute.networks.NetworkPool;
import io.fathom.cloud.compute.networks.NetworkPoolAllocation;
import io.fathom.cloud.compute.networks.NetworkPools;
import io.fathom.cloud.compute.networks.VirtualIp;
import io.fathom.cloud.compute.state.ComputeRepository;
import io.fathom.cloud.protobuf.CloudModel.InstanceData;
import io.fathom.cloud.protobuf.CloudModel.VirtualIpData;
import io.fathom.cloud.protobuf.CloudModel.VirtualIpPoolData;
import io.fathom.cloud.protobuf.CloudModel.VirtualIpPoolData.Builder;
import io.fathom.cloud.protobuf.CloudModel.VirtualIpPoolType;
import io.fathom.cloud.server.model.Project;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.inject.persist.Transactional;
@Transactional
@Singleton
public class IpPools {
private static final Logger log = LoggerFactory.getLogger(IpPools.class);
@Inject
ComputeRepository computeRepository;
@Inject
NetworkPools networkPools;
@Inject
AsyncTasks asyncTasks;
public VirtualIp findVirtualIp(Project project, String address) throws CloudException {
for (VirtualIpPoolData pool : computeRepository.getVirtualIpPools().list()) {
VirtualIpData vip = computeRepository.getAllocatedVips(pool.getId()).find(address);
if (vip == null) {
continue;
}
if (vip.getProjectId() != project.getId()) {
continue;
}
return new VirtualIp(pool, vip);
}
return null;
}
// public VirtualIp findVirtualIp(Project project, long id) throws
// CloudException {
// for (VirtualIpPoolData pool :
// computeRepository.getVirtualIpPools().list()) {
// for (VirtualIpData vip :
// computeRepository.getAllocatedVips(pool.getId()).list()) {
// if (vip.getProjectId() != project.getId()) {
// continue;
// }
// if (id == getId(vip)) {
// return new VirtualIp(pool, vip);
// }
// }
// }
// return null;
// }
// public static String getId(VirtualIpData vip) {
// return vip.getIp();
// //
// // InetAddress address = InetAddresses.forString(vip.getIp());
// // if (address instanceof Inet4Address) {
// // Inet4Address inet4 = (Inet4Address) address;
// // byte[] b = inet4.getAddress();
// // int i = ((b[0] & 0xFF) << 24) | ((b[1] & 0xFF) << 16) | ((b[2] &
// // 0xFF) << 8) | ((b[3] & 0xFF) << 0);
// // return i;
// // } else {
// // throw new UnsupportedOperationException();
// // }
// }
public List<VirtualIp> listVirtualIps(Project project) throws CloudException {
List<VirtualIp> ret = Lists.newArrayList();
for (VirtualIpPoolData pool : computeRepository.getVirtualIpPools().list()) {
for (VirtualIpData vip : computeRepository.getAllocatedVips(pool.getId()).list()) {
if (vip.getProjectId() != project.getId()) {
continue;
}
ret.add(new VirtualIp(pool, vip));
}
}
return ret;
}
@Transactional
public void attachFloatingIp(Project project, InstanceData instance, AddFloatingIpRequest request)
throws CloudException {
String address = request.address;
if (address == null) {
// TODO: Auto-allocate a suitable floating ip from the networks the
// instance can see
throw new IllegalArgumentException();
}
VirtualIp vip = findVirtualIp(project, address);
if (vip == null) {
throw new WebApplicationException(Status.NOT_FOUND);
}
if (vip.getData().hasInstanceId()) {
throw new WebApplicationException(Status.CONFLICT);
}
VirtualIpData.Builder b = VirtualIpData.newBuilder(vip.getData());
b.setInstanceId(instance.getId());
VirtualIpData updated = computeRepository.getAllocatedVips(vip.getPoolData().getId()).update(b);
asyncTasks.attachFloatingIp(project, instance, new VirtualIp(vip.getPoolData(), updated));
}
public void detachFloatingIp(Project project, InstanceData instance, RemoveFloatingIpRequest request)
throws CloudException {
String address = request.address;
if (address == null) {
throw new IllegalArgumentException();
}
VirtualIp vip = findVirtualIp(project, address);
if (vip == null) {
throw new WebApplicationException(Status.NOT_FOUND);
}
VirtualIpData vipData = vip.getData();
if (!vipData.hasInstanceId() || vipData.getInstanceId() != instance.getId()) {
throw new WebApplicationException(Status.NOT_FOUND);
}
VirtualIpData.Builder b = VirtualIpData.newBuilder(vip.getData());
b.clearInstanceId();
VirtualIpData updated = computeRepository.getAllocatedVips(vip.getPoolData().getId()).update(b);
asyncTasks.detachFloatingIp(project, instance, new VirtualIp(vip.getPoolData(), updated));
}
public VirtualIp allocateFloatingIp(Project project, VirtualIpPoolData poolData) throws CloudException {
NetworkPool pool = networkPools.buildPool(poolData);
NetworkPoolAllocation allocation = networkPools.allocateIp(project, pool);
return ((MappableIpNetworkPool.Allocation) allocation).getVirtualIp();
}
public void deallocateFloatingIp(Project project, String ip) throws CloudException {
VirtualIp vip = findVirtualIp(project, ip);
if (vip == null) {
throw new WebApplicationException(Status.NOT_FOUND);
}
if (vip.getData().hasInstanceId()) {
// TODO: Auto-detach?
throw new WebApplicationException(Status.CONFLICT);
}
NetworkPool pool = networkPools.buildPool(vip.getPoolData());
pool.markIpNotAllocated(vip);
}
public VirtualIpPoolData findVirtualIpPool(Project project, long poolId) throws CloudException {
// TODO: Restrict access to pools by project?
return computeRepository.getVirtualIpPools().find(poolId);
}
public List<VirtualIpPoolData> listVirtualIpPools(Project project) throws CloudException {
// TODO: Restrict access to pools by project?
return computeRepository.getVirtualIpPools().list();
}
public VirtualIpPoolData createVipPool(Builder b) throws CloudException {
if (b.getType() == VirtualIpPoolType.LAYER_3) {
if (!b.hasCidr()) {
throw new IllegalArgumentException();
}
}
if (b.getType() == VirtualIpPoolType.AMAZON_EC2) {
if (b.hasCidr()) {
throw new IllegalArgumentException();
}
}
return computeRepository.getVirtualIpPools().create(b);
}
public void deleteVirtualIpPool(VirtualIpPoolData pool) throws CloudException {
computeRepository.getVirtualIpPools().delete(pool.getId());
}
}