Java tutorial
/* * Copyright 1999-2008 University of Chicago * * 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 org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.rm.defaults; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.globus.util.Base64; import org.nimbustools.api._repr._CreateRequest; import org.nimbustools.api._repr._CustomizationRequest; import org.nimbustools.api._repr.vm._NIC; import org.nimbustools.api.brain.ModuleLocator; import org.nimbustools.api.defaults.repr.vm.DefaultKernel; import org.nimbustools.api.repr.Caller; import org.nimbustools.api.repr.CannotTranslateException; import org.nimbustools.api.repr.CreateRequest; import org.nimbustools.api.repr.CreateResult; import org.nimbustools.api.repr.CustomizationRequest; import org.nimbustools.api.repr.ReprFactory; import org.nimbustools.api.repr.vm.NIC; import org.nimbustools.api.repr.vm.RequiredVMM; import org.nimbustools.api.repr.vm.ResourceAllocation; import org.nimbustools.api.repr.vm.State; import org.nimbustools.api.repr.vm.VM; import org.nimbustools.api.repr.vm.VMFile; import org.nimbustools.messaging.gt4_0_elastic.generated.v2010_08_31.*; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.general.Networks; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.general.ResourceAllocations; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.image.Repository; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.rm.ContainerInterface; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.rm.Describe; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.rm.IDMappings; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.rm.Run; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.security.SSHKey; import org.nimbustools.messaging.gt4_0_elastic.v2008_05_05.security.SSHKeys; import java.net.URI; import java.net.URISyntaxException; import java.rmi.RemoteException; public class DefaultRun implements Run { // ------------------------------------------------------------------------- // STATIC VARIABLES // ------------------------------------------------------------------------- private static final Log logger = LogFactory.getLog(DefaultRun.class.getName()); // ------------------------------------------------------------------------- // INSTANCE VARIABLES // ------------------------------------------------------------------------- protected final ReprFactory repr; protected final ResourceAllocations RAs; protected final Networks networks; protected final Repository repository; protected final IDMappings ids; protected final ContainerInterface container; protected final Describe describe; protected final SSHKeys sshKeys; // ------------------------------------------------------------------------- // CONSTRUCTORS // ------------------------------------------------------------------------- public DefaultRun(ResourceAllocations rasImpl, Networks networksImpl, Repository repoImpl, IDMappings idsImpl, Describe describeImpl, ContainerInterface containerImpl, SSHKeys sshKeysImpl, ModuleLocator locator) throws Exception { if (rasImpl == null) { throw new IllegalArgumentException("rasImpl may not be null"); } this.RAs = rasImpl; if (networksImpl == null) { throw new IllegalArgumentException("networksImpl may not be null"); } this.networks = networksImpl; if (repoImpl == null) { throw new IllegalArgumentException("repoImpl may not be null"); } this.repository = repoImpl; if (idsImpl == null) { throw new IllegalArgumentException("idsImpl may not be null"); } this.ids = idsImpl; if (describeImpl == null) { throw new IllegalArgumentException("describeImpl may not be null"); } this.describe = describeImpl; if (containerImpl == null) { throw new IllegalArgumentException("containerImpl may not be null"); } this.container = containerImpl; this.sshKeys = sshKeysImpl; if (locator == null) { throw new IllegalArgumentException("locator may not be null"); } this.repr = locator.getReprFactory(); } public DefaultRun(ResourceAllocations rasImpl, Networks networksImpl, Repository repoImpl, IDMappings idsImpl, Describe describeImpl, ContainerInterface containerImpl, ModuleLocator locator) throws Exception { this(rasImpl, networksImpl, repoImpl, idsImpl, describeImpl, containerImpl, null, locator); } // ------------------------------------------------------------------------- // implements Run // ------------------------------------------------------------------------- public CreateRequest translateRunInstances(RunInstancesType req, Caller caller) throws RemoteException, CannotTranslateException { final String ownerID; try { ownerID = this.container.getOwnerID(caller); } catch (CannotTranslateException e) { throw new RemoteException(e.getMessage(), e); } final String imageID = req.getImageId(); if (imageID == null) { throw new RemoteException("Request is missing image ID"); } // currently ignored: groupSet, placement, kernel, ramdiskid, // blockDeviceMapping final _CustomizationRequest cust; final String keyname = req.getKeyName(); if (keyname != null && this.sshKeys != null) { cust = this.repr._newCustomizationRequest(); final SSHKey key = this.sshKeys.findKey(ownerID, keyname); if (key == null) { throw new RemoteException("There is no key '" + keyname + "' registered for you to use"); } cust.setContent(key.getPubKeyValue()); cust.setPathOnVM("/root/.ssh/authorized_keys"); } else { cust = null; } final CustomizationRequest[] custRequests; if (cust != null) { custRequests = new CustomizationRequest[1]; custRequests[0] = cust; } else { custRequests = null; } final String raType = req.getInstanceType(); final ResourceAllocation ra = this.RAs.getMatchingRA(raType, req.getMinCount(), req.getMaxCount(), false); final NIC[] nics = this.getNICs(ra.getPublicNetwork(), ra.getPrivateNetwork()); final RequiredVMM reqVMM = this.RAs.getRequiredVMM(); String userData = null; final UserDataType t_userData = req.getUserData(); if (t_userData != null) { final String base64Encoded = t_userData.getData(); if (base64Encoded != null) { // Remove newlines from the base64 string since they are not // supported by the Globus implementation final String base64EncodedNoCRLF = base64Encoded.replaceAll("[\r\n]", ""); if (!Base64.isBase64(base64EncodedNoCRLF)) { throw new RemoteException("userdata does not appear to " + "be base64 encoded?"); } final byte[] bytes = Base64.decode(base64EncodedNoCRLF.getBytes()); userData = new String(bytes); } } final VMFile[] files = this.repository.constructFileRequest(imageID, ra, caller); final String clientToken = req.getClientToken(); String availabilityZone = null; if (req.getPlacement() != null) { availabilityZone = req.getPlacement().getAvailabilityZone(); } final _CreateRequest creq = this.repr._newCreateRequest(); DefaultKernel kernel = null; String kernelRequestString = req.getKernelId(); if (kernelRequestString != null) { kernel = new DefaultKernel(); try { URI kernelURI = new URI("file://" + kernelRequestString); kernel.setKernel(kernelURI); } catch (URISyntaxException ueie) { throw new RemoteException(ueie.toString()); } } creq.setContext(null); creq.setCoScheduleDone(false); creq.setCoScheduleID(null); creq.setCoScheduleMember(false); creq.setCustomizationRequests(custRequests); creq.setInitialStateRequest(State.STATE_Running); creq.setName(imageID); creq.setRequestedKernel(kernel); // todo creq.setRequestedNics(nics); creq.setRequestedRA(ra); creq.setRequestedSchedule(null); // ask for default creq.setRequiredVMM(reqVMM); creq.setShutdownType(CreateRequest.SHUTDOWN_TYPE_TRASH); creq.setVMFiles(files); creq.setMdUserData(userData); creq.setSshKeyName(keyname); creq.setClientToken(clientToken); creq.setRequestedResourcePool(availabilityZone); return creq; } public RunInstancesResponseType translateCreateResult(CreateResult result, Caller caller, String sshKeyName) throws Exception { if (result == null) { throw new CannotTranslateException("creation result is missing"); } final VM[] vms = result.getVMs(); if (vms == null || vms.length == 0) { throw new CannotTranslateException("creation result is empty?"); } if (result.getCoscheduledID() != null) { throw new CannotTranslateException("not expecting " + "coscheduling ID in any cases yet"); } final String groupid = result.getGroupID(); if (groupid == null && vms.length != 1) { throw new CannotTranslateException("expecting a groupID if " + "more than one VM was created"); } final String vmidWhenJustOne; final String resID; // these mappings may exist already, for secondary idempotent launches if (groupid == null) { vmidWhenJustOne = vms[0].getID(); resID = this.ids.getOrNewInstanceReservationID(vmidWhenJustOne, sshKeyName); } else { vmidWhenJustOne = null; resID = this.ids.getOrNewGroupReservationID(groupid); } final RunningInstancesSetType rist = new RunningInstancesSetType(); final RunningInstancesItemType[] riits = new RunningInstancesItemType[vms.length]; final String msg = "New reservation ID '" + resID + "' for "; final StringBuffer buf = new StringBuffer(msg); if (vmidWhenJustOne == null) { buf.append("VM group '").append(groupid); } else { buf.append("single VM '").append(vmidWhenJustOne); } buf.append("'. Members:"); for (int i = 0; i < vms.length; i++) { final VM vm = vms[i]; final String id = vm.getID(); if (id == null) { throw new CannotTranslateException("VM has no ID"); } final String instID; if (vmidWhenJustOne != null) { // mapping already created: instID = this.ids.managerInstanceToElasticInstance(vmidWhenJustOne); } else { // this mapping may exist already, for secondary idempotent launches instID = this.ids.getOrNewInstanceID(vm.getID(), resID, sshKeyName); } if (i != 0) { buf.append(","); } buf.append(" id-").append(id).append("='").append(instID).append("'"); riits[i] = this.getOneCreatedVM(vm, instID, resID, sshKeyName); } logger.info(buf.toString()); final RunInstancesResponseType ret = new RunInstancesResponseType(); ret.setGroupSet(getGroupStub()); final String ownerID = this.container.getOwnerID(caller); if (ownerID == null) { throw new CannotTranslateException("Cannot find owner ID"); } ret.setOwnerId(ownerID); ret.setReservationId(resID); rist.setItem(riits); ret.setInstancesSet(rist); ret.setRequesterId(ownerID); return ret; } // ------------------------------------------------------------------------- // NETWORK REQUEST // ------------------------------------------------------------------------- protected NIC[] getNICs(String publicNetworkName, String privateNetworkName) throws CannotTranslateException { // if the network mappings are the same value, that currently means // only make one real NIC request final String pubNet = this.networks.getManagerPublicNetworkName(); final String privNet = this.networks.getManagerPrivateNetworkName(); if (pubNet == null || privNet == null) { throw new CannotTranslateException("Illegal Networks " + "implementation, null network mapping"); } final NIC[] nics; /* Check that when one of public and private is set, they are both set */ if (publicNetworkName != null && !publicNetworkName.trim().equals("")) { if (privateNetworkName == null || privateNetworkName.trim().equals("")) { throw new CannotTranslateException("Illegal Networks " + "implementation, public network set but null private network mapping"); } } if (privateNetworkName != null && !privateNetworkName.trim().equals("")) { if (publicNetworkName == null || publicNetworkName.trim().equals("")) { throw new CannotTranslateException("Illegal Networks " + "implementation, private network set but null public network mapping"); } } if (publicNetworkName != null && !publicNetworkName.trim().equals("")) { if (publicNetworkName.trim().equals(privateNetworkName.trim())) { nics = new NIC[1]; publicNetworkName = publicNetworkName.trim(); logger.info("Using network name " + publicNetworkName); nics[0] = this.oneRequestedNIC(publicNetworkName, "autoeth0"); } else { nics = new NIC[2]; publicNetworkName = publicNetworkName.trim(); privateNetworkName = privateNetworkName.trim(); logger.info("Using public network name " + publicNetworkName + " and private network name " + privateNetworkName); nics[0] = this.oneRequestedNIC(publicNetworkName, "autoeth0"); nics[1] = this.oneRequestedNIC(privateNetworkName, "autoeth1"); } } else if (pubNet.equals(privNet)) { nics = new NIC[1]; nics[0] = this.oneRequestedNIC(pubNet, "autoeth0"); } else { nics = new NIC[2]; nics[0] = this.oneRequestedNIC(pubNet, "autoeth0"); nics[1] = this.oneRequestedNIC(privNet, "autoeth1"); } return nics; } protected NIC oneRequestedNIC(String networkName, String nicName) throws CannotTranslateException { if (networkName == null) { throw new CannotTranslateException("networkName is missing"); } final _NIC nic = this.repr._newNIC(); nic.setAcquisitionMethod(NIC.ACQUISITION_AllocateAndConfigure); nic.setNetworkName(networkName); nic.setName(nicName); return nic; } // ------------------------------------------------------------------------- // RESULT // ------------------------------------------------------------------------- // todo: duped code; support groups public static GroupSetType getGroupStub() { final GroupItemType[] groupItemTypes = new GroupItemType[1]; groupItemTypes[0] = new GroupItemType("default"); return new GroupSetType(groupItemTypes); } protected RunningInstancesItemType getOneCreatedVM(VM vm, String instID, String resID, String sshKeyName) throws CannotTranslateException { if (instID == null) { throw new IllegalArgumentException("instID may not be null"); } if (resID == null) { throw new IllegalArgumentException("resID may not be null"); } if (vm == null) { throw new IllegalArgumentException("vm may not be null"); } final RunningInstancesItemType riit = new RunningInstancesItemType(); riit.setInstanceState(this.describe.getState(vm)); riit.setReason(this.describe.getReason(vm)); riit.setPlacement(this.describe.getPlacement()); riit.setImageId(this.describe.getImageID(vm.getVMFiles())); riit.setInstanceType(this.describe.getInstanceType(vm)); riit.setLaunchTime(this.describe.getLaunchTime(vm)); riit.setAmiLaunchIndex("0"); // todo: could generate this here with i this.handleNetworking(vm, riit); riit.setInstanceId(instID); riit.setKeyName(sshKeyName); riit.setClientToken(vm.getClientToken()); riit.setKernelId("default"); // todo riit.setMonitoring(new InstanceMonitoringStateType("disabled")); riit.setProductCodes(new ProductCodesSetType(new ProductCodesSetItemType[] {})); //riit.setRamdiskId(); //riit.setReason(); return riit; } protected void handleNetworking(VM vm, RunningInstancesItemType riit) throws CannotTranslateException { // ec2 only necessarily has networking information on a running // instance. we can loosen up requirements here. // this is motivated by idempotent instance support. In cases where // an idempotent launch maps to an already-terminated instance, // the VM object here will be in the terminated state and have no // NICs information final boolean isTerminated = vm.getState().getState().equals(State.STATE_Cancelled); if (isTerminated && (vm.getNics() == null || vm.getNics().length == 0)) { return; } final NIC[] nics = vm.getNics(); if (nics == null || nics.length == 0) { // zero NICs not supported by this interface throw new CannotTranslateException("NICs are missing"); } if (nics.length != 1 && nics.length != 2) { throw new CannotTranslateException("Can only handle one or two " + "assigned NICs, but were given " + nics.length + " for vm id-" + vm.getID()); } if (nics.length == 1 && nics[0] == null) { throw new CannotTranslateException("NIC[] value is missing"); } if (nics.length == 2 && nics[1] == null) { throw new CannotTranslateException("NIC[] value is missing"); } final String netName = nics[0].getNetworkName(); if (netName == null) { throw new CannotTranslateException("NIC in vm id-" + vm.getID() + " is missing network name"); } final String hostname = nics[0].getHostname(); if (hostname == null) { throw new CannotTranslateException("NIC in vm id-" + vm.getID() + " is missing hostname"); } final String ipAddress = nics[0].getIpAddress(); if (ipAddress == null) { throw new CannotTranslateException("NIC in vm id-" + vm.getID() + " is missing IP address"); } final String netName2; final String hostname2; final String ipAddress2; if (nics.length == 2) { netName2 = nics[1].getNetworkName(); if (netName2 == null) { throw new CannotTranslateException("NIC in vm id-" + vm.getID() + " is missing network name"); } hostname2 = nics[1].getHostname(); if (hostname2 == null) { throw new CannotTranslateException("NIC in vm id-" + vm.getID() + " is missing hostname"); } ipAddress2 = nics[1].getIpAddress(); if (ipAddress2 == null) { throw new CannotTranslateException("NIC in vm id-" + vm.getID() + " is missing IP address"); } } else { netName2 = null; hostname2 = null; ipAddress2 = null; } String privateAssignedHostname = null; String publicAssignedHostname = null; String privateAssignedIp = null; String publicAssignedIp = null; if (netName2 != null) { logger.info("Using networks " + netName + " and " + netName2); } else { logger.info("Using network " + netName); } if (this.networks.isPrivateNetwork(netName)) { riit.setPrivateDnsName(hostname); riit.setPrivateIpAddress(ipAddress); privateAssignedHostname = hostname; privateAssignedIp = ipAddress; } else if (this.networks.isPublicNetwork(netName)) { riit.setDnsName(hostname); riit.setIpAddress(ipAddress); publicAssignedHostname = hostname; publicAssignedIp = ipAddress; } else { throw new CannotTranslateException("Unknown network was " + "assigned: '" + netName + "'"); } if (nics.length == 2) { if (this.networks.isPrivateNetwork(netName2)) { if (privateAssignedHostname != null) { // if public and private are set to be the same, that means // request ONE nic and make it appear to be two in remote // interface throw new CannotTranslateException("Won't support " + "real NICs from duplicate networks yet"); } riit.setPrivateDnsName(hostname2); riit.setPrivateIpAddress(ipAddress2); privateAssignedHostname = hostname2; privateAssignedIp = ipAddress2; } else if (this.networks.isPublicNetwork(netName2)) { if (publicAssignedHostname != null) { // if public and private are set to be the same, that means // request ONE nic and make it appear to be two in remote // interface throw new CannotTranslateException("Won't support " + "real NICs from duplicate networks yet"); } riit.setDnsName(hostname2); riit.setIpAddress(ipAddress2); publicAssignedHostname = hostname2; publicAssignedIp = ipAddress2; } else { throw new CannotTranslateException("Unknown network was " + "assigned: '" + netName2 + "'"); } } if (this.networks.getManagerPublicNetworkName().equals(this.networks.getManagerPrivateNetworkName())) { if (publicAssignedHostname != null && privateAssignedHostname != null) { // if public and private are set to be the same, that means // request ONE nic and make it appear to be two in remote // interface throw new CannotTranslateException("Won't support " + "real NICs from duplicate networks yet"); } if (publicAssignedHostname != null) { riit.setPrivateDnsName(publicAssignedHostname); riit.setPrivateIpAddress(publicAssignedIp); } else { riit.setDnsName(privateAssignedHostname); riit.setIpAddress(privateAssignedIp); } } } }