A few years ago, I found myself attaching volumes to instances with some frequency. The volume often came from a snapshot which contained some test data. Like any lazy programmer, I didn’t want to do this work over and over again! I wrote this little utility which would examine the user data and mount a pre-existing volume, or create a new volume from a snapshot and attach that. Here’s the code;
import java.io.IOException;
import java.util.List;
import java.util.StringTokenizer;
import com.xerox.amazonws.ec2.AttachmentInfo;
import com.xerox.amazonws.ec2.EC2Exception;
import com.xerox.amazonws.ec2.EC2Utils;
import com.xerox.amazonws.ec2.Jec2;
import com.xerox.amazonws.ec2.VolumeInfo;
public class AttachVolume {
public static void main(String [] args) {
try {
String userData = EC2Utils.getInstanceUserdata();
StringTokenizer st = new StringTokenizer(userData);
String accessId = st.nextToken();
String secretKey = st.nextToken();
String volumeOrSnapId = st.nextToken();
Jec2 ec2 = new Jec2(accessId, secretKey);
String volumeId = null;
if (volumeOrSnapId.startsWith("snap-")) {
String zone = EC2Utils.getInstanceMetadata("placement/availability-zone");
// create volume from snapshot and wait
VolumeInfo vinf = ec2.createVolume(null, volumeOrSnapId, zone);
volumeId = vinf.getVolumeId();
List<VolumeInfo> vols = ec2.describeVolumes(new String [] {volumeId});
while (!vols.get(0).getStatus().equals("available")) {
System.out.println(vols.get(0).getStatus());
try { Thread.sleep(2); } catch (InterruptedException ex) {}
vols = ec2.describeVolumes(new String [] {volumeId});
}
}
if (volumeOrSnapId.startsWith("vol-")) {
volumeId = volumeOrSnapId;
}
// attach volume and wait
String instanceId = EC2Utils.getInstanceMetadata("instance-id");
ec2.attachVolume(volumeId, instanceId, "/dev/sdh");
List<VolumeInfo> vols = ec2.describeVolumes(new String [] {volumeId});
while (!vols.get(0).getAttachmentInfo().get(0).getStatus().equals("attached")) {
System.out.println(vols.get(0).getAttachmentInfo().get(0).getStatus());
try { Thread.sleep(2); } catch (InterruptedException ex) {}
vols = ec2.describeVolumes(new String [] {volumeId});
}
} catch (Exception ex) {
System.err.println("Couldn't complete the attach : "+ex.getMessage());
ex.printStackTrace();
System.exit(-1);
}
}
}
Requirements
- Java Runtime Environment (1.5 or greater)
- Typica + and it’s dependencies
- This utility (compiled)
A Few Words About the Code
The first thing you’ll notice is that user data is being parsed. The expectations are that the following items are passed via user data;
- access id – AWS Access Id
- secret key – AWS Secret Key
- volumeOrSnapId – either a volume ID or snapshot ID
The code inspects the last parameter to see if it is a snapshot id. If so, it creates a volume and waits for it to become “available”. One that’s done, it gets the instance ID from meta data and attaches the volume at a hard-coded device. (obviously, this could be in user data which is an exercise I’ll leave to the reader)
On a linux machines, I’d often call this from the /etc/rc.local script. I should also note that this works just as well with Eucalyptus due to its API fidelity with Amazon EC2
There you have it!



