#!/usr/bin/env python
#
# Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
#
"""Base Contrail Provisioning module."""

import os
import re
import stat
import shutil
import socket
import tempfile
import platform
import logging
import argparse
from distutils.version import LooseVersion


from contrail_vrouter_provisioning import local, ExtList


log = logging.getLogger('contrail_vrouter_provisioning.base')


class ContrailSetup(object):
    def __init__(self):
        (self.pdist, self.pdistversion, self.pdistrelease) = platform.dist()
        self.hostname = socket.gethostname()
        self.running_in_container = False
        if os.path.exists('/.dockerenv'):
            self.running_in_container = True

        self._temp_dir_name = tempfile.mkdtemp()
        self.contrail_bin_dir = '/opt/contrail/bin'
        self._fixed_qemu_conf = False

    def update_vips_in_ctrl_details(self, ctrl_infos):
        if self._args.internal_vip:
            ctrl_infos.append('INTERNAL_VIP=%s' % self._args.internal_vip)
        if self._args.contrail_internal_vip:
            ctrl_infos.append('CONTRAIL_INTERNAL_VIP=%s' %
                              self._args.contrail_internal_vip)
        if self._args.external_vip:
            ctrl_infos.append('EXTERNAL_VIP=%s' % self._args.external_vip)

    def _template_substitute(self, template, vals):
        data = template.safe_substitute(vals)
        return data

    def _template_substitute_write(self, template, vals, filename):
        data = self._template_substitute(template, vals)
        outfile = open(filename, 'w')
        outfile.write(data)
        outfile.close()

    def _replaces_in_file(self, file, replacement_list):
        rs = [(re.compile(regexp), repl)
              for (regexp, repl) in replacement_list]
        file_tmp = file + ".tmp"
        with open(file, 'r') as f:
            with open(file_tmp, 'w') as f_tmp:
                for line in f:
                    for r, replace in rs:
                        match = r.search(line)
                        if match:
                            line = replace + "\n"
                    f_tmp.write(line)
        shutil.move(file_tmp, file)

    def replace_in_file(self, file, regexp, replace):
        self._replaces_in_file(file, [(regexp, replace)])

    def setup_crashkernel_params(self):
        kcmd = r"sudo sed -i 's/crashkernel=.*\([ | \"]\)"
        kcmd += r"/crashkernel=384M-2G:64M,2G-16G:128M,16G-:256M\1/g' "
        kcmd += "/etc/default/grub.d/kexec-tools.cfg"
        if self.pdistversion == '14.04':
            local(kcmd, warn_only=True)
            cmd = "[ -f /etc/default/kdump-tools ] && "
            cmd += "sudo sed -i 's/USE_KDUMP=0/USE_KDUMP=1/' "
            cmd += "/etc/default/kdump-tools"
            local(cmd, warn_only=True)
        else:
            local(kcmd)
        local("sudo update-grub")

    def enable_kernel_core(self):
        """
        enable_kernel_core:
        update grub file
        install grub2
        enable services
        """
        gcnf = ''
        with open('/etc/default/grub', 'r') as f:
            gcnf = f.read()
            p = re.compile('\s*GRUB_CMDLINE_LINUX')
            el = ExtList(gcnf.split('\n'))
            try:
                i = el.findex(p.match)
                exec(el[i])
                el[i] = 'GRUB_CMDLINE_LINUX="%s crashkernel=128M"' % (
                        ' '.join(filter(lambda x: not x.startswith(
                            'crashkernel='), GRUB_CMDLINE_LINUX.split())))
                exec(el[i])
                el[i] = 'GRUB_CMDLINE_LINUX="%s kvm-intel.nested=1"' % (
                        ' '.join(filter(lambda x: not x.startswith(
                            'kvm-intel.nested='), GRUB_CMDLINE_LINUX.split())))

                with open('%s/grub' % self._temp_dir_name, 'w') as f:
                    f.write('\n'.join(el))
                    f.flush()
                local('sudo mv %s/grub /etc/default/grub' %
                      self._temp_dir_name)
                local('sudo /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg')
            except LookupError:
                log.warning('Improper grub file, kernel crash not enabled')

    def disable_selinux(self):
        # Disable selinux
        os.chdir(self._temp_dir_name)
        cmd = "sudo sed -i 's/SELINUX=.*/SELINUX=disabled/g'"
        cmd += " /etc/selinux/config"
        local(cmd, warn_only=True)
        local("sudo setenforce 0", warn_only=True)
        # cleanup in case move had error
        local("sudo rm config.new", warn_only=True)

    def setup_sriov_grub(self, uio_driver="None"):
        if not self._args.sriov:
            if uio_driver != "vfio-pci":
                return

        if self.pdist != 'Ubuntu':
            log.info("Not configuring SRIOV Grub changes for %s distribution",
                     self.pdist)
            return

        with open('/etc/default/grub', 'r') as f:
            gcnf = f.read()
            p = re.compile('\s*GRUB_CMDLINE_LINUX_DEFAULT')
            el = gcnf.split('\n')
            for i, x in enumerate(el):
                if not p.match(x):
                    continue
                exec(el[i])
                el[i] = 'GRUB_CMDLINE_LINUX_DEFAULT="%s intel_iommu=on"' % (
                        ' '.join(filter(lambda x: not x.startswith(
                            'intel_iommu='),
                            GRUB_CMDLINE_LINUX_DEFAULT.split())))
                exec(el[i])
                el[i] = 'GRUB_CMDLINE_LINUX_DEFAULT="%s iommu=pt"' % (
                        ' '.join(filter(lambda x: not x.startswith(
                            'iommu='), GRUB_CMDLINE_LINUX_DEFAULT.split())))
                exec(el[i])
                with open('%s/grub' % self._temp_dir_name, 'w') as f:
                    f.write('\n'.join(el))
                    f.flush()
                local('sudo mv %s/grub /etc/default/grub' %
                      self._temp_dir_name)
                local('sudo /usr/sbin/update-grub')
                break

    def setup_sriov_vfs(self):
        # Set the required number of Virtual Functions for given interfaces
        if self.pdist != 'Ubuntu':
            log.info("Not configuring VF's for %s distribution", self.pdist)
            return

        sriov_string = self._args.sriov
        if sriov_string:
            intf_list = sriov_string.split(",")
            for intf_details in intf_list:
                info = intf_details.split(":")
                str = 'echo %s > ' % info[1]
                str += '/sys/class/net/%s/device/sriov_numvfs;' % info[0]
                str += 'sleep 2; ifup -a'
                # Do nothing if the entry already present in /etc/rc.local
                if local('sudo grep -w \'%s\' /etc/rc.local' % str,