Skip to content

Instantly share code, notes, and snippets.

@progrium
Created December 2, 2009 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save progrium/247547 to your computer and use it in GitHub Desktop.
Save progrium/247547 to your computer and use it in GitHub Desktop.
#!/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()
#!/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