#!/usr/bin/python3
'''
 This configures the general parameters of mt-server via the API.
 Leonid Fainshtein <leonid.fainshtein@xorcom.com>
 Xorcom Ltd 2004-2024
'''
import requests
import time
import sys
import argparse

MT_API_MAX_ATTEPTS = 3

requests.packages.urllib3.disable_warnings()
req_headers = {"Content-Type": "application/json"} 

class MtApi:

    def __init__(self, host, username, password):
        self.token = None
        self.url = f"https://{host}/api"
        self.username = username
        self.password = password

    def exec(self, command, args):
        for i in range(0, MT_API_MAX_ATTEPTS):
            args['action'] = command
            if self.token:
                args['token'] = self.token
            try:
                resp = requests.post(self.url, json=args, headers=req_headers, verify=False)
                if resp.status_code == 200:
                    resp_json = resp.json()
                    if resp_json:
                        if resp_json.get('status') == 'error' and resp_json.get('error') == 'Invalid token':
                            self.authenticate()
                            continue
                        else:
                            return resp_json
                    else:
                        return None
            except Exception as e:
                print(f"CPBX API request {command} failed with error: {e}")
                return None

    def authenticate(self):
        self.token = None
        data = {"username": self.username, "password": self.password}
        resp = self.exec("authenticate", data)
        if resp:
            sts = resp.get('status')
            if sts == 'success':
                self.token = resp.get('token')
                return True
        return False

    def get_token(self):
        if self.token is None:
            if not self.authenticate():
                return False
        return True
    
    def wait_for_completion(self, task_id):
        i = 0
        while i < 1000:
            time.sleep(3)
            data = {'task_id': task_id}
            resp = self.exec('status', data)
            if resp:
                sts = resp.get('status')
                if sts == 'completed':
                    return None
                elif sts == 'failed':
                    return resp.get('message')
            i += 1
        return 'Timeout occurred'
def resource_plans(api):
    """ Returns array of the configured resource plans."""
    data = {}
    resp = api.exec("resource-plans", data)
    if resp:
        sts = resp.get('status')
        if sts == 'success':
            return resp.get('resource_plans')
        else:
            print(f"E: failed to get a list of resource plans. Error: {resp.get('error')}")
    return None

def die(msg, rc):
	print(msg)
	sys.exit(rc)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Configure the genaral parameters of the MT Server.')
    parser.add_argument('--host', type=str, required=True, metavar='HOST', help='FQDN of the MT Server. IP address is not allowed. Required.')
    parser.add_argument('--mtusername', type=str, metavar='HOST', help='User name for the MT Server. If not defined, then "admin" is used. Optional.')
    parser.add_argument('--mtpassword', type=str, metavar='PASSWORD', help='Password for the MT Server. If not defined, then it is taken from /var/lib/mt-server/init-password file. Optional.')
    parser.add_argument('--image', type=str, metavar='IMAGE_NAME', help='The default tenant LXD image name. Optional.')
    parser.add_argument('--cpu', type=int,  metavar='PERCENTAGE', help='The CPU overprovisioning coefficient in percent (100-3000). If defined, then "--memory" is required. Optional.')
    parser.add_argument('--memory', type=int, metavar='PERCENTAGE', help='The memory overprovisioning coefficient in percent (100-3000). If defined, then "--cpu" is required. Optional.')
    parser.add_argument('--netif', type=str,  metavar='NAME', help='Name of the default nertwork interface. Optional.')
    parser.add_argument('--username', type=str, metavar='NAME', help='User name for licensing server. If defined, then "--password" is required. Optional.')
    parser.add_argument('--password', type=str, metavar='PASSWORD', help='Password for licensing server. If defined, then "--username" is required. Optional.')
    args = parser.parse_args()

    # Theoretically, at least one parameter must be requested. But taking into consideration that the script could be called
    # from an Ansible playbook, and the user doesn't want to set any parameters then we dont check the parameters presence here.
    if (args.username and not args.password) or (not args.username and args.password):
        print("E: Both username and password must be provided.")
        sys.exit(1)

    if (args.cpu  and not args.memory) or (not args.cpu and args.memory):
        print("E: Both --cpu and --memory must be provided or both must not be provided.")
        sys.exit(1)
    if args.cpu and (args.cpu < 100 or args.cpu > 3000):
        print("E: --cpu must be between 100 and 3000.")
        sys.exit(1)
    if args.memory and (args.memory < 100 or args.memory > 3000):
        print("E: --memory must be between 100 and 3000.")
        sys.exit(1)

    host = args.host
    username = args.mtusername if args.mtusername else "admin"
    if not args.mtpassword:
        with open('/var/lib/mt-server/init_password', 'r') as f:
            args.mtpassword = f.readline().strip()
    password = args.mtpassword
    api = MtApi(host, username, password)
    if not api.get_token():
        print("E: MT Manager API authentication problem or the MT Manager server is not accessible.\n")
        sys.exit(1)


    if args.image:
        api.exec("set-dflt-image", {'image': args.image})
    if args.cpu  and args.memory:
        api.exec("set-overprovision", {'overprov_cpu': args.cpu, 'overprov_memory': args.memory})
    if args.netif:
        api.exec("set-dflt-net-interface", {'iface': args.netif})
    if args.username and args.password:
        api.exec("set-lsrv-credentials", {'username': args.username, 'password': args.password})
