/** * $Id: $ * $Date: $ * */ package org.xmlsh.aws.util; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.xml.stream.XMLStreamException; import net.sf.saxon.s9api.SaxonApiException; import org.xmlsh.core.CoreException; import org.xmlsh.core.InvalidArgumentException; import org.xmlsh.core.Options; import org.xmlsh.core.SafeXMLStreamWriter; import org.xmlsh.core.UnexpectedException; import org.xmlsh.core.XValue; import org.xmlsh.core.io.OutputPort; import org.xmlsh.util.StringPair; import org.xmlsh.util.Util; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.BlockDeviceMapping; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DeleteTagsRequest; import com.amazonaws.services.ec2.model.DryRunResult; import com.amazonaws.services.ec2.model.DryRunSupportedRequest; import com.amazonaws.services.ec2.model.EbsBlockDevice; import com.amazonaws.services.ec2.model.EbsInstanceBlockDevice; import com.amazonaws.services.ec2.model.Filter; import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.InstanceBlockDeviceMapping; import com.amazonaws.services.ec2.model.InstanceState; import com.amazonaws.services.ec2.model.InstanceStateChange; import com.amazonaws.services.ec2.model.LaunchPermission; import com.amazonaws.services.ec2.model.Placement; import com.amazonaws.services.ec2.model.ProductCode; import com.amazonaws.services.ec2.model.Reservation; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.Volume; import com.amazonaws.services.ec2.model.VolumeAttachment; import com.amazonaws.services.ec2.model.VolumeType; public abstract class AWSEC2Command extends AWSCommand<AmazonEC2Client> { public AWSEC2Command() { super(); } protected void getEC2Client(Options opts) throws UnexpectedException, InvalidArgumentException { setAmazon(AWSClientFactory.newEC2lient(mShell, opts)); } protected boolean isDryRun( AmazonWebServiceRequest req ){ return bMayDryRun && req instanceof DryRunSupportedRequest; } protected <X extends AmazonWebServiceRequest> int dryRun(DryRunSupportedRequest<X> request) throws XMLStreamException, InvalidArgumentException, SaxonApiException, CoreException, IOException { DryRunResult<X> result ; try { result = this.getAWSClient().dryRun( request ); } catch( AmazonServiceException e ) { if( e.isRetryable()) throw e ; return super.handleException(e); } catch( AmazonClientException e){ if( e.getCause() instanceof AmazonServiceException ) return super.handleException((AmazonServiceException)e.getCause()); return super.handleException(e); } startResult(); startElement( "dry-run"); attribute( "success" , result.isSuccessful()); if( ! result.isSuccessful() ) textElement("message", result.getMessage()); endElement(); endResult(); return 0; } protected void writeStateChages(List<InstanceStateChange> states) throws IOException, XMLStreamException, SaxonApiException, CoreException { OutputPort stdout = this.getStdout(); mWriter = new SafeXMLStreamWriter( stdout.asXMLStreamWriter(getSerializeOpts())); startDocument(); startElement(this.getName()); for (InstanceStateChange state : states) { writeStateChange(state); } endElement(); endDocument(); closeWriter(); stdout.writeSequenceTerminator(getSerializeOpts()); } private void writeStateChange(InstanceStateChange change) throws XMLStreamException { startElement("state-change"); attribute("instance-id", change.getInstanceId()); InstanceState current = change.getCurrentState(); InstanceState prev = change.getPreviousState(); writeState("current", current); writeState("previous", prev); endElement(); } private void writeState(String elem, InstanceState state) throws XMLStreamException { startElement(elem); attribute("name", state.getName()); attribute("code", String.valueOf(state.getCode())); endElement(); } protected void writeReservation(Reservation res) throws XMLStreamException { startElement("reservation"); attribute("id", res.getReservationId()); attribute("requester-id", res.getRequesterId()); for (Instance inst : res.getInstances()) { startElement("instance"); attribute("instance-id", inst.getInstanceId()); attribute("image", inst.getImageId()); attribute("key-name", inst.getKeyName()); attribute("architecture", inst.getArchitecture()); attribute("client-token", inst.getClientToken()); attribute("lifecycle", Util.notNull(inst.getInstanceLifecycle())); attribute("instance-type", inst.getInstanceType()); attribute("kernel-id", inst.getKernelId()); attribute("platform", inst.getPlatform()); attribute("private-dns", inst.getPrivateDnsName()); attribute("private-ip", inst.getPrivateIpAddress()); attribute("public-dns", inst.getPublicDnsName()); attribute("public-ip", inst.getPublicIpAddress()); attribute("ramdisk-id", inst.getRamdiskId()); attribute("root-device-name", inst.getRootDeviceName()); attribute("spot-request-id", inst.getSpotInstanceRequestId()); attribute("state-transistion-reason", inst.getStateTransitionReason()); attribute("subnet-id", inst.getSubnetId()); attribute("state", inst.getState().getName()); attribute("virtualization-type", inst.getVirtualizationType()); attribute("vpcid", inst.getVpcId()); attribute("ami-launch-index", inst.getAmiLaunchIndex().toString()); attribute("launch-date", Util.formatXSDateTime(inst.getLaunchTime())); attribute("monitoring", inst.getMonitoring().getState()); attribute("source-dest-check", getSourceCheck(inst)); attribute("state-reason", getStateReason(inst)); writeProductCodes(inst.getProductCodes()); writeTags(inst.getTags()); writePlacement(inst.getPlacement()); writeInstanceBlockDeviceMappings(inst.getBlockDeviceMappings()); endElement(); } endElement(); } public void writeInstanceBlockDeviceMappings( List<InstanceBlockDeviceMapping> mappings) throws XMLStreamException { startElement("devices"); for (InstanceBlockDeviceMapping device : mappings) { writeInstanceDeviceMapping(device); } endElement(); } public void writeProductCodes(List<ProductCode> productCodes) throws XMLStreamException { if (productCodes == null) return; startElement("product-codes"); for (ProductCode code : productCodes) { startElement("product-code"); attribute("id", code.getProductCodeId()); endElement(); } endElement(); } public String getStateReason(Instance inst) { if (inst.getStateReason() != null) return inst.getStateReason().getCode(); else return ""; } public String getSourceCheck(Instance inst) { Boolean is = inst.getSourceDestCheck(); return is == null ? "false" : is.toString(); } public void writePlacement(Placement placement) throws XMLStreamException { startElement("placement"); attribute("availability-zone", placement.getAvailabilityZone()); attribute("group-name", placement.getGroupName()); attribute("tenancy", placement.getTenancy()); endElement(); } public void writeInstanceDeviceMapping(InstanceBlockDeviceMapping device) throws XMLStreamException { startElement("device"); attribute("name", device.getDeviceName()); EbsInstanceBlockDevice ebs = device.getEbs(); attribute("status", ebs.getStatus()); attribute("volume-id", ebs.getVolumeId()); attribute("attach-date", Util.formatXSDateTime(ebs.getAttachTime())); attribute("delete-on-termination", ebs.getDeleteOnTermination() .toString()); endElement(); } protected List<Tag> parseTags(List<XValue> tv) throws InvalidArgumentException { List<Tag> tags = new ArrayList<Tag>(); for (XValue xt : tv) { StringPair pair = new StringPair(xt.toString(), '='); tags.add(pair.hasLeft() ? new Tag(pair.getLeft(), pair.getRight()) : new Tag(pair.getRight()) ); } return tags; } protected void writeAttachements(List<VolumeAttachment> attachments) throws XMLStreamException { startElement("attachments"); for (VolumeAttachment attachment : attachments) writeAttachment(attachment); endElement(); } protected void writeAttachment(VolumeAttachment attachment) throws XMLStreamException { startElement("attachment"); attribute("delete-on-termination", AWSUtil.parseBoolean(attachment.getDeleteOnTermination())); attribute("attach-date", Util.formatXSDateTime(attachment.getAttachTime())); attribute("device", attachment.getDevice()); attribute("instance-id", attachment.getInstanceId()); attribute("volume-id", attachment.getVolumeId()); attribute("state", attachment.getState()); endElement(); } protected Collection<String> getIps(List<XValue> args) throws UnknownHostException { ArrayList<String> ips = new ArrayList<String>(args.size()); for (String sip : Util.toStringArray(args)) { ips.add(AWSUtil.resolveDNS(sip)); } return ips; } protected void writeBlockDeviceMappings( List<BlockDeviceMapping> deviceMappings) throws XMLStreamException { startElement("device-mappings"); for (BlockDeviceMapping mapping : deviceMappings) writeBlockDeviceMapping(mapping); endElement(); } private void writeBlockDeviceMapping(BlockDeviceMapping device) throws XMLStreamException { startElement("device"); attribute("name", device.getDeviceName()); EbsBlockDevice ebs = device.getEbs(); if (ebs != null) { attribute("shapshot-id", ebs.getSnapshotId()); attribute("delete-on-termination", ebs.getDeleteOnTermination()); attribute("volume-size", ebs.getVolumeSize()); attribute("volume-type", ebs.getVolumeType()); attribute("encrypted", ebs.getEncrypted()); attribute("iops", ebs.getIops()); } endElement(); } @Override public void attribute(String localName, boolean flag) throws XMLStreamException { attribute(localName, flag ? "true" : "false"); } protected void writeLaunchPermissions( List<LaunchPermission> launchPermissions) throws XMLStreamException { startElement("launch-permissions"); for (LaunchPermission p : launchPermissions) { writeLaunchPermission(p); } endElement(); } private void writeLaunchPermission(LaunchPermission p) throws XMLStreamException { startElement("launch-permissions"); if (!Util.isBlank(p.getGroup())) attribute("group", p.getGroup()); if (!Util.isBlank(p.getUserId())) attribute("user-id", p.getUserId()); endElement(); } protected void writeVolume(Volume volume) throws XMLStreamException { startElement("volume"); attribute("volume-id", volume.getVolumeId()); attribute("snapshot-id ", volume.getSnapshotId()); attribute("availability-zone", volume.getAvailabilityZone()); attribute("create-date", Util.formatXSDateTime(volume.getCreateTime())); attribute("size", volume.getSize().toString()); attribute("state", volume.getState()); attribute("volume-type", volume.getVolumeType()); attribute("iops", volume.getIops()); attribute("encrypted", volume.getEncrypted()); attribute("kms-key-id", volume.getKmsKeyId()); writeAttachements(volume.getAttachments()); writeTags(volume.getTags()); } protected Collection<Filter> parseFilters(List<String> values) { if (values == null || values.size() == 0) return null; ArrayList<Filter> filters = new ArrayList<Filter>(values.size()); for (String v : values) { StringPair nv = new StringPair(v, '='); Filter filter = new Filter().withName(nv.getLeft()).withValues( nv.getRightA().splitString(',')); filters.add(filter); } return filters; } protected Collection<BlockDeviceMapping> getBlockDeviceMappings(Options opts) throws InvalidArgumentException { List<XValue> blocks = opts.getOptValues("block-device-mapping"); if (blocks == null || blocks.size() == 0) return null; List<BlockDeviceMapping> mappings = new ArrayList<BlockDeviceMapping>( blocks.size()); for (XValue b : blocks) mappings.add(parseBlockDeviceMapping(b.toString())); // TBD return mappings; } /* * Mapping string from the original AWS CLI format The block device mapping * for the instance. This argument is passed in the form of * <devicename>=<blockdevice>. The devicename is the device name of the * physical device on the instance to map. The blockdevice can be one of the * following values: * * none - Suppresses an existing mapping of the device from the AMI used to * launch the instance. For example: "/dev/sdc=none". ephemeral[0..3] - An * instance store volume to be mapped to the device. For example: * "/dev/sdc=ephemeral0". * [snapshot-id]:[volume-size]:[delete-on-termination] * :[volume-type[:iops]]:[encrypted] - An Amazon EBS volume to be mapped to * the device. For example * "/dev/sdh=snap-7eb96d16::false:io1:500:encrypted". */ protected BlockDeviceMapping parseBlockDeviceMapping(String string) throws InvalidArgumentException { BlockDeviceMapping map = new BlockDeviceMapping(); StringPair pair = new StringPair(string, '='); String device = pair.getLeft(); // if( device.startsWith("/dev/")) // device = device.substring(5); if (!pair.hasRight()) { map.setNoDevice(device); return map; } String r = pair.getRight(); if (r.equals("none")) { map.setNoDevice(device); return map; } map.setDeviceName(device); // Ephemeral = virtual ? if (!r.contains(":")) { map.setVirtualName(r); return map; } // Parse out the EBS stuff // [snapshot-id]:[volume-size]:[delete-on-termination]:[volume-type[:iops]]:[encrypted] String aebs[] = r.split(":"); EbsBlockDevice ebs = new EbsBlockDevice(); // [snapshot-id]: if (aebs.length >= 1) { String snapshotId = aebs[0]; if (!Util.isBlank(snapshotId)) ebs.setSnapshotId(snapshotId); } // :[volume-size]: if (aebs.length >= 2) { if (!Util.isBlank(aebs[1])) ebs.setVolumeSize(new Integer(aebs[1])); } // [delete-on-termination]: if (aebs.length >= 3) { if (!Util.isBlank(aebs[2])) ebs.setDeleteOnTermination(Boolean.valueOf(Util .parseBoolean(aebs[2]))); } if (aebs.length >= 4) { // [volume-type[:iops]]:[encrypted] int i = 3; if (!Util.isBlank(aebs[i])) { ebs.setVolumeType(aebs[i]); if (aebs[i].equals(VolumeType.Io1.toString())) { i++; if (aebs.length <= i || Util.isBlank(aebs[i])) throw new InvalidArgumentException( "EBS block mapping with VolumeType :io1 MUST have PIOPS"); ebs.setIops(Integer.valueOf(aebs[i])); } i++; if (aebs.length > i) ebs.setEncrypted(Util.parseBoolean(aebs[i])); } } map.setEbs(ebs); return map; } protected int createTags(List<Tag> tags, List<String> resources) throws InvalidArgumentException, IOException, XMLStreamException, SaxonApiException { CreateTagsRequest request = new CreateTagsRequest().withTags(tags) .withResources(resources); traceCall("createTags"); getAWSClient().createTags(request); return 0; } protected void writeTags(List<Tag> tags) throws XMLStreamException { if (tags == null) return; startElement("tags"); for (Tag t : tags) writeTag(t); endElement(); } protected void writeTag(Tag tag) throws XMLStreamException { startElement("tag"); attribute( "key" , tag.getKey()); attribute("value", tag.getValue()); endElement(); } protected int deleteTags(List<Tag> tags, String[] resources) throws InvalidArgumentException, IOException, XMLStreamException, SaxonApiException { DeleteTagsRequest request = new DeleteTagsRequest().withTags(tags) .withResources(Arrays.asList(resources)); getAWSClient().deleteTags(request); return 0; } } // // // Copyright (C) 2008-2014 David A. Lee. // // The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is David A. Lee // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. //