/** * This file is part of ElasticDroid. * * ElasticDroid is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * ElasticDroid is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with ElasticDroid. If not, see <http://www.gnu.org/licenses/>. * * Authored by siddhu on 7 Jan 2011 */ package org.elasticdroid.model; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import org.elasticdroid.model.tpl.GenericModel; import org.elasticdroid.tpl.GenericActivity; import org.elasticdroid.tpl.GenericListActivity; import android.util.Log; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DeleteTagsRequest; import com.amazonaws.services.ec2.model.StartInstancesRequest; import com.amazonaws.services.ec2.model.StartInstancesResult; import com.amazonaws.services.ec2.model.StopInstancesRequest; import com.amazonaws.services.ec2.model.StopInstancesResult; import com.amazonaws.services.ec2.model.Tag; /** * Model to allow user to control instance attributes: * <ul> * <li>Start instance</li> * <li>Stop instance </li> * <li>Set/change instance tag (tag key = name) </li> * </ul> * @author siddhu * * 7 Jan 2011 */ public class ControlInstancesModel extends GenericModel<String, Void, Object> { /** * Enumeration to indicate type of control to perform * */ public static enum ControlType { START_INSTANCE, STOP_INSTANCE, TAG_INSTANCE } /** The connection Data for AWS */ private HashMap<String, String> connectionData; /** The operation to perform with this particular object */ private ControlType operationType; /** Logging tag */ private static final String TAG = "org.elasticdroid.model.ControlInstancesModel"; /** The EC2 tags to create, if any. Used only with @link{ControlType#TAG_INSTANCE} */ private ArrayList<Tag> ec2Tags; /** * Initialise the model by supplying connection data to start/stop instances * * DO NOT USE THIS CONSTRUCTOR IF YOU ARE GOING TO TAG AN INSTANCE! YOU WILL GET AN ILLEGAL * ARGUMENT EXCEPTION WHEN YOU EXECUTE IN BACKGROUND. * * @param activity * @param connectionData The AWS connection data * @param operation Type: Start instance, stop instance, or tag instance. */ public ControlInstancesModel(GenericActivity activity, HashMap<String, String> connectionData , ControlType operationType) { super(activity); this.connectionData = connectionData; this.operationType = operationType; //set the tag to null this.ec2Tags = null; } /** * Initialise the model by supplying connection data to start/stop instances * * DO NOT USE THIS CONSTRUCTOR IF YOU ARE GOING TO TAG AN INSTANCE! YOU WILL GET AN ILLEGAL * ARGUMENT EXCEPTION WHEN YOU EXECUTE IN BACKGROUND. * * @param listActivity * @param connectionData The AWS connection data * @param operation Type: Start instance, stop instance, or tag instance. */ public ControlInstancesModel(GenericListActivity listActivity, HashMap<String, String> connectionData, ControlType operationType) { super(listActivity); this.connectionData = connectionData; this.operationType = operationType; //set the tag to null this.ec2Tags = null; } /** * Initialise the model by supplying connection data to tag instances. Requires additional * argument specifying the tag to use. * * @param activity * @param connectionData The AWS connection data * @param operation Type: Start instance, stop instance, or tag instance. * @param ec2Tagnames: The list of tagnames to assign the instances. */ public ControlInstancesModel(GenericActivity activity, HashMap<String, String> connectionData , ControlType operationType, List<String> ec2Tagnames) { super(activity); this.connectionData = connectionData; this.operationType = operationType; ec2Tags = new ArrayList<Tag>(); //create a list of Tags. for (String ec2Tagname : ec2Tagnames) { ec2Tags.add(new Tag("Name", ec2Tagname)); } } /** * Initialise the model by supplying connection data to start/stop instances. Requires * additional argument specifying the tag to use * * @param listActivity * @param connectionData The AWS connection data * @param operation Type: Start instance, stop instance, or tag instance. * @param ec2Tagnames: The list of tagnames to assign the instances. */ public ControlInstancesModel(GenericListActivity listActivity, HashMap<String, String> connectionData, ControlType operationType, List<String> ec2Tagnames) { super(listActivity); this.connectionData = connectionData; this.operationType = operationType; ec2Tags = new ArrayList<Tag>(); //create a list of Tags. for (String ec2Tagname : ec2Tagnames) { ec2Tags.add(new Tag("Name", ec2Tagname)); } } /** * @param instances List of instances to stop or start * @return @see {@link ControlInstancesModel#controlInstances(List)} */ @Override protected Object doInBackground(String... instances) { //TODO remove try { Thread.sleep(4000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //call controlInstances to do the actual job. if ((operationType == ControlType.START_INSTANCE) || (operationType == ControlType.STOP_INSTANCE)) { return controlInstances(Arrays.asList(instances)); } else { if (ec2Tags.size() == 0) { Log.v(TAG, "Deleting tags..."); return deleteTags(Arrays.asList(instances)); } else { //tag instance otherwise. return tagInstance(Arrays.asList(instances)); } } } /** * Method that does the actual work of starting or stopping the instances * * This method uses the stop boolean to identify whether the instances should be stopped * (stop = true) or started (stop = false). * * @return Returns one of the following: * <ul> * <li>newInstanceStates: Returns a list of stateCodes and state names for all of the instances * </li> * <li> AmazonServiceException</li> * <li> AmazonClientException</li> * </ul> * */ public Object controlInstances(List<String> instances) { for (String instance : instances) { Log.v(TAG, "Starting instance: " + instance); } //create credentials using the BasicAWSCredentials class BasicAWSCredentials credentials = new BasicAWSCredentials(connectionData.get("accessKey"), connectionData.get("secretAccessKey")); //create Amazon EC2 Client object, and set tye end point to the region. params[3] //contains endpoint AmazonEC2Client amazonEC2Client = new AmazonEC2Client(credentials); //override the default connection endpoint if provided. if (connectionData.get("endpoint") != null) { amazonEC2Client.setEndpoint(connectionData.get("endpoint")); } //if you want to start an instance if (operationType == ControlType.START_INSTANCE) { StartInstancesRequest request = new StartInstancesRequest(instances); StartInstancesResult result = null; try { result = amazonEC2Client.startInstances(request); } catch(AmazonServiceException amazonServiceException) { return amazonServiceException; } catch(AmazonClientException amazonClientException) { return amazonClientException; } //redundant check. if (result != null) { return result.getStartingInstances(); } } //stop = true, start the instance. else { StopInstancesRequest request = new StopInstancesRequest(instances); StopInstancesResult result = null; try { result = amazonEC2Client.stopInstances(request); } catch(AmazonServiceException amazonServiceException) { return amazonServiceException; } catch(AmazonClientException amazonClientException) { return amazonClientException; } if (result != null) { return result.getStoppingInstances(); } } return null; } /** * Create/override tags of key name for the instances. * @param instances: list of instances * @return * <ul> * <li> true: to indicate success in reassigning the tags </li> * <li>IllegalArgumentException: If the number of instances != number of tags</li> * <li>AmazonServicesException: Serverside issues with AWS</li> * <li>AmazonClientException: (Probably) connectivity issues</li> * </ul> */ public Object tagInstance(List<String> instances) { if (instances.size() != ec2Tags.size()) { return new IllegalArgumentException("The number of instances should be equal to be " + "the number"); } //create credentials using the BasicAWSCredentials class BasicAWSCredentials credentials = new BasicAWSCredentials(connectionData.get("accessKey"), connectionData.get("secretAccessKey")); //create Amazon EC2 Client object, and set tye end point to the region. params[3] //contains endpoint AmazonEC2Client amazonEC2Client = new AmazonEC2Client(credentials); //override the default connection endpoint if provided. if (connectionData.get("endpoint") != null) { amazonEC2Client.setEndpoint(connectionData.get("endpoint")); } //create a TagsRequest for (String instance : instances) { Log.v(TAG, "Tagging " + instance); } CreateTagsRequest request = new CreateTagsRequest(instances, ec2Tags); //okay, tag the instance try { amazonEC2Client.createTags(request); } catch(AmazonServiceException amazonServiceException) { return amazonServiceException; } catch(AmazonClientException amazonClientException) { return amazonClientException; } return new Boolean(true); //return true to indicate success! } public Object deleteTags(List<String> instances) { //create credentials using the BasicAWSCredentials class BasicAWSCredentials credentials = new BasicAWSCredentials(connectionData.get("accessKey"), connectionData.get("secretAccessKey")); //create Amazon EC2 Client object, and set tye end point to the region. params[3] //contains endpoint AmazonEC2Client amazonEC2Client = new AmazonEC2Client(credentials); //override the default connection endpoint if provided. if (connectionData.get("endpoint") != null) { amazonEC2Client.setEndpoint(connectionData.get("endpoint")); } //create empty tags for each of the instances from which the name tag is to be deleted. for (String instance : instances) { Log.v(TAG, "Tagging " + instance); //create a tag with Name for each instance from which Name tag is to be deleted. ec2Tags.add(new Tag("Name")); } DeleteTagsRequest request = new DeleteTagsRequest(instances); request.setTags(ec2Tags); //okay, tag the instance try { amazonEC2Client.deleteTags(request); } catch(AmazonServiceException amazonServiceException) { return amazonServiceException; } catch(AmazonClientException amazonClientException) { return amazonClientException; } return new Boolean(true); //return true to indicate success! } }