#!/usr/bin/python3

# Copyright (c) 2017 Intel Corporation
#
# 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.

import datetime
import os
import re
import subprocess
import sys


# This script is run as a libvirt hook.
# More information here: https://libvirt.org/hooks.html

# The devstack/lib/ironic script in function setup_qemu_log_hook() will replace
# LOG_DIR with the correct location. And will place the script into the correct
# directory.
VM_LOG_DIR = os.path.abspath("%LOG_DIR%")

# Regular expression to find ANSI escape sequences at the beginning of a string
ANSI_ESCAPE_RE = re.compile(r"""
    ^\x1b\[    # ANSI escape codes are ESC (0x1b) [
    ?([\d;]*)(\w)""", re.VERBOSE)

NOW = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S")


def main():
    if len(sys.argv) < 3:
        return

    guest_name = sys.argv[1]
    action = sys.argv[2]

    if action == "started":
        interfaces = subprocess.check_output(
            ['ip', 'link', 'show', 'type', 'macvtap']
        ).decode().split("\n")
        for iface_line in interfaces:
            if 'macvtap' in iface_line:
                iface_string = iface_line.split('@')
                ifaces = iface_string[0].split(' ')
                subprocess.call(['ip', 'link', 'set', 'dev', ifaces[1],
                                 'multicast', 'on', 'allmulticast', 'on'])

    if action != "release":
        return

    if not console_log_exists(guest_name):
        return

    new_path = move_console_log(guest_name)
    if not new_path:
        return

    no_ansi_filename = "{}_no_ansi_{}.log".format(guest_name, NOW)
    no_ansi_path = os.path.join(VM_LOG_DIR, no_ansi_filename)
    create_no_ansi_file(new_path, no_ansi_path)


def create_no_ansi_file(source_filename, dest_filename):
    with open(source_filename) as in_file:
        data = in_file.read()

    data = remove_ansi_codes(data)

    with open(dest_filename, 'w') as out_file:
        out_file.write(data)


def get_console_log_path(guest_name):
    logfile_name = "{}_console.log".format(guest_name)
    return os.path.join(VM_LOG_DIR, logfile_name)


def console_log_exists(guest_name):
    return os.path.isfile(get_console_log_path(guest_name))


def move_console_log(guest_name):
    new_logfile_name = "{}_console_{}.log".format(guest_name, NOW)
    new_path = os.path.join(VM_LOG_DIR, new_logfile_name)
    if os.path.exists(new_path):
        return False
    os.rename(get_console_log_path(guest_name), new_path)
    return new_path


def remove_ansi_codes(data):
    """Remove any ansi codes from the provided string"""
    output = ''
    while data:
        result = ANSI_ESCAPE_RE.match(data)
        if not result:
            output += data[0]
            data = data[1:]
        else:
            data = data[result.end():]
    return output


if '__main__' == __name__:
    sys.exit(main())
