#
# Copyright (c) 2014 Piston Cloud Computing, Inc. All Rights Reserved.
#
#    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.
#


"""
Run tempest and upload results to Refstack.

This module deals with generating a working tempest conf file from
the environment variables (usually populated by sourcing openrc.sh)

This is currently just built for Havana tempest.
We're also just starting with nova-net and not neutron support.
TODO:
* generate config

"""
import argparse
import ConfigParser
import logging
import os
import requests
import subprocess


class Test:
    log_format = "%(asctime)s %(name)s %(levelname)s %(message)s"
    base_config_file = os.path.join(
        os.path.abspath(os.path.dirname(__file__)),
        'tempest.conf')

    expected_env = {'OS_AUTH_URL': "uri",
                    'OS_TENANT_NAME': "admin_tenant_name",
                    'OS_USERNAME': "admin_username",
                    'OS_PASSWORD': "admin_password"}

    def __init__(self, args):
        '''Prepare a tempest test against a cloud.'''
        self.logger = logging.getLogger("execute_test")
        self.console_log_handle = logging.StreamHandler()
        self.console_log_handle.setFormatter(
            logging.Formatter(self.log_format))
        self.logger.addHandler(self.console_log_handle)

        if args.verbose > 1:
            self.logger.setLevel(logging.DEBUG)
        elif args.verbose == 1:
            self.logger.setLevel(logging.INFO)
        else:
            self.logger.setLevel(logging.CRITICAL)

        # assign local vars to match args
        self.url = args.url
        self.test_id = args.test_id
        self.tempest_dir = args.tempest_dir
        self.output_conf = os.path.join(self.tempest_dir, 'tempest.config')
        self.tempest_script = os.path.join(self.tempest_dir, 'run_tests.sh')

        # set up object config parser
        self.config_parser = ConfigParser.SafeConfigParser()
        self.config_parser.read(self.base_config_file)

        #import config
        self.import_config_from_env()

        # write the config file
        self.config_parser.write(open(self.output_conf, 'w+'))

        #prep cloud based on new config
        self.prepare_cloud()

    def import_config_from_env(self):
        """create config from environment variables if set otherwise
        promt user for values"""
        for env_var, key in self.expected_env.items():
            if not os.environ.get(env_var):
                value = raw_input("Enter value for %s: " % env_var)
            else:
                value = os.environ.get(env_var)

            self.config_parser.set('identity', key, value)

    def prepare_cloud(self):
        """triggers tempest auto generate code to add users and setup image"""
        #TODO davidlenwell: figure out how to import and run code in
        #                   scripts/prep_cloud.py
        pass

    def post_test_result(self):
        '''Post the combined results back to the server.'''
        self.logger.info('Send back the result')

        with open(self.result, 'rb') as result_file:
            # clean out any passwords or sensitive data.
            result_file = self._scrub_sensitive_data(result_file)
            # send the file home.
            payload = {'file': result_file, 'test_id': self.test_id}
            self._post_to_api('post-result', payload)

    def _scrub_sensitive_data(self, results_file):
        '''stub function for cleaning the results before sending them back.'''
        return results_file

    def _post_status(self, message):
        '''this function posts status back to the api server
        if it has a test_id to report it with.'''
        if self.test_id:
            payload = {'test_id': self.test_id, 'status': message}
            self._post_to_api('update-test-status', payload)

    def _post_to_api(self, method, payload):
        '''This is a utility function for posting to the api. it is used by
        both _post_status and post_test_result'''
        try:
            url = '%s/v1/%s' % (self.url, method)
            requests.post(url, payload)
            self.logger.info('posted successfully')
        except Exception as e:
            #TODO davidlenwell: be more explicit with exceptions.
            self.logger.critical('failed to post %s - %s ' % (url,e))
            raise

    def run(self):
        '''Execute tempest test against the cloud.'''
        try:
            cmd = (self.tempest_script, '-C', self.output_conf)
            subprocess.check_output(cmd, shell=True)

            self.post_test_result()

        except subprocess.CalledProcessError as e:
            self.logger.error('%s failed to complete' % (e))


if __name__ == '__main__':
    ''' Generate tempest.conf from a tempest.conf.sample and then run test.'''
    parser = argparse.ArgumentParser(description='Starts a tempest test',
                                     formatter_class=argparse.
                                     ArgumentDefaultsHelpFormatter)

    parser.add_argument('-s', '--silent',
                        action='store_true',
                        help='rigged for silent running')

    parser.add_argument("-v", "--verbose",
                        action="count",
                        help="show verbose output")

    parser.add_argument("--url",
                        action='store',
                        required=False,
                        default='https://api.refstack.org',
                        type=str,
                        help="refstack API url \
                               retrieve configurations. i.e.:\
                               --url https://127.0.0.1:8000")

    parser.add_argument("--test-id",
                        action='store',
                        required=False,
                        dest='test_id',
                        type=int,
                        help="refstack test ID i.e.:\
                                       --test-id 1234 ")

    parser.add_argument("--tempest-dir",
                        action='store',
                        required=False,
                        dest='tempest_dir',
                        default='test_runner/src/tempest',
                        help="tempest directory path")

    args = parser.parse_args()

    test = Test(args)
    test.run
