<filename>api/azimuth/provider/dto.py
"""
This module defines data-transfer objects used by providers.
"""

from dataclasses import dataclass
from datetime import datetime
import enum
import io
import json
import re
from typing import Any, Mapping, Optional, Sequence, Tuple

import yaml
import requests


@dataclass(frozen = True)
class Capabilities:
    """
    Represents the capabilities of the cloud.
    """
    #: Indicates if the cloud supports volumes
    supports_volumes: bool = False


@dataclass(frozen = True)
class Tenancy:
    """
    Represents a tenancy/organisation on a cloud provider.
    """
    #: The ID of the tenancy
    id: str
    #: The human-readable name of the tenancy
    name: str


@dataclass(frozen = True)
class Quota:
    """
    Represents a quota available to a tenancy.
    """
    #: The resource that the quota is for
    resource: str
    #: The units of the quota. For a unit-less quota, use ``None``.
    units: Optional[str]
    #: The amount of the resource that has been allocated
    allocated: int
    #: The amount of the resource that has been used
    used: int


@dataclass(frozen = True)
class Image:
    """
    Represents an image available to a tenancy.

    Can be combined with a :py:class:`Size` to create a new :py:class:`Machine`.
    """
    #: The id of the image
    id: str
    #: The human-readable name of the image
    name: str
    #: Indicates if the image is public or private
    is_public: bool
    #: The size of the image in MB
    size: float
    #: The metadata associated with the image
    metadata: Mapping[str, str]


@dataclass(frozen = True)
class Size:
    """
    Represents a machine size available to a tenancy.

    A size is a specification of the number of virtaul CPUs and RAM available to
    a machine.

    Can be combined with an :py:class:`Image` to create a new :py:class:`Machine`.
    """
    #: The id of the size
    id: str
    #: The human-readable name of the size
    name: str
    #: The number of CPUs
    cpus: int
    #: The amount of RAM in MB
    ram: int
    #: The size of the image's disk in GB
    #: Can be -1 to indicate no root disk size limit
    disk: int


@enum.unique
class MachineStatusType(enum.Enum):
    """
    Enum representing the possible status types.
    """
    BUILD = 'BUILD'
    ACTIVE = 'ACTIVE'
    ERROR = 'ERROR'
    OTHER = 'OTHER'


@dataclass(frozen = True)
class MachineStatus:
    """
    Represents a machine status.
    """
    #: The type of the status
    type: MachineStatusType
    #: A short string representation of the status
    name: str
    #: A more details description of the status, e.g. an error
    details: Optional[str]


@dataclass(frozen = True)
class Machine:
    """
    Represents a machine in a tenancy.
    """
    #: The id of the machine
    id: str
    #: The human-readable name of the machine
    name: str
    #: The ID of the image used to deploy the machine
    image_id: str
    #: The ID of the size of the machine
    size_id: str
    #: The status of the machine
    status: MachineStatus
    #: The power state of the machine
    power_state: str
    #: String representation of any task that is currently executing
    task: Optional[str]
    #: The internal IPv4 address of the machine
    internal_ip: Optional[str]
    #: The external IPv4 address of the machine
    external_ip: Optional[str]
    #: Tuple of ids of attached volumes for the machine
    attached_volume_ids: Sequence[str]
    #: The metadata associated with the machine
    metadata: Mapping[str, str]
    #: The id or username of the user who deployed the machine
    owner: str
    #: The datetime at which the machine was deployed
    created: datetime


class FirewallRuleDirection(enum.Enum):
    """
    Enum representing the possible directions for a firewall rule.
    """
    INBOUND = "INBOUND"
    OUTBOUND = "OUTBOUND"
    # Add ingress and egress as aliases for inbound and outbound
    INGRESS = "INBOUND"
    EGRESS = "OUTBOUND"


@enum.unique
class FirewallRuleProtocol(enum.Enum):
    """
    Enum representing the possible protocols for a firewall rule.
    """
    ANY = "ANY"
    ICMP = "ICMP"
    UDP = "UDP"
    TCP = "TCP"

    def requires_port(self):
        """
        Indicates if the protocol requires a port or not.
        """
        return self in {self.__class__.UDP, self.__class__.TCP}


@dataclass(frozen = True)
class FirewallRule:
    """
    Represents a firewall rule applying to a host.
    """
    #: The id of the firewall rule
    id: str
    #: The direction for the firewall rule
    direction: FirewallRuleDirection
    #: The protocol for the firewall rule
    protocol: FirewallRuleProtocol
    #: The port range matched by the firewall rule, if applicable
    port_range: Optional[Tuple[int, int]] = None
    #: The remote CIDR matched by the firewall rule, if applicable
    remote_cidr: Optional[str] = None
    #: The name of the remote firewall group matched by the firewall rule, if applicable
    remote_group: Optional[str] = None


@dataclass(frozen = True)
class FirewallGroup:
    """
    Represents a group in the firewall.

    This means a group in two senses - a set of rules and a set of hosts that
    have the group applied.
    """
    #: The name of the firewall group
    name: str
    #: The rules for the firewall group
    rules: Sequence[FirewallRule]
    #: Indicates if the rules in the group are editable
    #: Generally, this will only be the case for the instance-level rules
    editable: bool = False


@enum.unique
class VolumeStatus(enum.Enum):
    """
    Enum representing the possible volume statuses.
    """
    CREATING  = 'CREATING'
    AVAILABLE = 'AVAILABLE'
    ATTACHING = 'ATTACHING'
    DETACHING = 'DETACHING'
    IN_USE    = 'IN_USE'
    DELETING  = 'DELETING'
    ERROR     = 'ERROR'
    OTHER     = 'OTHER'


@dataclass(frozen = True)
class Volume:
    """
    Represents a volume attached to a machine.
    """
    #: The id of the volume
    id: str
    #: The name of the volume
    name: str
    #: The status of the volume
    status: VolumeStatus
    #: The size of the volume in GB
    size: int
    #: The id of the machine the volume is attached to, or None if the volume is not attached
    machine_id: Optional[str]
    #: The device that the volume is attached on, or None if the volume is not attached
    device: Optional[str]


@dataclass(frozen = True)
class ExternalIp:
    """
    Represents an externally visible IP address.
    """
    #: The id of the external IP
    id: str
    #: The externally visible IP address
    external_ip: str
    #: The ID of the machine to which the external IP address is mapped,
    #: or None if it is not mapped
    machine_id: Optional[str]

<filename>api/azimuth/provider/dto.py
"""
This module defines data-transfer objects used by providers.
"""

from dataclasses import dataclass
from datetime import datetime
import enum
import io
import json
import re
from typing import Any, Mapping, Optional, Sequence, Tuple

import yaml
import requests


@dataclass(frozen = True)
class Capabilities:
    """
    Represents the capabilities of the cloud.
    """
    #: Indicates if the cloud supports volumes
    supports_volumes: bool = False


@dataclass(frozen = True)
class Tenancy:
    """
    Represents a tenancy/organisation on a cloud provider.
    """
    #: The ID of the tenancy
    id: str
    #: The human-readable name of the tenancy
    name: str


@dataclass(frozen = True)
class Quota:
    """
    Represents a quota available to a tenancy.
    """
    #: The resource that the quota is for
    resource: str
    #: The units of the quota. For a unit-less quota, use ``None``.
    units: Optional[str]
    #: The amount of the resource that has been allocated
    allocated: int
    #: The amount of the resource that has been used
    used: int


@dataclass(frozen = True)
class Image:
    """
    Represents an image available to a tenancy.

    Can be combined with a :py:class:`Size` to create a new :py:class:`Machine`.
    """
    #: The id of the image
    id: str
    #: The human-readable name of the image
    name: str
    #: Indicates if the image is public or private
    is_public: bool
    #: The size of the image in MB
    size: float
    #: The metadata associated with the image
    metadata: Mapping[str, str]


@dataclass(frozen = True)
class Size:
    """
    Represents a machine size available to a tenancy.

    A size is a specification of the number of virtaul CPUs and RAM available to
    a machine.

    Can be combined with an :py:class:`Image` to create a new :py:class:`Machine`.
    """
    #: The id of the size
    id: str
    #: The human-readable name of the size
    name: str
    #: The number of CPUs
    cpus: int
    #: The amount of RAM in MB
    ram: int
    #: The size of the image's disk in GB
    #: Can be -1 to indicate no root disk size limit
    disk: int


@enum.unique
class MachineStatusType(enum.Enum):
    """
    Enum representing the possible status types.
    """
    BUILD = 'BUILD'
    ACTIVE = 'ACTIVE'
    ERROR = 'ERROR'
    OTHER = 'OTHER'


@dataclass(frozen = True)
class MachineStatus:
    """
    Represents a machine status.
    """
    #: The type of the status
    type: MachineStatusType
    #: A short string representation of the status
    name: str
    #: A more details description of the status, e.g. an error
    details: Optional[str]


@dataclass(frozen = True)
class Machine:
    """
    Represents a machine in a tenancy.
    """
    #: The id of the machine
    id: str
    #: The human-readable name of the machine
    name: str
    #: The ID of the image used to deploy the machine
    image_id: str
    #: The ID of the size of the machine
    size_id: str
    #: The status of the machine
    status: MachineStatus
    #: The power state of the machine
    power_state: str
    #: String representation of any task that is currently executing
    task: Optional[str]
    #: The internal IPv4 address of the machine
    internal_ip: Optional[str]
    #: The external IPv4 address of the machine
    external_ip: Optional[str]
    #: Tuple of ids of attached volumes for the machine
    attached_volume_ids: Sequence[str]
    #: The metadata associated with the machine
    metadata: Mapping[str, str]
    #: The id or username of the user who deployed the machine
    owner: str
    #: The datetime at which the machine was deployed
    created: datetime


class FirewallRuleDirection(enum.Enum):
    """
    Enum representing the possible directions for a firewall rule.
    """
    INBOUND = "INBOUND"
    OUTBOUND = "OUTBOUND"
    # Add ingress and egress as aliases for inbound and outbound
    INGRESS = "INBOUND"
    EGRESS = "OUTBOUND"


@enum.unique
class FirewallRuleProtocol(enum.Enum):
    """
    Enum representing the possible protocols for a firewall rule.
    """
    ANY = "ANY"
    ICMP = "ICMP"
    UDP = "UDP"
    TCP = "TCP"

    def requires_port(self):
        """
        Indicates if the protocol requires a port or not.
        """
        return self in {self.__class__.UDP, self.__class__.TCP}


@dataclass(frozen = True)
class FirewallRule:
    """
    Represents a firewall rule applying to a host.
    """
    #: The id of the firewall rule
    id: str
    #: The direction for the firewall rule
    direction: FirewallRuleDirection
    #: The protocol for the firewall rule
    protocol: FirewallRuleProtocol
    #: The port range matched by the firewall rule, if applicable
    port_range: Optional[Tuple[int, int]] = None
    #: The remote CIDR matched by the firewall rule, if applicable
    remote_cidr: Optional[str] = None
    #: The name of the remote firewall group matched by the firewall rule, if applicable
    remote_group: Optional[str] = None


@dataclass(frozen = True)
class FirewallGroup:
    """
    Represents a group in the firewall.

    This means a group in two senses - a set of rules and a set of hosts that
    have the group applied.
    """
    #: The name of the firewall group
    name: str
    #: The rules for the firewall group
    rules: Sequence[FirewallRule]
    #: Indicates if the rules in the group are editable
    #: Generally, this will only be the case for the instance-level rules
    editable: bool = False


@enum.unique
class VolumeStatus(enum.Enum):
    """
    Enum representing the possible volume statuses.
    """
    CREATING  = 'CREATING'
    AVAILABLE = 'AVAILABLE'
    ATTACHING = 'ATTACHING'
    DETACHING = 'DETACHING'
    IN_USE    = 'IN_USE'
    DELETING  = 'DELETING'
    ERROR     = 'ERROR'
    OTHER     = 'OTHER'


@dataclass(frozen = True)
class Volume:
    """
    Represents a volume attached to a machine.
    """
    #: The id of the volume
    id: str
    #: The name of the volume
    name: str
    #: The status of the volume
    status: VolumeStatus
    #: The size of the volume in GB
    size: int
    #: The id of the machine the volume is attached to, or None if the volume is not attached
    machine_id: Optional[str]
    #: The device that the volume is attached on, or None if the volume is not attached
    device: Optional[str]


@dataclass(frozen = True)
class ExternalIp:
    """
    Represents an externally visible IP address.
    """
    #: The id of the external IP
    id: str
    #: The externally visible IP address
    external_ip: str
    #: The ID of the machine to which the external IP address is mapped,
    #: or None if it is not mapped
    machine_id: Optional[str]

This module defines data-transfer objects used by providers. Represents the capabilities of the cloud. #: Indicates if the cloud supports volumes Represents a tenancy/organisation on a cloud provider. #: The ID of the tenancy #: The human-readable name of the tenancy Represents a quota available to a tenancy. #: The resource that the quota is for #: The units of the quota. For a unit-less quota, use ``None``. #: The amount of the resource that has been allocated #: The amount of the resource that has been used Represents an image available to a tenancy.      Can be combined with a :py:class:`Size` to create a new :py:class:`Machine`. #: The id of the image #: The human-readable name of the image #: Indicates if the image is public or private #: The size of the image in MB #: The metadata associated with the image Represents a machine size available to a tenancy.      A size is a specification of the number of virtaul CPUs and RAM available to     a machine.      Can be combined with an :py:class:`Image` to create a new :py:class:`Machine`. #: The id of the size #: The human-readable name of the size #: The number of CPUs #: The amount of RAM in MB #: The size of the image's disk in GB #: Can be -1 to indicate no root disk size limit Enum representing the possible status types. Represents a machine status. #: The type of the status #: A short string representation of the status #: A more details description of the status, e.g. an error Represents a machine in a tenancy. #: The id of the machine #: The human-readable name of the machine #: The ID of the image used to deploy the machine #: The ID of the size of the machine #: The status of the machine #: The power state of the machine #: String representation of any task that is currently executing #: The internal IPv4 address of the machine #: The external IPv4 address of the machine #: Tuple of ids of attached volumes for the machine #: The metadata associated with the machine #: The id or username of the user who deployed the machine #: The datetime at which the machine was deployed Enum representing the possible directions for a firewall rule. # Add ingress and egress as aliases for inbound and outbound Enum representing the possible protocols for a firewall rule. Indicates if the protocol requires a port or not. Represents a firewall rule applying to a host. #: The id of the firewall rule #: The direction for the firewall rule #: The protocol for the firewall rule #: The port range matched by the firewall rule, if applicable #: The remote CIDR matched by the firewall rule, if applicable #: The name of the remote firewall group matched by the firewall rule, if applicable Represents a group in the firewall.      This means a group in two senses - a set of rules and a set of hosts that     have the group applied. #: The name of the firewall group #: The rules for the firewall group #: Indicates if the rules in the group are editable #: Generally, this will only be the case for the instance-level rules Enum representing the possible volume statuses. Represents a volume attached to a machine. #: The id of the volume #: The name of the volume #: The status of the volume #: The size of the volume in GB #: The id of the machine the volume is attached to, or None if the volume is not attached #: The device that the volume is attached on, or None if the volume is not attached Represents an externally visible IP address. #: The id of the external IP #: The externally visible IP address #: The ID of the machine to which the external IP address is mapped, #: or None if it is not mapped