#!/usr/bin/env python
# Copyright 2016 VMware, Inc.
# All rights reserved. -- VMware Confidential

"""
    This script is executed by the `software-packages` command.

    The purpose of this script is to modify the content that gets
    staged on the appliance. For most appliances, all the patch
    payload rpms are applicable, so the pre-stage script should be
    very simple.

    All the patching installation related logic should be placed in
    the pre-install.py and post-install.sh scripts.
"""
import os
from os.path import join, exists, abspath, dirname
import logging
import json

from update_utils import runCommand, DEPLOYMENT_ROOT, getRPMBlacklist, \
    isRootPasswdExpired
from vmware.update.json_utils import prettyJsonDump
from vmware.update.extensions import extend, Hook
from vmware.update.specs import RequirementsResult, Requirements, \
    InternalError, StatusInfo, Mismatch

logger = logging.getLogger(__name__)

PASSWD_EXPIRED_TEXT = {'id':'com.vmware.password.expired',
                       'localized':'Appliance (OS) root password expired.',
                       'args':[]}
PASSWD_RESOLUTION_TEXT = {'id':'com.vmware.password.resolution',
                          'localized':'Please change appliance (OS) root'
                          ' password before attempting an update',
                          'args':[]}

@extend(Hook.Requirements)
def collectRequirements(_requirementsSpec):
    mismatches = []
    rpmIgnoreList = getRPMBlacklist()
    requirements = Requirements(rpmIgnoreList=rpmIgnoreList)
    if isRootPasswdExpired():
        logger.error("Appliance (OS) root password expired. "
                     "Please change appliance (OS) root password "
                     "before attempting an update")
        mismatch = Mismatch(PASSWD_EXPIRED_TEXT,
                    description=PASSWD_EXPIRED_TEXT,
                    resolution=PASSWD_RESOLUTION_TEXT,
                    severity=Mismatch.ERROR)
        mismatches = [mismatch]
    return RequirementsResult(requirements=requirements, mismatches=mismatches)

@extend(Hook.Validation)
def validate(_validationSpec):
    pass

def _reportSuccess(outputFile):
    result = StatusInfo(StatusInfo.State.SUCCESS, progress=100)
    prettyJsonDump(outputFile, result)

def _reportFailure(outputFile):
    result = StatusInfo(StatusInfo.State.ERROR)
    prettyJsonDump(outputFile, result)

def _reportProgress(outputFile, progress):
    result = StatusInfo(StatusInfo.State.RUNNING, progress=progress)
    prettyJsonDump(outputFile, result)

@extend(Hook.Prepare)
def prepare(prepareSpec):
    # This hook is designed to be used in exceptional cases when system rpms need
    # to be installed before the rest of the rpms
    # if you change the system in this hook you need to WARN the user for that
    # as on failure the customer will need to revert via snapshot
    pass

@extend(Hook.Prepatch)
def prepatch(prepatchSpec):
    _reportProgress(prepatchSpec.outputFile, 0)
    prepatchScript = join(DEPLOYMENT_ROOT, "scripts", "pre-install.py")
    out, err, rc = runCommand(['/bin/python', prepatchScript], progress=True,
                               message="Running pre-install script.")
    logger.debug("Prepatch script \n out=%s\nerror=%s\nrc=%d\n" %
                     (out, err, rc))
    if rc:
        if 'impact VCHA Cluster' in str(err):
            logger.error("[ERROR] Cannot proceed with the update."
                        " Please follow kb \"https://kb.vmware.com/s/article/55938\ "
                        "before update.")
        _reportFailure(prepatchSpec.outputFile)
        raise InternalError("Unable to successfully execute pre-install.py")

    logger.debug("Pre-patching completed successfully")
    _reportSuccess(prepatchSpec.outputFile)

@extend(Hook.Patch)
def patch(patchSpec):
    _reportProgress(patchSpec.outputFile, 0)

    # Execute pre-patch.sh
    prepatchScript = join(DEPLOYMENT_ROOT, "scripts", "pre-patch.sh")
    out, err, rc = runCommand([prepatchScript], progress=True,
                               message="Running pre-patch script." )
    logger.debug("Patch script \n out=%s\nerror=%s\nrc=%d\n" %
                     (out, err, rc))

    if rc:
        _reportFailure(patchSpec.outputFile)
        raise InternalError("Unable to successfully execute pre-patch.sh")

    # Execute post-patch.sh
    postpatchScript = join(DEPLOYMENT_ROOT, "scripts", "post-patch.sh")
    out, err, rc = runCommand([postpatchScript], progress=True,
                               message="Running post-patch script." )
    logger.debug("Patch script \n out=%s\nerror=%s\nrc=%d\n" %
                     (out, err, rc))

    if rc:
        _reportFailure(patchSpec.outputFile)
        raise InternalError("Unable to successfully execute post-patch.sh")

    logger.debug("Patching completed successfully")
    _reportSuccess(patchSpec.outputFile)
