#!/usr/bin/python
# -*- coding: utf-8 -*-

# 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
import sys
import os
from euca2ools import Euca2ool, Util, ConnectionFailed

usage_string = \
    """
Starts instances.

euca-run-instances [-n, --instance-count count] [-g, --group group_name] [-k, --keypair keyname] 
[-d user_data] [-f user_data_file] [--addressing addressing] [-t, --instance-type instance_type] 
[-z, --availability-zone zone] [--kernel kernel_id] [--ramdisk ramdisk_id] [-b block_device_mapping]
[--monitor] [-s, --subnet subnet_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).

-b, --block-device-mapping      	Block device mapping for the instance(s). Option may be used multiple times.

--monitor				Enable monitoring for instance.

-s, --subnet				Amazon VPC subnet ID for the instance.

"""


def usage(status=1):
    print usage_string
    Util().usage()
    sys.exit(status)


def version():
    print Util().version()
    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:b:', [
            'key=',
            'kernel=',
            'ramdisk=',
            'instance-count=',
            'instance-type=',
            'group=',
            'user-data=',
            'user-data-file=',
            'addressing=',
            'availability-zone=',
            'block-device-mapping=',
            'monitor',
            'subnet_id=',
            ])
    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
    block_device_map_args = []
    block_device_map = None
    monitor = False
    subnet_id = 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 ('-b', '--block-device-mapping'):
            block_device_map_args.append(value)
        elif name == '--monitor':
            monitor = True
        elif name in ('-s', '--subnet'):
            subnet_id = value
        elif name in ('-h', '--help'):
            usage(0)
        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)
        try:
            euca_conn = euca.make_connection()
        except ConnectionFailed, e:
            print e.message
            sys.exit(1)
        if block_device_map_args:
            block_device_map = \
                euca.parse_block_device_args(block_device_map_args)
        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,
                block_device_map=block_device_map,
                monitoring_enabled=monitor,
                subnet_id=subnet_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()

