# Info: KCL AWS provider defaults schemas for provisioning (Provisioning)
# Author: JesusPerezLorenzo 
# Release: 0.0.4
# Date: 15-12-2023
import regex
import provisioning

schema ReqPlan:
    """
    RequiredPlan settings
    """
    scale: bool = True
    arch: "x86_64" | "arm64" = "x86_64"
    cores: int = 1
    memory: int
    infaces: int = 2
    ena: str = "supported,required"
    # virtyp: hvm
    gen?: str = "current"

    check:
        multiplyof(memory, 256), "Memory must be a multiplier of 256"
        len(ena) > 0, "Check ena value"

schema Permission:
    """
    Permisssion for Security Groups
    """
    name: str
    "protocol": "tcp" | "udp" = "tcp"
    fromPort: int
    toPort: int
    ranges: str = "[{CidrIp=0.0.0.0/0},{CidrIp=10.0.0.0/24}]"

schema SecurityGroup:
    """
    Security Groups
    """
    id?: str
    name: str
    perms?: [Permission]

schema Storage_aws(provisioning.Storage):
    """
    AWS Storage settings
    """
    volname: str = ""

    # The volume type. This parameter can be one of the following values:
    # - General Purpose SSD: gp2 | gp3
    # - Provisioned IOPS SSD: io1 | io2
    # - Throughput Optimized HDD: st1
    # - Cold HDD: sc1
    # - Magnetic: standard
    # - Warning:  Throughput Optimized HDD (st1 ) and Cold HDD (sc1 ) volumes can't be used as boot volumes.
    voltype: "standard" | "io1" | "io2" | "gp2" | "sc1" | "st1" | "gp3" = "gp2"
    zone: str = ""
    voldevice: str = "sdf"
    labels: str = ""
    deletetermination: bool = False
    encrypted: bool = False
    kms_id: str = ""

    check:
        len(voldevice) > 0, "Check volume device value /dev/sd[f-p]"

schema ServerDefaults_aws(provisioning.ServerDefaults):
    """
    Server Defaults settings
    """
    not_use: bool = False
    provider: "aws" = "aws"
    # AWS provision data settings
    prov_settings: str = "defs/aws_data.k"
    # AWS provision data settings clean 
    prov_settings_clean: bool = False
    time_zone: str = "UTC"
    # AWS region like: eu-west-1 # TODO  check regex match
    zone?: str
    plan?: str
    reqplan?: ReqPlan
    # Specific AMIs can be used with their ID
    # If 'storage_os: find'  storage_os_find will be used to find one in zone (region)
    # expected something like: "name=debian-12 | arch=x86_64" or "name: debian-12 | arch: x86_64"  will be parsed to find latest available
    storage_os_find: str = "name: debian-12 | arch: x86_64"
    #storage_os: find
    storage_os?: str
    #storage_os: ami-0eb11ab33f229b26c
    # If not Storage size, Plan Storage size will be used
    #storage_size: int
    storages?: [Storage_aws]
    # Add one or more SSH keys to the admin account. Accepted values are SSH public keys or filenames from
    # where to read the keys.
    # ssh public key to be included in /root/.ssh/authorized_keys
    ssh_key_path?: str
    # Public certificate must be created or imported as a key_name 
    # use: providers/aws/bin/on-ssh.sh (add -h to get info)
    ssh_key_name?: str
    # AWS do not use utility network, if no value it will not be set and utility IP will not be set
    # public network, if no value it will not be set and public IP will not be set
    #network_utility_ipv4: bool = True
    #network_utility_ipv6: bool = False
    #network_public_ipv4: bool = True
    #network_public_ipv6: bool = False
    #TODO settings for Elastic IPs or instace without pubic IP 
    # To use private network a VPC + Subnet + NetworkInfterface has to be created, IPs will be set in servers items
    # In AWS this is only a name
    network_private_name?: str
    #network_private_id?: str 
    liveness_ip?: str
    liveness_port: int = 22
    # Disable api_stop to keep PublicIpAddress 
    disable_stop: bool = True

    # Labels to describe the server in `key: value` format, multiple can be declared.
    # Usage: env: dev
    labels: str = "{Key=cluster,Value=k8s}"
    # Main user (default Debian user is admin) 
    user: str = "admin"

    check:
        len(user) > 0, "Check user value"
        priv_cidr_block == Undefined or regex.match(priv_cidr_block, "^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}\/(?:3[0-2]|[0-2]?[0-9])$"), "'priv_cidr_block = ${priv_cidr_block}' check value definition"
        liveness_ip == Undefined or regex.match(liveness_ip, "^\$.*$") or regex.match(liveness_ip, "^((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])$"), "'liveness_ip = ${liveness_ip}' check value definition (use $vaule or xx.xx.xx.xx)"

