#!/usr/bin/env python

# Copyright 2019 The Kubernetes Authors.
#
# 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.

################################################################################
# usage: image-upload.py [FLAGS] ARGS
#  This program uploads an OVA created from a Packer build
################################################################################

import argparse
import atexit
import hashlib
import json
import os
import re
import requests
import subprocess
import string
import sys


def main():
    parser = argparse.ArgumentParser(
        description="Uploads an OVA created from a Packer build")
    parser.add_argument(dest='build_dir',
                        nargs='?',
                        metavar='BUILD_DIR',
                        default='.',
                        help='The Packer build directory')
    parser.add_argument('--key-file',
                        dest='key_file',
                        required=True,
                        nargs='?',
                        metavar='KEY_FILE',
                        help='The GCS key file')
    args = parser.parse_args()

    # Get the absolute path to the GCS key file.
    key_file = os.path.abspath(args.key_file)

    # Change the working directory if one is specified.
    os.chdir(args.build_dir)
    print("image-upload-ova: cd %s" % args.build_dir)

    # Load the packer manifest JSON
    data = None
    with open('packer-manifest.json', 'r') as f:
        data = json.load(f)

    # Get the first build.
    build = data['builds'][0]
    build_data = build['custom_data']

    version = build_data['kubernetes_semver']
    build_name = "%s-kube-%s" % (build_data['build_name'], version)
    print("image-upload-ova: loaded %s" % build_name)

    # Get the OVA and its checksum.
    ova = "%s.ova" % build_name
    ova_sum = "%s.sha256" % ova

    # Determine whether or not this is a release or CI image.
    upload_dir = 'ci'
    if re.match(r'^v?\d+\.\d+\.\d+(-\d+)?$', version):
        upload_dir = 'release'

    # Get the path to the GCS OVA and its checksum.
    gcs_ova = "gs://capv-images/%s/%s/%s" % (
        upload_dir, version, ova)
    gcs_ova_sum = "%s.sha256" % gcs_ova

    # Get the URL of the OVA and its checksum.
    url_ova = string.replace(gcs_ova, "gs://", "http://storage.googleapis.com/")
    url_ova_sum = "%s.sha256" % url_ova

    # Compare the remote checksum with the local checksum.
    lcl_ova_sum_val = get_local_checksum(ova_sum)
    print("image-upload-ova:  local sha256 %s" % lcl_ova_sum_val)
    rem_ova_sum_val = get_remote_checksum(url_ova_sum)
    print("image-upload-ova: remote sha256 %s" % rem_ova_sum_val)
    if lcl_ova_sum_val == rem_ova_sum_val:
        print("image-upload-ova: skipping upload")
        print("image-upload-ova: download from %s" % url_ova)
        return

    # Activate the GCS service account.
    activate_service_account(key_file)
    atexit.register(deactivate_service_account)

    # Upload the OVA and its checksum.
    print("image-upload-ova: upload %s" % gcs_ova)
    subprocess.check_call(['gsutil', 'cp', ova, gcs_ova])
    print("image-upload-ova: upload %s" % gcs_ova_sum)
    subprocess.check_call(['gsutil', 'cp', ova_sum, gcs_ova_sum])

    print("image-upload-ova: download from %s" % url_ova)


def activate_service_account(path):
    args = [
        "gcloud", "auth",
        "activate-service-account",
        "--key-file", path,
    ]
    subprocess.check_call(args)


def deactivate_service_account():
    subprocess.call(["gcloud", "auth", "revoke"])


def get_remote_checksum(url):
    r = requests.get(url)
    if r.status_code >= 200 and r.status_code <= 299:
        return r.text.strip()
    return None


def get_local_checksum(path):
    with open(path, 'r') as f:
        return f.readline().strip()


if __name__ == "__main__":
    main()
