#!/usr/bin/env python3

# ------------------------------------------------------------------------
# Copyright 2020, 2021 IBM Corp. 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.
# ------------------------------------------------------------------------

""" Automated build, push and deploy """


# Global modules

import sys


# Local modules

from modules.args     import (
    addCommonArgsString,
    getCommonArgsParser
)
from modules.command  import CmdShell
from modules.context  import getContext
from modules.fail     import fail
from modules.nfstools import Overlays
from modules.ocp      import ocLogin


# Functions

def _getArgs():
    """ Get command line arguments """
    parser = getCommonArgsParser(
        'Automated build, push and deploy'
    )

    parser.add_argument(
        '-y',
        '--hdb-copy',
        required = False,
        action   = 'store_true',
        help     = "Copy HANA DB snapshot to NFS server"
    )

    parser.add_argument(
        '-b',
        '--build-images',
        required = False,
        action   = 'store_true',
        help     = "Build images"
    )

    parser.add_argument(
        '-p',
        '--push-images',
        required = False,
        action   = 'store_true',
        help     = "Push images to local OCP cluster registry"
    )

    parser.add_argument(
        '-o',
        '--setup-overlay-share',
        required = False,
        action   = 'store_true',
        help     = "Setup overlay share"
    )

    parser.add_argument(
        '-u',
        '--overlay-uuid',
        metavar  = '<overlay-uuid>',
        required = False,
        help     = "UUID of overlay share for options '-d' and '-t'"
    )

    parser.add_argument(
        '-l',
        '--list-overlay-shares',
        required = False,
        action   = 'store_true',
        help     = "List existing overlay shares"
    )

    parser.add_argument(
        '-t',
        '--tear-down-overlay-share',
        required = False,
        action   = 'store_true',
        help     = "Tear down overlay share specified with option '-u'"
    )

    parser.add_argument(
        '-d',
        '--create-deployment-file',
        required = False,
        action   = 'store_true',
        help     = "Create deployment file"
    )

    parser.add_argument(
        '-s',
        '--start-deployment',
        required = False,
        action   = 'store_true',
        help     = "Start deployment on OCP cluster"
    )

    parser.add_argument(
        '-x',
        '--stop-deployment',
        required = False,
        action   = 'store_true',
        help     = "Stop deployment on OCP cluster"
    )

    parser.add_argument(
        '-a',
        '--execute-all',
        required = False,
        action   = 'store_true',
        help     = "Execute all actions (except '-t', '-l' and '-x')"
    )

    parser.add_argument(
        '-r',
        '--execute-rest',
        required = False,
        action   = 'store_true',
        help     = "Start with specified action "
                   "and execute all subsequent actions in automation process."
    )

    return parser.parse_args()


def _genHeader(header, lineChar):
    """ Generate header string (generic) """
    return lineChar*60+'\n'+header+'\n'+lineChar*60


def _genHeader1(header):
    """ Generate header string (level 1 header) """
    return _genHeader(header, '=')


def _genHeader2(header):
    """ Generate header string (level 2 header) """
    return _genHeader(header, '-')


def getOverlayUuid(ctx, overlayUuid):
    """ Get overlay UUID from parameter or cli argument.
        Exit, if no overlay UUID can be determined """
    if not overlayUuid:
        if ctx.ar.overlay_uuid:
            overlayUuid = ctx.ar.overlay_uuid
        else:
            fail("Please specify an overlay share UUID via option '-u'")

    return Overlays(ctx).find(overlayUuid).uuid


def _runCmd(cmd):
    result = CmdShell().run(cmd)
    if result.rc != 0:
        msg = ''
        msg += f"Command '{cmd}' failed"
        msg += f'\n  stdout: >>>{result.out}<<<'
        msg += f'\n  stderr: >>>{result.err}<<<'
        msg += f'\n  rc: {result.rc}'
        fail(msg)
    return result


def _copyHdb(ctx):
    """ Copy snapshot of HANA DB to NFS server (automation option) """
    print(_genHeader1(f"Copying snapshot of HANA DB '{ctx.cf.refsys.hdb.sidU}'"
                      f" to NFS server '{ctx.cf.nfs.host.name}'"))
    cmd = f'time {ctx.cf.build.repo.root}/tools/nfs-hdb-copy'
    cmd += ctx.ar.commonArgsStr
    _runCmd(cmd)


def _buildImages(ctx):
    """ Build images for all flavors (automation option) """
    for flavor in ctx.config.getImageFlavors():
        print(_genHeader1(f"Building image for flavor '{flavor}'"))
        cmd = f'time {ctx.cf.build.repo.root}/tools/image-build'
        cmd += f' -f {flavor}'
        cmd += ctx.ar.commonArgsStr
        _runCmd(cmd)


def _pushImages(ctx):
    """ Push images for all flavors to OCP (automation option) """
    for flavor in ctx.config.getImageFlavors():
        print(_genHeader1(f"Pushing image for flavor '{flavor}'"))
        cmd = f'time {ctx.cf.build.repo.root}/tools/image-push'
        cmd += f' -f {flavor}'
        cmd += ctx.ar.commonArgsStr
        _runCmd(cmd)


def _setupOverlayShare(ctx):
    """ Setup an overlay share on NFS server (automation option) """
    print(_genHeader1('Setting up overlay share'))
    cmd = f'time {ctx.cf.build.repo.root}/tools/nfs-overlay-setup'
    cmd += ctx.ar.commonArgsStr
    overlayUuid = _runCmd(cmd).out
    print(overlayUuid)
    return overlayUuid


def _createDeploymentFile(ctx, overlayUuid):
    """ Create deployment file (automation option) """
    overlayUuid = getOverlayUuid(ctx, overlayUuid)
    deploymentFile = ctx.cf.ocp.deployment.file
    print(_genHeader1(f"Creating deployment file '{deploymentFile}'"
                      f" with overlay share '{overlayUuid}'"))
    cmd = f'time {ctx.cf.build.repo.root}/tools/ocp-deployment-gen'
    cmd += f' -u {overlayUuid}'
    cmd += f' -o {deploymentFile}'
    cmd += ctx.ar.commonArgsStr
    print(_runCmd(cmd).out)


def _startDeployment(ctx):
    """ Start deployment using deployment file (automation option) """
    deploymentFile = ctx.cf.ocp.deployment.file
    print(_genHeader1(f"Starting deployment using file '{deploymentFile}'"))
    ocLogin(ctx, ctx.cr.ocp.user)
    CmdShell().run(f'time oc apply -f {deploymentFile}')


def _listOverlayShares(ctx):
    """ List all overlay shares on NFS server (manual option) """
    print(_genHeader1('List of existing overlay shares:'))
    cmd = f'time {ctx.cf.build.repo.root}/tools/nfs-overlay-list'
    cmd += ctx.ar.commonArgsStr
    print(_runCmd(cmd).out)


def _tearDownOverlayShare(ctx, overlayUuid):
    """ Tear down an overlay share on NFS server (manual option) """
    overlayUuid = getOverlayUuid(ctx, overlayUuid)
    print(_genHeader1(f'Tearing down overlay share {overlayUuid}'))
    cmd = f'{ctx.cf.build.repo.root}/tools/nfs-overlay-teardown'
    cmd += f' -u {overlayUuid}'
    cmd += ctx.ar.commonArgsStr
    _runCmd(cmd)


def _stopDeployment(ctx):
    """ Stop deployment using deployment file (manual option) """
    deploymentFile = ctx.cf.ocp.deployment.file
    print(_genHeader1(f"Stopping deployment using file '{deploymentFile}'"))
    ocLogin(ctx, ctx.cr.ocp.user)
    CmdShell().run(f'time oc delete -f {deploymentFile}')


# ----------------------------------------------------------------------

def _main():

    ctx = getContext(_getArgs())

    addCommonArgsString(ctx)

    overlayUuid = None

    # ↓↓↓ AUTOMATION OPTIONS ↓↓↓

    # Copy snapshot of HANA

    if ctx.ar.execute_all or ctx.ar.hdb_copy:
        ctx.ar.execute_all = ctx.ar.execute_all or ctx.ar.execute_rest
        _copyHdb(ctx)

    # Build images

    if ctx.ar.execute_all or ctx.ar.build_images:
        ctx.ar.execute_all = ctx.ar.execute_all or ctx.ar.execute_rest
        _buildImages(ctx)

    # Push images

    if ctx.ar.execute_all or ctx.ar.push_images:
        ctx.ar.execute_all = ctx.ar.execute_all or ctx.ar.execute_rest
        _pushImages(ctx)

    # Setup overlay share

    if ctx.ar.execute_all or ctx.ar.setup_overlay_share:
        ctx.ar.execute_all = ctx.ar.execute_all or ctx.ar.execute_rest
        overlayUuid = _setupOverlayShare(ctx)

    # Create deployment YAML file

    if ctx.ar.execute_all or ctx.ar.create_deployment_file:
        ctx.ar.execute_all = ctx.ar.execute_all or ctx.ar.execute_rest
        _createDeploymentFile(ctx, overlayUuid)

    # Start deployment

    if ctx.ar.execute_all or ctx.ar.start_deployment:
        ctx.ar.execute_all = ctx.ar.execute_all or ctx.ar.execute_rest
        _startDeployment(ctx)

    # ↑↑↑ AUTOMATION OPTIONS ↑↑↑

    # ↓↓↓ MANUAL OPTIONS ↓↓↓

    # List existing overlay shares

    if ctx.ar.list_overlay_shares:
        _listOverlayShares(ctx)

    # Tear down overlay share

    if ctx.ar.tear_down_overlay_share:
        _tearDownOverlayShare(ctx, overlayUuid)

    # Stop deployment

    if ctx.ar.stop_deployment:
        _stopDeployment(ctx)

    # ↑↑↑ MANUAL OPTIONS ↑↑↑


# ----------------------------------------------------------------------

if __name__ == '__main__':
    try:
        _main()
    except KeyboardInterrupt:
        print()
    sys.exit(0)
