package edu.iit.cs553;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
public class Provisioner {
private AmazonEC2Client ec2Client;
private CloudWatchMonitor monitor;
private List<Map<String, Integer>> instancesIdsAndStates;
public Provisioner()
{
this.ec2Client = new AmazonEC2Client(new ClasspathPropertiesFileCredentialsProvider());
this.monitor = new CloudWatchMonitor();
ec2Client.setEndpoint("ec2.us-west-2.amazonaws.com");
this.instancesIdsAndStates = new ArrayList<Map<String, Integer>>();
initInstancesIdsAndStates();
}
public void allocateNeededWorkersUsingCloudWatchMonitor()
{
getInstancesState();
int numberOfTasksInQueue = monitor.getNumberOfTasksInQueue();
System.out.println("Number of tasks in queue: " + numberOfTasksInQueue);
for (int i = 0; i < numberOfTasksInQueue; i++)
{
boolean additionalWorkerAllocated = allocateAdditionalWorker();
if (additionalWorkerAllocated == true)
{
System.out.println("An additional worker has been allocated");
} else
{
System.out.println("All workers are busy!");
}
}
}
public void allocateNeededWorkersWithoutCloudWatch(int numberOfTasksInQueue)
{
getInstancesState();
System.out.println("\nNumber of tasks in queue: " + numberOfTasksInQueue + "\n");
for (int i = 0; i < numberOfTasksInQueue; i++)
{
boolean additionalWorkerAllocated = allocateAdditionalWorker();
if (additionalWorkerAllocated == true)
{
System.out.println("An additional worker has been allocated");
} else
{
System.out.println("All workers are busy!");
}
}
}
/**
* Allocates a new worker if at least one is not working
*
* @return true if a new worker has been allocated, false if couldn't
* allocate a new worker because everyone is working
*/
private boolean allocateAdditionalWorker()
{
boolean additionalWorkerAllocated = false;
for (Map<String, Integer> instanceIdAndState : this.instancesIdsAndStates)
{
String instanceId = getInstanceId(instanceIdAndState);
int instanceState = instanceIdAndState.get(instanceId);
if (instanceState == 0)
{
launchInstance(instanceId);
additionalWorkerAllocated = true;
return additionalWorkerAllocated;
}
}
return additionalWorkerAllocated;
}
private void launchInstance(String instanceId)
{
StartInstancesRequest startInstancesRequest = new StartInstancesRequest();
List<String> instancesIdsToLaunch = new ArrayList<String>();
instancesIdsToLaunch.add(instanceId);
startInstancesRequest.setInstanceIds(instancesIdsToLaunch);
ec2Client.startInstances(startInstancesRequest);
updateInstanceState(instanceId, "running");
}
private void getInstancesState()
{
DescribeInstancesResult describeInstancesResult = ec2Client.describeInstances();
List<Reservation> reservations = describeInstancesResult.getReservations();
for (Reservation reservation : reservations)
{
List<Instance> instances = reservation.getInstances();
for (Instance instance : instances)
{
String instanceId = instance.getInstanceId();
String instanceStateInString = instance.getState().getName();
updateInstanceState(instanceId, instanceStateInString);
}
}
}
private void updateInstanceState(String instanceId, String instanceStateInString)
{
for (Map<String, Integer> instanceIdAndState : this.instancesIdsAndStates)
{
int instanceState = getInstanceStateFromStateInString(instanceStateInString);
String currentInstanceId = getInstanceId(instanceIdAndState);
if (instanceId.equals(currentInstanceId))
{
instanceIdAndState.put(currentInstanceId, instanceState);
}
}
}
private int getInstanceStateFromStateInString(String instanceStateInString)
{
int state = 0;
if (instanceStateInString.equals("running"))
{
state = 1;
}
return state;
}
private String getInstanceId(Map<String, Integer> instanceIdAndState)
{
Set<String> keySet = instanceIdAndState.keySet();
Iterator<String> iterator = keySet.iterator();
String instanceId = iterator.next();
return instanceId;
}
private void initInstancesIdsAndStates()
{
List<String> instancesIds = initInstancesIds();
for (String instanceId : instancesIds)
{
Map<String, Integer> instanceIdAndState = new HashMap<String, Integer>();
instanceIdAndState.put(instanceId, 0);
this.instancesIdsAndStates.add(instanceIdAndState);
}
getInstancesState();
}
private List<String> initInstancesIds()
{
DescribeInstancesResult describeInstancesResult = ec2Client.describeInstances();
List<Reservation> reservations = describeInstancesResult.getReservations();
List<String> instancesIds = new ArrayList<String>();
for (Reservation reservation : reservations)
{
List<Instance> instances = reservation.getInstances();
for (Instance instance : instances)
{
String instanceId = instance.getInstanceId();
instancesIds.add(instanceId);
}
}
return instancesIds;
}
// Used for debugging purposes
public void displayInstancesStates()
{
for (Map<String, Integer> instanceIdAndState : this.instancesIdsAndStates)
{
String instanceId = getInstanceId(instanceIdAndState);
int instanceState = instanceIdAndState.get(instanceId);
System.out.println(instanceId + ": " + instanceState);
}
}
}