#!/usr/bin/env python

# Software License Agreement (BSD License)
#
# Copyright (c) 2009, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
# without modification, are permitted provided that the following conditions
# are met:
#
#   Redistributions of source code must retain the above
#   copyright notice, this list of conditions and the
#   following disclaimer.
#
#   Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the
#   following disclaimer in the documentation and/or other
#   materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: Neil Soman neil@eucalyptus.com

import getopt, sys, os
from euca2ools import Euca2ool, Util

usage_string = """
Starts instances.

euca-run-instances [-n, --instance-count count] [-g, --group group_name] [-k, --keypair keyname] 
[--addressing addressing] [-t, --instance-type instance_type] [-z, --availability-zone zone] 
[--kernel kernel_id] [--ramdisk ramdisk_id] [-h, --help] [--version] [--debug] image_id 

REQUIRED PARAMETERS
	
image_id			identifier for the image to run. 

OPTIONAL PARAMETERS

-n, --instance-count		Number of instances to run.
	
-g, --group			Security group to run the instance under.

-k, --keypair			Name of a (previously created) keypair to associate with this reservation.		

-d, --user-data			User data for instances read from the command line.

-f, --user-data-file		User data for instances as a filename.

--addressing			Addressing mode (e.g., private).

-t, --instance-type		VM Image type to run the instance(s) as (default: m1.small).

-z, --availability-zone		Availability zone to run the instance(s) in.

--kernel			Id of the kernel to be used to launch instance(s).

--ramdisk			Id of the ramdisk to be used to launch instance(s).

"""

version_string = """    euca-run-instances version: 1.0 (BSD)"""

def usage():
    print usage_string
    Util().usage()

def version():
    print version_string
    sys.exit()

def display_reservations(reservation):
    reservation_string = '%s\t%s' % (reservation.id, reservation.owner_id)
    group_delim = '\t'
    for group in reservation.groups:
	reservation_string += '%s%s' % (group_delim, group.id)
	group_delim = ', '
    print 'RESERVATION\t%s' % (reservation_string) 
    for instance in reservation.instances:
	instance_string = '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s' % (instance.id, instance.image_id, instance.public_dns_name, instance.private_dns_name, instance.state, instance.key_name, instance.launch_time, instance.kernel, instance.ramdisk)
	print 'INSTANCE\t%s' % (instance_string)

def read_user_data(user_data_filename):
    USER_DATA_CHUNK_SIZE = 512
    user_data = "";
    user_data_file = open(user_data_filename, "r")
    while 1:
	data = user_data_file.read(USER_DATA_CHUNK_SIZE)
	if not data:
	    break
	user_data += data
    user_data_file.close()
    return user_data

def main():
    euca = None
    try:
        euca = Euca2ool('k:n:t:g:d:f:z:',
                                   ['key=', 'kernel=', 'ramdisk=', 'instance-count=', 'instance-type=', 
				    'group=', 'user-data=', 'user-data-file=', 'addressing=', 'availability-zone='])
    except Exception, e:
	print e
        usage()
 
    image_id = None
    keyname = None
    kernel_id = None
    ramdisk_id = None
    min_count = 1
    max_count = 1
    instance_type = 'm1.small' 
    group_names = [] 
    user_data = None
    user_data_file = None
    addressing_type = None
    zone = None
    for name, value in euca.opts:
        if name in ('-k', '--key'):
	    keyname = value
	elif name == '--kernel':
	    kernel_id = value
	elif name == '--ramdisk':
	    ramdisk_id = value
	elif name in ('-n', '--instance-count'):
	    counts = value.split('-')
	    if (len(counts) > 1):
		min_count = int(counts[0])
		max_count = int(counts[1])
	    else:
		min_count = max_count = int(counts[0])
	elif name in ('-t', '--instance-type'):
	    instance_type = value
	elif name in ('-g', '--group'):
	    group_names.append(value)
	elif name in ('-d', '--user-data'):
	    user_data = value
	elif name in ('-f', '--user-data-file'):
	    user_data_file = value
	elif name == '--addressing':
	    addressing_type = value
	elif name in ('-z', '--availability-zone'):
	     zone = value
        elif name in ('-h', '--help'):
            usage()
	elif name == '--version':
	    version()

    for arg in euca.args:
	image_id = arg
	break

    if image_id:
	if not user_data:
	    if user_data_file:
        	try:
            	    euca.validate_file(user_data_file)
        	except FileValidationError:
            	    print 'Invalid user data file path'
            	    sys.exit(1)
		user_data = read_user_data(user_data_file)
        euca_conn = euca.make_connection()
	try:
            reservation = euca_conn.run_instances(image_id = image_id,
					      min_count = min_count,
					      max_count = max_count,
					      key_name = keyname,
					      security_groups = group_names,
					      user_data = user_data,
					      addressing_type = addressing_type,
					      instance_type = instance_type,
					      placement = zone,
					      kernel_id = kernel_id,
					      ramdisk_id = ramdisk_id)
        except Exception, ex:
            euca.display_error_and_exit('%s' % ex)

        display_reservations(reservation)
    else:
	print 'image_id must be specified'
	usage()

if __name__ == "__main__":
    main()
 
