#!/usr/bin/python
# -*- coding: utf-8; -*-
#
# (c) 2008-2010 Mandriva, http://www.mandriva.com/
#
# $Id: pulse2-package-server 5210 2010-02-04 17:45:08Z cdelfosse $
#
# This file is part of Pulse 2, http://pulse2.mandriva.org
#
# Pulse 2 is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Pulse 2 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Pulse 2.  If not, see <http://www.gnu.org/licenses/>.

"""
Pulse 2 Package Server Imaging module registration.
"""

import os
import sys
import uuid
from optparse import OptionParser
import logging
from twisted.internet import reactor

from mmc.site import mmcconfdir
from mmc.client import async
from pulse2.package_server.config import P2PServerCP

# Return codes
ERROR_NO_UUID = 1
ERROR_BAD_ARGUMENT = 2
ERROR_BAD_CONFIG_PATH = 3
ERROR_BAD_CONFIG = 4
ERROR_REGISTRATION_FAILURE = 5
ERROR_ALREADY_REGISTERED = 6

inifile = os.path.join(mmcconfdir, "pulse2", "package-server", "package-server.ini")
code = ERROR_REGISTRATION_FAILURE
log = logging.getLogger()

class BaseAction(object):
    """ Generic methods for an xmlrpc based action
    """
    def __init__(self, options):
        self.cacert = None
        self.localcert = None

        if self._check_options(options) is False:
            sys.exit(ERROR_BAD_ARGUMENT)

        if options.inifile:
            if not os.path.exists(options.inifile):
                log.error('No such file: %s' % options.inifile)
                sys.exit(ERROR_BAD_CONFIG_PATH)

        self.config = P2PServerCP()
        try:
            self.config.setup(options.inifile)
        except Exception, e:
            log.error('Error parsing conf file: %s' % e)
            sys.exit(ERROR_BAD_CONFIG)

        # Some magic ?
        self.config.imaging_api['mount_point'] = self.config.imaging_api['mount_point'].replace('/', '')

        self.client_url = "%s://%s:%s/%s" % (self.config.proto,
                                             self.config.public_ip,
                                             str(self.config.port),
                                             self.config.imaging_api['mount_point'])

        self.uuid = self.config.imaging_api['uuid']
        if not self.uuid:
            log.error("No uuid in config file: %s" % inifile)
            sys.exit(ERROR_NO_UUID)

        log.debug("Connecting from: %s" % self.client_url)
        log.debug("Connecting to: %s" % options.mmc_url)
        self.proxy = async.Proxy(options.mmc_url)

    def _check_options(self, options):
        ret = True
        if not options.mmc_url:
            log.error('Missing option: --mmc-agent-url')
            ret = False
        if options.certificates:
            certs = options.certificates.split(':')
            if len(certs)<>2:
                log.error('Bad option: --certificates argument must be \'cacert:localcert\'')
                ret = False
            else:
                self.cacert = certs[0]
                self.localcert = certs[1]
        return ret

    def run(self):
        raise NotImplemented


class CheckAction(BaseAction):
    def run(self):
        d = self.proxy.callRemote('imaging.isImagingServerRegistered', self.uuid)
        d.addCallback(self.resultOk)
        d.addErrback(self.resultError)

    def resultOk(self, result):
        global code

        if result is True:
            log.info('Imaging server already registered')
            code = ERROR_ALREADY_REGISTERED
        else:
            log.info('Imaging server not registered')
            code = 0
        reactor.stop()

    def resultError(self, error):
        log.error(error)
        reactor.stop()


class RegisterAction(BaseAction):
    def __init__(self, options):
        super(RegisterAction, self).__init__(options)
        self.name = options.name

    def _check_options(self, options):
        ret = super(RegisterAction, self)._check_options(options)
        if not options.name:
            log.error('Missing option: --name')
            ret = False
        return ret

    def run(self):
        d = self.proxy.callRemote('imaging.imagingServerRegister',
                                  self.name, self.client_url, self.uuid)
        d.addCallback(self.resultOk)
        d.addErrback(self.resultError)

    def resultOk(self, result):
        global code

        code, msg = result

        if code is True:
            log.info('Registration succeeded')
            code = 0
        else:
            log.error('Registration failed: %s' % msg)
            code = ERROR_REGISTRATION_FAILURE

        reactor.stop()

    def resultError(self, error):
        global code

        log.error(error)
        code = ERROR_REGISTRATION_FAILURE
        reactor.stop()


def generate_uuid():
    """
    Generate an uuid
    """
    print uuid.uuid1()

if __name__ == '__main__':
    code = 0

    # Declare options
    parser = OptionParser()
    parser.add_option("-m", "--mmc-agent-url", dest="mmc_url", metavar="URL",
                      help="MMC Agent URL")
    parser.add_option("-n", "--name", dest="name", metavar="NAME",
                      help="Imaging server name (mandatory)")
    parser.add_option("-c", "--certificates", dest="certificates", metavar="cacert:localcert",
                      help="Verify peer with those certs")
    parser.add_option("-i", "--inifile", dest="inifile", metavar="FILE", default=inifile,
                      help="Alternate configuration file")
    parser.add_option("-u", "--uuid", dest="generate", default=False, action="store_true",
                      help="Generate an UUID")
    parser.add_option("-C", "--check", dest="check", default=False, action="store_true",
                      help="Check if UUID is already registered")
    parser.add_option("-q", "--quiet", dest="quiet", default=False, action="store_true",
                      help="Be quiet")
    parser.add_option("-V", "--verbose", dest="verbose", default=False, action="store_true",
                      help="Be more verbose")
    (options, args) = parser.parse_args()

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(0)

    if options.check and options.generate:
        parser.error('Options -C and -u are mutually exclusive')
    if options.quiet and options.verbose:
        parser.error('Options -V and -q are mutually exclusive')

    # Logging options
    loglevel = logging.INFO
    if options.quiet:
        loglevel = logging.ERROR
    if options.verbose:
        loglevel = logging.DEBUG
    logging.basicConfig(format='%(levelname)s - %(message)s', level=loglevel)

    # Handle generate action
    if options.generate:
        generate_uuid()
        sys.exit(0)

    # For the rest, it is handled by *Actions
    if options.check:
        action = CheckAction(options)
    else:
        action = RegisterAction(options)

    action.run()
    reactor.run()
    sys.exit(code)
