# Copyright (c) 2014 Mirantis Inc.
#
# 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.

from testtools import testcase

from sahara.tests.integration.configs import config as cfg
from sahara.tests.integration.tests import base as b
from sahara.tests.integration.tests import edp
from sahara.tests.integration.tests import scaling
from sahara.tests.integration.tests import swift
from sahara.utils import edp as utils_edp
from sahara.utils import files as f


class HDP2GatingTest(swift.SwiftTest, scaling.ScalingTest,
                     edp.EDPTest):

    config = cfg.ITConfig().hdp2_config
    SKIP_EDP_TEST = config.SKIP_EDP_TEST
    SKIP_SWIFT_TEST = config.SKIP_SWIFT_TEST
    SKIP_SCALING_TEST = config.SKIP_SCALING_TEST

    def setUp(self):
        super(HDP2GatingTest, self).setUp()
        self.cluster_id = None
        self.cluster_template_id = None
        self.ng_template_ids = []

    def _prepare_test(self):
        self.hdp2_config = cfg.ITConfig().hdp2_config
        self.floating_ip_pool = self.common_config.FLOATING_IP_POOL
        self.internal_neutron_net = None
        if self.common_config.NEUTRON_ENABLED:
            self.internal_neutron_net = self.get_internal_neutron_net_id()
            self.floating_ip_pool = (
                self.get_floating_ip_pool_id_for_neutron_net())

        self.hdp2_config.IMAGE_ID, self.hdp2_config.SSH_USERNAME = (
            self.get_image_id_and_ssh_username(self.hdp2_config))

    @b.errormsg("Failure while 'rm-nn' node group template creation: ")
    def _create_rm_nn_ng_template(self):
        template = {
            'name': 'test-node-group-template-hdp2-rm-nn',
            'plugin_config': self.hdp2_config,
            'description': 'test node group template for HDP plugin',
            'node_processes': self.hdp2_config.MASTER_NODE_PROCESSES,
            'floating_ip_pool': self.floating_ip_pool,
            'node_configs': {}
        }
        self.ng_tmpl_rm_nn_id = self.create_node_group_template(**template)
        self.ng_template_ids.append(self.ng_tmpl_rm_nn_id)

    @b.errormsg("Failure while 'nm-dn' node group template creation: ")
    def _create_nm_dn_ng_template(self):
        template = {
            'name': 'test-node-group-template-hdp2-nm-dn',
            'plugin_config': self.hdp2_config,
            'description': 'test node group template for HDP plugin',
            'node_processes': self.hdp2_config.WORKER_NODE_PROCESSES,
            'floating_ip_pool': self.floating_ip_pool,
            'node_configs': {}
        }
        self.ng_tmpl_nm_dn_id = self.create_node_group_template(**template)
        self.ng_template_ids.append(self.ng_tmpl_nm_dn_id)

    @b.errormsg("Failure while cluster template creation: ")
    def _create_cluster_template(self):
        template = {
            'name': 'test-cluster-template-hdp2',
            'plugin_config': self.hdp2_config,
            'description': 'test cluster template for HDP plugin',
            'cluster_configs': {
                'YARN': {
                    'yarn.log-aggregation-enable': False
                }
            },
            'node_groups': [
                {
                    'name': 'master-node-dn',
                    'node_group_template_id': self.ng_tmpl_rm_nn_id,
                    'count': 1
                },
                {
                    'name': 'worker-node-nm',
                    'node_group_template_id': self.ng_tmpl_nm_dn_id,
                    'count': 3
                }
            ],
            'net_id': self.internal_neutron_net
        }
        self.cluster_template_id = self.create_cluster_template(**template)

    @b.errormsg("Failure while cluster creation: ")
    def _create_cluster(self):
        cluster_name = '%s-%s-v2' % (self.common_config.CLUSTER_NAME,
                                     self.hdp2_config.PLUGIN_NAME)
        cluster = {
            'name': cluster_name,
            'plugin_config': self.hdp2_config,
            'cluster_template_id': self.cluster_template_id,
            'description': 'test cluster',
            'cluster_configs': {}
        }
        self.create_cluster(**cluster)
        self.cluster_info = self.get_cluster_info(self.hdp2_config)
        self.await_active_workers_for_namenode(self.cluster_info['node_info'],
                                               self.hdp2_config)

    @b.errormsg("Failure during check of Swift availability: ")
    def _check_swift(self):
        self.check_swift_availability(self.cluster_info)

    @b.errormsg("Failure while EDP testing: ")
    def _check_edp(self):
        self._edp_test()

    def _edp_test(self):
        path = 'tests/integration/tests/resources/'

        # check pig
        pig_job = f.get_file_text(path + 'edp-job.pig')
        pig_lib = f.get_file_text(path + 'edp-lib.jar')
        self.edp_testing(job_type=utils_edp.JOB_TYPE_PIG,
                         job_data_list=[{'pig': pig_job}],
                         lib_data_list=[{'jar': pig_lib}],
                         swift_binaries=True,
                         hdfs_local_output=True)

        # check mapreduce
        mapreduce_jar = f.get_file_text(path + 'edp-mapreduce.jar')
        mapreduce_configs = {
            'configs': {
                'mapred.mapper.class': 'org.apache.oozie.example.SampleMapper',
                'mapred.reducer.class':
                'org.apache.oozie.example.SampleReducer'
            }
        }
        self.edp_testing(job_type=utils_edp.JOB_TYPE_MAPREDUCE,
                         job_data_list=[],
                         lib_data_list=[{'jar': mapreduce_jar}],
                         configs=mapreduce_configs,
                         swift_binaries=True,
                         hdfs_local_output=True)

        # check mapreduce streaming
        mapreduce_streaming_configs = {
            'configs': {
                'edp.streaming.mapper': '/bin/cat',
                'edp.streaming.reducer': '/usr/bin/wc'
            }
        }
        self.edp_testing(job_type=utils_edp.JOB_TYPE_MAPREDUCE_STREAMING,
                         job_data_list=[],
                         lib_data_list=[],
                         configs=mapreduce_streaming_configs)

        # check java
        java_jar = f.get_file_text(
            path + 'hadoop-mapreduce-examples-2.3.0.jar')
        java_configs = {
            'configs': {
                'edp.java.main_class':
                'org.apache.hadoop.examples.QuasiMonteCarlo'
            },
            'args': ['10', '10']
        }
        self.edp_testing(utils_edp.JOB_TYPE_JAVA,
                         job_data_list=[],
                         lib_data_list=[{'jar': java_jar}],
                         configs=java_configs)

    @b.errormsg("Failure while cluster scaling: ")
    def _check_scaling(self):
        datanode_count_after_resizing = (
            self.cluster_info['node_info']['datanode_count']
            + self.hdp_config.SCALE_EXISTING_NG_COUNT)
        change_list = [
            {
                'operation': 'resize',
                'info': ['worker-node-nm',
                         datanode_count_after_resizing]
            },
            {
                'operation': 'add',
                'info': ['new-worker-node-tt-dn',
                         self.hdp2_config.SCALE_NEW_NG_COUNT,
                         '%s' % self.ng_tmpl_nm_dn_id]
            }
        ]

        self.cluster_info = self.cluster_scaling(self.cluster_info,
                                                 change_list)
        self.await_active_workers_for_namenode(self.cluster_info['node_info'],
                                               self.hdp2_config)

    @b.errormsg(
        "Failure during check of Swift availability after cluster scaling: ")
    def _check_swift_after_scaling(self):
        self.check_swift_availability(self.cluster_info)

    @b.errormsg("Failure while EDP testing after cluster scaling: ")
    def _check_edp_after_scaling(self):
        self._edp_test()

    @testcase.attr('hdp2')
    def test_hdp2_plugin_gating(self):
        self._prepare_test()
        self._create_rm_nn_ng_template()
        self._create_nm_dn_ng_template()
        self._create_cluster_template()
        self._create_cluster()

        self._check_swift()
        self._check_edp()

        if not self.hdp2_config.SKIP_SCALING_TEST:
            self._check_scaling()
            self._check_swift_after_scaling()
            self._check_edp_after_scaling()

    def tearDown(self):
        self.delete_objects(self.cluster_id, self.cluster_template_id,
                            self.ng_template_ids)
        super(HDP2GatingTest, self).tearDown()
