#!/usr/bin/env python
# Copyright (c) 2012 Arcus
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions
# of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import socket
import utils
import os
from subprocess import call
try:
    import simplejson as json
except ImportError:
    import json

class ClientException(BaseException):
    pass

class AuthException(BaseException):
    pass

API_URL = 'https://nucleo.arcus.io/api/v1'

class Client(object):
    """
    Arcus Client

    """
    def __init__(self, username=None, password=None, url=API_URL, \
        api_key=None):
        self._api_url = url
        self._username = username
        self._password = password
        self._api_key = api_key
        self._logged_in = False
        self._meta = {}
        if self._username and self._password:
            self._login()
        elif not self._api_key:
            raise ClientException('You must specify a username and password or api key')

    def _request(self, path='', method='get', data=None, api_key=None, params={}):
        data = utils.api_request(self._api_url, path, method=method, \
            data=data, api_key=api_key, params={})
        if data.status_code == 403:
            raise AuthException('Unauthorized')
        return data

    def _login(self):
        user_data = {'username': self._username, 'password': self._password}
        resp = self._request('/login', method='post', data=user_data)
        if resp.status_code == 200:
            self._logged_in = True
        else:
            raise AuthException(data.get('error', 'Login fail'))
        data = {}
        try:
            data = json.loads(resp.content)
            self._meta = data.get('meta', {})
            self._api_key = data.get('meta', {}).get('api_key')
        except:
            pass
        return data

    def get_meta(self):
        """
        Returns meta user info

        """
        return self._meta

    def get_apps(self):
        """
        Returns dict of applications

        :returns: Applications as dict

        """
        data = self._request(path='/apps', method='get', api_key=self._api_key)
        if data.status_code == 200:
            return data.json.get('apps')
        else:
            raise ClientException(data.content)

    def get_app(self, name=None):
        """
        Returns data for specified application

        :returns: Application data as dict

        """
        data = self._request('/apps/{0}'.format(name), method='get',
            api_key=self._api_key)
        if data.status_code == 200:
            return data.json.get('details')
        else:
            raise ClientException(data.content)

    def get_app_stats(self, name=None):
        """
        Returns statistics for specified application

        :returns: Application statistics as dict

        """
        data = self._request('/apps/{0}/stats'.format(name), method='get',
            api_key=self._api_key)
        if data.status_code == 200:
            return data.json.get('stats')
        else:
            raise ClientException(data.content)

    def register_node(self):
        """
        Registers current machine with Arcus Cloud

        """
        node_name = socket.gethostname()
        # call puppet to register
        data = self._request('/nodes/register', method='post', \
            data={'node_name': node_name}, api_key=self._api_key)
        if data.status_code == 200:
            data = json.loads(data.content)
            puppet_master = data.get('puppet_master')
            key = data.get('key')
            # write key
            with open('/etc/arcus.key', 'w') as f:
                f.write(key)
            # clear existing certs
            call('find /etc/puppet -name \"{0}.pem\" -delete 2>&1 > /dev/null'.format(node_name), \
                shell=True)
            # run puppet
            res = call('puppet agent -t --server {0} 2>&1 > /dev/null'.format(\
                puppet_master), shell=True)
            # puppet will return a one as waitforcert was not specified
            if res == 1:
                return True
            else:
                raise ClientException('Error registering: {0}'.format(\
                    res))
        else:
            raise ClientException(data.content)
