#!/usr/bin/env python
#
# Created as part of the StratusLab project (http://stratuslab.eu),
# co-funded by the European Commission under the Grant Agreement
# INFSO-RI-261552."
#
# Copyright (c) 2010, SixSq Sarl
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import sys

sys.path.append('/var/lib/stratuslab/python')

from stratuslab.Runner import Runner
from stratuslab.Creator import Creator
from stratuslab.Runnable import Runnable
from stratuslab.ConfigHolder import ConfigHolder
from stratuslab.Util import printAction
from stratuslab.Util import printStep
from stratuslab.commandbase.StorageCommand import StorageCommand

class MainProgram(Runnable):
    '''A command-line program to run a virtual machine.'''

    def parse(self):
        options = Runner.defaultRunOptions()

        self.parser.add_option('--quiet', dest='quiet',
                help='quiet output. Only returns <VM-ID>, <IP>',
                action='store_true', default=False)

        self.parser.add_option('-n', '--number', dest='instanceNumber',
                help='number of machines to start (default 1)', metavar='INT',
                default=options['instanceNumber'], type='int')

        self.parser.add_option('--local-ip', dest='isLocalIp', action='store_true',
                help='By default, virtual machines are assigned a public IP address. ' \
                'With this option, a local address is provided, which means that it ' \
                'not be reachable from the outside, but will be reachable from other ' \
                'instances in the same data-center.',
                default=False)

        self.parser.add_option('--private-ip', dest='isPrivateIp', action='store_true',
                help='By default, virtual machines are assigned a public IP address. ' \
                'With this option, a private address is provided, which means that it ' \
                'not be reachable anywhere. This is useful for instances that initiate '\
                'the connection to other machinces.',
                default=False)

        self.parser.add_option('--save', dest='saveDisk', action='store_true',
                help='save image after VM shutdown',
                default=False)

        self.parser.add_option('--author-email', dest='authorEmail',
                help='Used with --save option. Email address of the author of ' \
                'the new image. After image is saved a notification is sent ' \
                'with further instructions.',
                default='', metavar='EMAIL')

        self.parser.add_option('--author', dest='author',
                help='Used with --save option. Author of the new image',
                default='', metavar='NAME')

        self.parser.add_option('--image-version', dest='newImageGroupVersion',
                help='Used with --save option. Version for the new image.',
                default='', metavar='VERSION')

        self.parser.add_option('--title', dest='title',
                help='Used with --save option. Title of the new image',
                default='', metavar='TEXT')

        self.parser.add_option('--comment', dest='comment',
                help='Used with --save option. Description of the new image',
                default='', metavar='TEXT')

        self.parser.add_option('--marketplace-endpoint-newimage', dest='marketplaceEndpointNewimage',
                help='Used with --save option. Marketplace to register the new image manifest in. '
                'No default. If not provided, either base image Marketplace or defined '
                'by cloud site will be used.',
                default='', metavar='URL')

        self.parser.add_option('-o', '--output', dest='outVmIdsFile',
                help='save vm-id to a file', metavar='FILE',
                default=None)

        self.parser.add_option('--volatile-disk', dest='extraDiskSize',
                help='volatile data disk size in GB', metavar='INT',
                action='callback', callback=self.diskSizeOptionCallback,
                default=0, type='int')

        self.parser.add_option('--persistent-disk', dest='persistentDiskUUID',
                help='persistent disk UUID',
                default=None)

        self.parser.add_option('--readonly-disk', dest='readonlyDiskId',
                help='marketplace readonly disk image ID',
                default=None, metavar='MARKETPLACEID')

        self.parser.add_option('--qcow-disk-format', dest='useQcowDiskFormat',
                help='launch instance from an image in qcow2 disk format. Only ' \
                'used when image is provided as URL. When image is given by ID, disk ' \
                'format is inferred from the image metadata.',
                action='store_true',
                default=False)

        self.parser.add_option('--address', dest='specificAddressRequest',
                help='request a specific ip address',
                metavar='IP', default=None)

        self.parser.add_option('--no-check-image-url', dest='noCheckImageUrl',
                help='Do not check image availability. Image availability is ',
                action='store_true',
                default=False)

        self.parser.add_option('--vm-name', dest='vmName',
                help='name of VM. If not given, a default name will be assigned by cloud layer.',
                metavar='NAME', default=options['vmName'])
        
        self.parser.add_option('--notify', dest='msgRecipients', action='append',
                help='recipient coordinates (host,vhost,user,pass,queue)',
                default=[])

        StorageCommand.addPDiskEndpointOptions(self.parser)

        super(MainProgram, self).parse()


    def diskSizeOptionCallback(self, option, opt_str, value, parser):
        setattr(parser.values, option.dest, 1024*value)

    def checkOptions(self):

        super(MainProgram, self).checkOptions()

        if self.options.saveDisk:
            pre_message = 'With the --save option, please '
            if not self.options.author:
                self.parser.error(pre_message + 'provide a valid author name of the image (--author).')
            if not self.options.authorEmail:
                self.parser.error(pre_message + 'provide a valid email address of the author of the image (--author-email).')
            if not self.options.newImageGroupVersion:
                self.parser.error(pre_message + 'provide a version number for the new image (--image-version).')
            if not self.options.title:
                self.parser.error(pre_message + 'provide a title for the image (--title).')

            if not self.options.comment:
                self.parser.error(pre_message + 'provide a comment for the image (--comment).')

    def doWork(self):
        configHolder = ConfigHolder(self.options.__dict__, self.config)
        
        if self.options.saveDisk:
            creator = Creator(self.image, configHolder)
            creator.createRunner()
            runner = creator.runner
        else:
            runner = Runner(self.image, configHolder)
        
        if self.options.listType:
            runner.listInstanceTypes()
        else:
            runner.runInstance()

if __name__ == '__main__':
    try:
        MainProgram()
    except KeyboardInterrupt:
        print '\n\nExecution interrupted by the user... goodbye!'
