Created
December 2, 2009 20:37
-
-
Save progrium/247547 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from subprocess import call | |
import sys, os, time | |
# TODO: ssh connect, find key | |
# TODO: options | |
# TODO: specify and set user data (hostname, ip, mounts) | |
CMD_PREFIX = 'euca' | |
CMD_SILENT = False | |
KEY_INDEX_PATH = os.path.expanduser('~/.nebula/keys') | |
def nebcmd(name, extra=None): | |
cmd = '%s-%s' % (CMD_PREFIX, name) | |
if not CMD_SILENT: | |
cmd = '%s %s' % (cmd, '2>/dev/null') | |
if extra: | |
cmd = '%s %s' % (cmd, extra) | |
return cmd | |
def privatekey_path(keypair, set_path=None): | |
if not set_path: | |
try: | |
with open('%s/%s' % (KEY_INDEX_PATH, keypair)) as f: | |
return f.read().strip() | |
except IOError: | |
return None | |
else: | |
if not os.path.exists(KEY_INDEX_PATH): | |
os.makedirs(KEY_INDEX_PATH) | |
with open('%s/%s' % (KEY_INDEX_PATH, keypair), 'a') as f: | |
f.write('%s\n' % set_path) | |
def keypairs(): | |
with os.popen(nebcmd('describe-keypairs', "| cut -f2")) as stdout: | |
return [line.strip() for line in stdout.readlines()] | |
def launch_instance(image_id, keypair): | |
with os.popen(nebcmd('run-instances -k %s %s' % (keypair, image_id), "| grep INSTANCE | cut -f2")) as stdout: | |
return stdout.readlines()[0].strip() | |
def wait_for_ip(instance_id): | |
ip = '0.0.0.0' | |
while ip == '0.0.0.0': | |
yield False | |
time.sleep(1) | |
with os.popen(nebcmd('describe-instances', "| grep %s | cut -f5" % instance_id)) as stdout: | |
ip = stdout.readlines()[0].strip() | |
yield ip | |
def wait_for_status(instance_id, target_status): | |
status = None | |
while status != target_status: | |
yield False | |
time.sleep(1) | |
with os.popen(nebcmd('describe-instances', "| grep %s | cut -f6" % instance_id)) as stdout: | |
status = stdout.readlines()[0].strip() | |
if target_status != 'terminated' and status == 'terminated': | |
raise Exception("Instance unexpectedly terminated.") | |
yield True | |
def image_index(): | |
with os.popen(nebcmd('describe-images', "| grep emi- | cut -f2,3")) as stdout: | |
image_list = stdout.readlines() | |
return [i.strip().split('\t') for i in image_list] | |
def out(s): | |
sys.stdout.write(s) | |
sys.stdout.flush() | |
def select(options, prompt): | |
for i, option in enumerate(options): | |
print "[%i]\t%s" % (i, '\t'.join(option)) | |
return int(raw_input(prompt)) | |
if __name__ == '__main__': | |
index = image_index() | |
image_id = index[select(index, "Select Image: ")][0] | |
keypairs = keypairs() | |
keypair = keypairs[0 if len(keypairs) == 1 else select(keypairs, "Select Keypair: ")] | |
out("[%s] Launching %s" % (keypair, image_id)) | |
instance_id = launch_instance(image_id, keypair) | |
try: | |
for running in wait_for_status(instance_id, 'running' ): | |
out('.' if not running else '.\n') | |
print "[%s] Running as %s" % (keypair, instance_id) | |
out("[%s] Waiting for IP." % keypair) | |
for ip in wait_for_ip(instance_id): | |
out('.' if not ip else '%s\n' % ip) | |
except: | |
print "Killing instance." | |
os.popen(nebcmd('terminate-instances %s' % instance_id)) | |
pk = privatekey_path(keypair) | |
if not pk: | |
while not os.path.exists(pk or ''): | |
pk = os.path.expanduser(raw_input("Private key path for %s: " % keypair)) | |
privatekey_path(keypair, pk) | |
with os.popen("""ssh -i %s root@%s 'echo "Hello world" > foobar'""" % (pk, ip)) as stdout: | |
print stdout.readlines() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from subprocess import call | |
from datetime import datetime | |
import sys, urllib, time, os | |
# TODO: allow specifying plus intelligent default of image size | |
# TODO: check you're in proper euca profile... | |
# TODO someday: mount a temporary scratch NFS volume for the image destination | |
# TODO: self update this script | |
default_name_value = None | |
def default_name(): | |
global default_name_value | |
if not default_name_value: | |
ami_path = urllib.urlopen(os.environ['EC2_URL'].replace('/services/Eucalyptus', '/latest/meta-data/ami-manifest-path')).read() | |
default_name_value = '%s-%s' % (ami_path.split('/')[5], datetime.today().strftime('%Y%m%d')) | |
return default_name_value | |
def check_environment(): | |
if call(['which','ec2din'], stdout=open('/dev/null')) or call(['which','euca-bundle-vol'], stdout=open('/dev/null')): | |
print "Unable to run ec2 or euca tools." | |
sys.exit(1) | |
if call(['ec2din'], stdout=open('/dev/null')): | |
print "Unable to access Nebula." | |
sys.exit(1) | |
def check_size(dir): | |
return int(os.popen("""ruby -e 'puts `df %s`.split("\n").last.split(" ")[3]'""" % dir).read().strip()) | |
def fix_time(): | |
call(['date', '-s', urllib.urlopen('http://j.mp/now-utc').read()]) | |
def get_nfs_mounts(): | |
return [l.split(' ')[2] for l in os.popen('mount | grep "type nfs"').read().split("\n")[:-1]] | |
def make_snapshot(name, scratch='/mnt', size=4096): | |
if size * 1024 > check_size(scratch): | |
print "%s does not have enough disk space." % scratch | |
make_snapshot(name, raw_input("Scratch path [%s]: " % scratch) or scratch, size) | |
else: | |
cmd = ['euca-bundle-vol', '-d', scratch, '-e', ','.join(['/tmp', scratch] + get_nfs_mounts()), '--no-inherit', '-s', str(size)] | |
print ' '.join(cmd) | |
bundle_failed = call(cmd) | |
if bundle_failed: | |
print "Image bundling failed." | |
sys.exit(1) | |
else: | |
time.sleep(3) | |
cmd = ['euca-upload-bundle', '-b', name, '-m', '%s/image.manifest.xml' % scratch] | |
print ' '.join(cmd) | |
upload_failed = call(cmd) | |
if upload_failed: | |
print "Bundle upload failed." | |
sys.exit(1) | |
else: | |
time.sleep(1) | |
cmd = ['euca-register', '%s/image.manifest.xml' % name] | |
print ' '.join(cmd) | |
register_failed = call(cmd) | |
if register_failed: | |
print "Image registration failed." | |
sys.exit(1) | |
else: | |
"Snapshot taken!" | |
if __name__ == '__main__': | |
if '--fixtime' in sys.argv: | |
fix_time() | |
else: | |
check_environment() | |
make_snapshot(raw_input("Image Name [%s]: " % default_name()) or default_name()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment