#!/usr/bin/env python3

# Copyright 2021 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.

import argparse
import itertools
import json
import os
import subprocess
import sys

root_path = os.path.abspath(os.path.join(sys.argv[0], '..', '..'))

# Define what OS's are supported on which providers
builds = {'amazon': ['amazon linux', 'centos', 'flatcar', 'ubuntu', 'windows'],
          'azure':  ['centos', 'ubuntu', 'windows'],
          'ova': ['centos', 'photon', 'rhel', 'ubuntu', 'windows'],
          'oci':['ubuntu', 'oracle linux']}

def generate_goss(provider, system, versions, runtime, dryrun=False, save=False):
    cmd = ['goss', '-g', 'packer/goss/goss.yaml', '--vars', 'packer/goss/goss-vars.yaml']
    vars = {'OS': system, 'PROVIDER': provider,
            'OS_VERSION': versions['os'],
            'containerd_version': versions['containerd'],
            'docker_ee_version': versions['docker'],
            'distribution_version': versions['os'],
            'kubernetes_version': versions['k8s'],
            'kubernetes_deb_version': versions['k8s_deb'],
            'kubernetes_rpm_version': versions['k8s_rpm'],
            'kubernetes_source_type': 'pkg',
            'kubernetes_cni_version': versions['cni'],
            'kubernetes_cni_deb_version': versions['cni_deb'],
            'kubernetes_cni_rpm_version': versions['cni_rpm'],
            'kubernetes_cni_source_type': 'pkg',
            'runtime': runtime,
            'pause_image': versions['pause']}

    if system == "windows" and versions.get('ssh_url') is not None:
        vars['ssh_source_url'] = versions['ssh_url']

    # Build command
    cmd.extend(['--vars-inline', json.dumps(vars), 'render'])
    print('\nGenerating os: %s, provider: %s, runtime: %s' % (system, provider, runtime))
    print(cmd)

    # Run command with output going to file
    if not dryrun:
        if save:
            out_dir = os.path.join(root_path, 'packer', 'goss')
            out_filename = '%s-%s-%s-goss-spec.yaml' % (provider,
                                                        system.replace(' ', '-'), versions['k8s'])
            out_filename = os.path.join(out_dir, out_filename)
            with open(out_filename, 'w') as f:
                subprocess.run(cmd, cwd=root_path, stdout=f, check=True)
        else:
            subprocess.run(cmd, cwd=root_path, check=True)


def read_json_file(filename):
    j = None
    with open(filename, 'r') as f:
        j = json.load(f)
    return j


def main():
    parser = argparse.ArgumentParser(
        description='Generates GOSS specs. By default, generates all '
                    'possible specs to stdout.',
        usage='%(prog)s [-h] [--provider {amazon,azure,ova}] '
              '[--os {al2,centos,flatcar,photon,rhel,ubuntu,windows}]')
    parser.add_argument('--provider',
                        choices=['amazon', 'azure', 'ova','oci'],
                        action='append',
                        default=None,
                        help='One provider. Can be used multiple times')
    parser.add_argument('--os',
                        choices=['al2', 'centos', 'flatcar', 'photon', 'rhel', 'ubuntu', 'windows'],
                        action='append',
                        default=None,
                        help='One OS. Can be used multiple times')
    parser.add_argument('--dry-run',
                        action='store_true',
                        help='Do not run GOSS, just print GOSS commands')
    parser.add_argument('--write',
                        action='store_true',
                        help='Write GOSS specs to file')
    args = parser.parse_args()

    versions = {}
    # Load JSON files with Version info
    cni = read_json_file(os.path.join(root_path, 'packer', 'config', 'cni.json'))
    versions['cni'] = cni['kubernetes_cni_semver'].lstrip('v')
    versions['cni_deb'] = cni['kubernetes_cni_deb_version']
    versions['cni_rpm'] = cni['kubernetes_cni_rpm_version'].split('-')[0]

    k8s = read_json_file(os.path.join(root_path, 'packer', 'config', 'kubernetes.json'))
    versions['k8s'] = k8s['kubernetes_semver'].lstrip('v')
    versions['k8s_deb'] = k8s['kubernetes_deb_version']
    versions['k8s_rpm'] = k8s['kubernetes_rpm_version'].split('-')[0]

    containerd = read_json_file(os.path.join(root_path, 'packer', 'config', 'containerd.json'))
    versions['containerd'] = containerd['containerd_version']

    docker = read_json_file(os.path.join(root_path, 'packer', 'config', 'windows', 'docker.json'))
    versions['docker'] = docker['docker_ee_version']

    wincommon = read_json_file(os.path.join(root_path, 'packer', 'config', 'windows', 'common.json'))
    versions['ssh_url'] = wincommon['ssh_source_url']

    common = read_json_file(os.path.join(root_path, 'packer', 'config', 'common.json'))
    versions['pause'] = common['pause_image']

    providers = builds.keys()
    if args.provider is not None:
        providers = args.provider

    # Generate a unique list of all possible OS's if a choice wasn't made
    oss = args.os
    if args.os is None:
        oss = []
        for x in list(builds.values()):
            for o in x:
                oss.append(o)
        oss = list(set(oss))
    oss = [sub.replace('al2', 'amazon linux') for sub in oss]
    # Generate spec for each valid permutation
    for provider, system in itertools.product(providers, oss):
        if system in builds[provider]:
            if system == 'windows':
                runtimes = ["docker-ee","containerd"]
                os_versions = ["2019", "2022"]
            elif system == 'rhel':
                runtimes = ["containerd"]
                os_versions = ["7", "8"]
            elif system == 'photon':
                runtimes = ["containerd"]
                os_versions = ["3", "4", "5"]
            else: 
                runtimes = ["containerd"]
                os_versions = [""]
            for runtime in runtimes:
                for version in os_versions:
                    versions["os"] = version
                    generate_goss(provider, system, versions, runtime, args.dry_run, args.write)
            

if __name__ == '__main__':
    main()
