package io.fathom.cloud.compute.scheduler;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.compute.networks.IpRange;
import io.fathom.cloud.compute.scheduler.SchedulerHost.SchedulerHostNetwork;
import io.fathom.cloud.compute.services.ComputeSecrets;
import io.fathom.cloud.compute.services.DatacenterManager;
import io.fathom.cloud.compute.services.Ec2DatacenterManager;
import io.fathom.cloud.compute.services.RawDatacenterManager;
import io.fathom.cloud.compute.state.HostStore;
import io.fathom.cloud.protobuf.CloudModel.HostData;
import io.fathom.cloud.protobuf.CloudModel.HostGroupData;
import io.fathom.cloud.protobuf.CloudModel.HostGroupSecretData;
import io.fathom.cloud.protobuf.CloudModel.InstanceData;
import io.fathom.cloud.ssh.SshConfig;
import io.fathom.cloud.ssh.SshContext;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.persist.Transactional;
@Singleton
public class InstanceScheduler {
private static final Logger log = LoggerFactory.getLogger(InstanceScheduler.class);
@Inject
HostStore hostStore;
@Inject
SshContext sshContext;
@Inject
ComputeSecrets computeSecrets;
static final Random random = new Random();
final Map<Long, SchedulerHost> allHosts = Maps.newHashMap();
public SchedulerHost findHost(long i) {
synchronized (allHosts) {
return allHosts.get(i);
}
}
// public SchedulerHost findHost(String key) {
// synchronized (allHosts) {
// for (SchedulerHost host : allHosts.values()) {
// if (host.getKey().equals(key)) {
// return host;
// }
// }
// return null;
// }
// }
@Transactional
public void refreshHosts() throws CloudException {
Map<Long, HostGroupData> hostGroups = Maps.newHashMap();
Map<Long, DatacenterManager> datacenters = Maps.newHashMap();
for (HostGroupData hostGroupData : hostStore.getHostGroups().list()) {
hostGroups.put(hostGroupData.getId(), hostGroupData);
}
for (HostData hostData : hostStore.getHosts().list()) {
HostGroupData hostGroupData = hostGroups.get(hostData.getHostGroup());
if (hostGroupData == null) {
throw new IllegalStateException();
}
DatacenterManager datacenter = datacenters.get(hostGroupData.getId());
if (datacenter == null) {
switch (hostGroupData.getHostGroupType()) {
case HOST_GROUP_TYPE_RAW:
datacenter = new RawDatacenterManager();
break;
case HOST_GROUP_TYPE_AMAZON_EC2:
HostGroupSecretData secretData = computeSecrets.getSecretData(hostGroupData);
datacenter = new Ec2DatacenterManager(hostGroupData, secretData);
break;
default:
throw new IllegalStateException();
}
datacenters.put(hostGroupData.getId(), datacenter);
}
IpRange ipRange = IpRange.parse(hostData.getCidr());
InetAddress address = ipRange.getAddress();
InetSocketAddress sshSocketAddress = new InetSocketAddress(address, 22);
SshConfig sshConfig = sshContext.buildConfig(sshSocketAddress);
SchedulerHost host = new GawkerHost(datacenter, hostData, sshConfig);
synchronized (allHosts) {
allHosts.put(hostData.getId(), host);
}
}
// TODO: Cope with deleted hosts
}
public List<SchedulerHost> pickHosts(SchedulerRequest request) {
log.warn("Scheduler is tragically stupid");
List<SchedulerHost> hosts = Lists.newArrayList();
synchronized (allHosts) {
List<Long> hostIds = Lists.newArrayList(allHosts.keySet());
if (hostIds.size() == 0) {
throw new IllegalArgumentException("No hosts are configured");
}
for (int i = 0; i < request.maxCount; i++) {
int r;
synchronized (random) {
r = random.nextInt(hostIds.size());
}
long hostId = hostIds.get(r);
hosts.add(allHosts.get(hostId));
}
}
return hosts;
}
public static class SchedulerResult {
public InstanceData oldInstanceInfo;
}
public List<SchedulerHost> getAllHosts() {
synchronized (allHosts) {
List<SchedulerHost> hosts = Lists.newArrayList();
hosts.addAll(allHosts.values());
return hosts;
}
}
public SchedulerHostNetwork findHostByAddress(InetAddress address) {
// TODO: We really need to clean this up...
synchronized (allHosts) {
for (SchedulerHost host : allHosts.values()) {
for (SchedulerHostNetwork network : host.getNetworks()) {
if (network.getIpRange().contains(address)) {
return network;
}
}
}
return null;
}
}
}