예제 #1
0
    def delete(self, **kwargs):
        """
        Handles DELETE requests. Writes the jsonified output of remove_resource
        to the response object.

        @param resource_id: identifier for the NDB model instance (usually a
                            urlsafe key)
        @type  resource_id: basestring
        @param version: version of the API (number or "latest")
        @type  version: basestring
        @return: json stringified rest resource

        Other query arguments include
        projection: a list of strings denoting which attributes should be
                    included in the resource's representation
        key_only: a boolean which denotes that only the resource's key should be
                  returned if true
        """
        query = self._validate_query(
            kwargs,
            vol.Schema(
                {
                    vol.Required('resource_id'): basestring,
                    vol.Required('version'): basestring,
                    vol.Optional('projection'): val.Coerce(
                        val.List(basestring)),
                    vol.Optional('key_only'): vol.Boolean()
                },
                extra=False))

        self._set_interface('DELETE', query['version'])
        resource = self.remove_resource(**query)
        self.response.write(json.dumps(resource))
예제 #2
0
def _single_validate(typ, value, key):
    """Validate a single element."""
    # if required argument
    if value is None:
        raise vol.Invalid(f"Missing required option '{key}'")

    # parse extend data from type
    match = RE_SCHEMA_ELEMENT.match(typ)

    # prepare range
    range_args = {}
    for group_name in ('i_min', 'i_max', 'f_min', 'f_max'):
        group_value = match.group(group_name)
        if group_value:
            range_args[group_name[2:]] = float(group_value)

    if typ.startswith(V_STR):
        return str(value)
    elif typ.startswith(V_INT):
        return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
    elif typ.startswith(V_FLOAT):
        return vol.All(vol.Coerce(float), vol.Range(**range_args))(value)
    elif typ.startswith(V_BOOL):
        return vol.Boolean()(value)
    elif typ.startswith(V_EMAIL):
        return vol.Email()(value)
    elif typ.startswith(V_URL):
        return vol.Url()(value)
    elif typ.startswith(V_PORT):
        return NETWORK_PORT(value)
    elif typ.startswith(V_MATCH):
        return vol.Match(match.group('match'))(str(value))

    raise vol.Invalid(f"Fatal error for {key} type {typ}")
예제 #3
0
파일: validate.py 프로젝트: radhus/hassio
def _single_validate(typ, value, key):
    """Validate a single element."""
    try:
        # if required argument
        if value is None:
            raise vol.Invalid("Missing required option '{}'.".format(key))

        if typ == V_STR:
            return str(value)
        elif typ == V_INT:
            return int(value)
        elif typ == V_FLOAT:
            return float(value)
        elif typ == V_BOOL:
            return vol.Boolean()(value)
        elif typ == V_EMAIL:
            return vol.Email()(value)
        elif typ == V_URL:
            return vol.Url()(value)
        elif typ == V_PORT:
            return NETWORK_PORT(value)

        raise vol.Invalid("Fatal error for {} type {}".format(key, typ))
    except ValueError:
        raise vol.Invalid("Type {} error for '{}' on {}.".format(
            typ, value, key)) from None
예제 #4
0
    def delete(self, **kwargs):
        """
        Handles DELETE requests. Writes the jsonified output of remove_resources
        to the response object.

        @param version: version of the API (number or "latest")
        @type  version: basestring
        @return: json stringified dict containing rest resources

        Other query arguments include
        limit: the number of resources to delete (batch size)
        projection: a list of strings denoting which attributes should be
                    included in the resources' representations
        keys_only: a boolean which denotes that only the resources' keys
                   should be returned if true
        """
        query = self._validate_query(
            kwargs,
            vol.Schema(
                {
                    vol.Required('version'): basestring,
                    vol.Optional('limit'): val.Coerce(int),
                    vol.Optional('projection'): val.Coerce(
                        val.List(basestring)),
                    vol.Optional('keys_only'): vol.Boolean()
                },
                extra=False))

        resources = self.remove_resources(**query)
        self.response.write(json.dumps(resources))
예제 #5
0
async def setup_module(center, config):
    """Set up automations package.

    Parameters
    ----------
    center : Center instance
        The Center instance.
    config : dict
        The config dict.
    """
    _process_automations(center, config)
    automations = center.data[DATA_AUTOMATIONS]

    async def handle_action(**kwargs):
        """Enable or disable an automation."""
        name = kwargs[NAME]
        automation = automations[name]
        enabled = kwargs.get(ENABLED, not automation.enabled)
        if enabled:
            automation.enable()
        else:
            automation.disable()

    toggle_action_schema = BASE_ACTION_SCHEMA.extend({
        vol.Required(NAME):
        vol.All(vol.Coerce(str), vol.In(automations)),
        ENABLED:
        vol.Boolean(),  # pylint: disable=no-value-for-parameter
    })

    # register action to enable/disable automation
    center.actions.register("automations", ACTION_TOGGLE, handle_action,
                            toggle_action_schema)
    def get_param_schema(self):
        # Validators for schema

        return {
            u'min_confidence': voluptuous.Coerce(float),
            u'min_support': voluptuous.Coerce(float),
            u'make_default': voluptuous.Coerce(voluptuous.Boolean()),
            u'limit': voluptuous.Coerce(int),
            u'cursor': voluptuous.Coerce(str),
        }
예제 #7
0
파일: written.py 프로젝트: mplsart/arts-612
    def get_param_schema(self):

        return {
            u'limit': voluptuous.Coerce(int),
            u'cursor': coerce_to_cursor,
            # 'sort': voluptuous.Coerce(str),
            u'category_slug': voluptuous.Coerce(unicode),
            u'get_by_slug': voluptuous.Coerce(unicode),
            u'is_published': voluptuous.Coerce(voluptuous.Boolean()),
            u'start_date': coerce_to_datetime
            # 'q': voluptuous.Coerce(str)
        }
예제 #8
0
def boolean_constraint(session, options):
    # The built-in Boolean validator ends up casting any value to a bool
    # We want to be stricter and actively reject anything except:
    #   - bool
    #   - 1 / 0
    #   - "1" / "0"
    #   - "true" / "false"
    #   - "yes" / "no"
    return v.Any(
        # Don't use "bool" because that would result in a coercion which we don't want
        v.In([True, False]),
        # This covers 0/1 and "0"/"1"
        v.All(int, v.In([0, 1]), bool),
        v.All(str, v.In(["true", "false", "yes", "no"]), v.Boolean()))
예제 #9
0
def _single_validate(coresys: CoreSys, typ: str, value: Any, key: str):
    """Validate a single element."""
    # if required argument
    if value is None:
        raise vol.Invalid(f"Missing required option '{key}'")

    # Lookup secret
    if str(value).startswith("!secret "):
        secret: str = value.partition(" ")[2]
        value = coresys.secrets.get(secret)
        if value is None:
            raise vol.Invalid(f"Unknown secret {secret}")

    # parse extend data from type
    match = RE_SCHEMA_ELEMENT.match(typ)

    if not match:
        raise vol.Invalid(f"Unknown type {typ}")

    # prepare range
    range_args = {}
    for group_name in _SCHEMA_LENGTH_PARTS:
        group_value = match.group(group_name)
        if group_value:
            range_args[group_name[2:]] = float(group_value)

    if typ.startswith(V_STR) or typ.startswith(V_PASSWORD):
        return vol.All(str(value), vol.Range(**range_args))(value)
    elif typ.startswith(V_INT):
        return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
    elif typ.startswith(V_FLOAT):
        return vol.All(vol.Coerce(float), vol.Range(**range_args))(value)
    elif typ.startswith(V_BOOL):
        return vol.Boolean()(value)
    elif typ.startswith(V_EMAIL):
        return vol.Email()(value)
    elif typ.startswith(V_URL):
        return vol.Url()(value)
    elif typ.startswith(V_PORT):
        return network_port(value)
    elif typ.startswith(V_MATCH):
        return vol.Match(match.group("match"))(str(value))
    elif typ.startswith(V_LIST):
        return vol.In(match.group("list").split("|"))(str(value))

    raise vol.Invalid(f"Fatal error for {key} type {typ}")
예제 #10
0
    raise vol.Invalid("Can't validate docker host settings")


DOCKER_PORTS = vol.Schema({
    vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")):
    convert_to_docker_ports,
})

# pylint: disable=no-value-for-parameter
SCHEMA_HASS_CONFIG = vol.Schema(
    {
        vol.Optional(ATTR_UUID, default=lambda: uuid.uuid4().hex):
        vol.Match(r"^[0-9a-f]{32}$"),
        vol.Optional(ATTR_BOOT, default=True):
        vol.Boolean(),
        vol.Inclusive(ATTR_IMAGE, 'custom_hass'):
        DOCKER_IMAGE,
        vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'):
        vol.Coerce(str),
        vol.Optional(ATTR_PORT, default=8123):
        NETWORK_PORT,
        vol.Optional(ATTR_PASSWORD):
        vol.Any(None, vol.Coerce(str)),
        vol.Optional(ATTR_SSL, default=False):
        vol.Boolean(),
        vol.Optional(ATTR_WATCHDOG, default=True):
        vol.Boolean(),
        vol.Optional(ATTR_WAIT_BOOT, default=600):
        vol.All(vol.Coerce(int), vol.Range(min=60)),
    },
예제 #11
0
from ..exceptions import APIError
from ..validate import docker_ports
from .utils import api_process, api_process_raw, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)

SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): vol.Coerce(str)})

# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema({
    vol.Optional(ATTR_BOOT):
    vol.In([BOOT_AUTO, BOOT_MANUAL]),
    vol.Optional(ATTR_NETWORK):
    vol.Maybe(docker_ports),
    vol.Optional(ATTR_AUTO_UPDATE):
    vol.Boolean(),
    vol.Optional(ATTR_AUDIO_OUTPUT):
    vol.Maybe(vol.Coerce(str)),
    vol.Optional(ATTR_AUDIO_INPUT):
    vol.Maybe(vol.Coerce(str)),
    vol.Optional(ATTR_INGRESS_PANEL):
    vol.Boolean(),
    vol.Optional(ATTR_WATCHDOG):
    vol.Boolean(),
})

# pylint: disable=no-value-for-parameter
SCHEMA_SECURITY = vol.Schema({vol.Optional(ATTR_PROTECTED): vol.Boolean()})


class APIAddons(CoreSysAttributes):
예제 #12
0
    ATTR_VERSION,
    CONTENT_TYPE_TAR,
)
from ..coresys import CoreSysAttributes
from ..exceptions import APIError
from ..snapshots.validate import ALL_FOLDERS
from .utils import api_process, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)


# pylint: disable=no-value-for-parameter
SCHEMA_RESTORE_PARTIAL = vol.Schema(
    {
        vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)),
        vol.Optional(ATTR_HOMEASSISTANT): vol.Boolean(),
        vol.Optional(ATTR_ADDONS): vol.All([vol.Coerce(str)], vol.Unique()),
        vol.Optional(ATTR_FOLDERS): vol.All([vol.In(ALL_FOLDERS)], vol.Unique()),
    }
)

SCHEMA_RESTORE_FULL = vol.Schema(
    {vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str))}
)

SCHEMA_SNAPSHOT_FULL = vol.Schema(
    {
        vol.Optional(ATTR_NAME): vol.Coerce(str),
        vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)),
    }
)
예제 #13
0
                    'Invalid start timeshift delay value, an integer expected'
                ), v.Range(min=1))),
        v.Required('time_units'):
        v.Maybe(
            v.All(
                str,
                v.
                In(set(TimeUnits),
                   msg='Invalid start timeshift unit value, one of %s expected'
                   % (', '.join(['"%s"' % x for x in tuple(TimeUnits)]))),
            ), )
    }
}

StopSection = {
    v.Required('never'): v.Maybe(v.Boolean()),
    'on': v.Maybe(datetime.datetime),
    'after_num_repeats': v.Maybe(v.All(int, v.Range(min=1))),
}

RelativeScheduleSchema = v.Schema({
    'start':
    StartSection,
    'stop':
    StopSection,
    v.Required('periodical'): {
        v.Required('repeats'):
        v.Maybe(
            v.All(
                str,
                v.In(
예제 #14
0
 vol.Required(ATTR_VERSION):
 vol.Coerce(str),
 vol.Required(ATTR_SLUG):
 vol.Coerce(str),
 vol.Required(ATTR_DESCRIPTON):
 vol.Coerce(str),
 vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)],
 vol.Optional(ATTR_MACHINE): [vol.In(MACHINE_ALL)],
 vol.Optional(ATTR_URL):
 vol.Url(),
 vol.Required(ATTR_STARTUP):
 vol.All(_simple_startup, vol.In(STARTUP_ALL)),
 vol.Required(ATTR_BOOT):
 vol.In([BOOT_AUTO, BOOT_MANUAL]),
 vol.Optional(ATTR_INIT, default=True):
 vol.Boolean(),
 vol.Optional(ATTR_ADVANCED, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_STAGE, default=AddonStages.STABLE):
 vol.Coerce(AddonStages),
 vol.Optional(ATTR_PORTS):
 DOCKER_PORTS,
 vol.Optional(ATTR_PORTS_DESCRIPTION):
 DOCKER_PORTS_DESCRIPTION,
 vol.Optional(ATTR_WEBUI):
 vol.Match(r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"),
 vol.Optional(ATTR_INGRESS, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_INGRESS_PORT, default=8099):
 vol.Any(network_port, vol.Equal(0)),
 vol.Optional(ATTR_INGRESS_ENTRY):
예제 #15
0
    vol.Optional(ATTR_MODE):
    vol.Coerce(WifiMode),
    vol.Optional(ATTR_AUTH):
    vol.Coerce(AuthMethod),
    vol.Optional(ATTR_SSID):
    str,
    vol.Optional(ATTR_PSK):
    str,
})

# pylint: disable=no-value-for-parameter
SCHEMA_UPDATE = vol.Schema({
    vol.Optional(ATTR_IPV4): _SCHEMA_IP_CONFIG,
    vol.Optional(ATTR_IPV6): _SCHEMA_IP_CONFIG,
    vol.Optional(ATTR_WIFI): _SCHEMA_WIFI_CONFIG,
    vol.Optional(ATTR_ENABLED): vol.Boolean(),
})


def ipconfig_struct(config: IpConfig) -> dict[str, Any]:
    """Return a dict with information about ip configuration."""
    return {
        ATTR_METHOD: config.method,
        ATTR_ADDRESS: [address.with_prefixlen for address in config.address],
        ATTR_NAMESERVERS: [str(address) for address in config.nameservers],
        ATTR_GATEWAY: str(config.gateway) if config.gateway else None,
    }


def wifi_struct(config: WifiConfig) -> dict[str, Any]:
    """Return a dict with information about wifi configuration."""
예제 #16
0
"""Validate functions."""

import voluptuous as vol

from supervisor.plugins.const import ATTR_FALLBACK

from ..const import ATTR_ACCESS_TOKEN, ATTR_IMAGE, ATTR_SERVERS, ATTR_VERSION
from ..validate import dns_server_list, docker_image, token, version_tag

# pylint: disable=no-value-for-parameter
SCHEMA_DNS_CONFIG = vol.Schema(
    {
        vol.Optional(ATTR_VERSION): version_tag,
        vol.Optional(ATTR_IMAGE): docker_image,
        vol.Optional(ATTR_SERVERS, default=list): dns_server_list,
        vol.Optional(ATTR_FALLBACK, default=True): vol.Boolean(),
    },
    extra=vol.REMOVE_EXTRA,
)


SCHEMA_AUDIO_CONFIG = vol.Schema(
    {vol.Optional(ATTR_VERSION): version_tag, vol.Optional(ATTR_IMAGE): docker_image},
    extra=vol.REMOVE_EXTRA,
)


SCHEMA_CLI_CONFIG = vol.Schema(
    {
        vol.Optional(ATTR_VERSION): version_tag,
        vol.Optional(ATTR_IMAGE): docker_image,
예제 #17
0
# pylint: disable=no-value-for-parameter
SCHEMA_SNAPSHOT = vol.Schema(
    {
        vol.Required(ATTR_SLUG): vol.Coerce(str),
        vol.Required(ATTR_TYPE): vol.In([SNAPSHOT_FULL, SNAPSHOT_PARTIAL]),
        vol.Required(ATTR_NAME): vol.Coerce(str),
        vol.Required(ATTR_DATE): vol.Coerce(str),
        vol.Inclusive(ATTR_PROTECTED, "encrypted"): vol.All(
            vol.Coerce(str), vol.Length(min=1, max=1)
        ),
        vol.Inclusive(ATTR_CRYPTO, "encrypted"): CRYPTO_AES128,
        vol.Optional(ATTR_HOMEASSISTANT, default=dict): vol.Schema(
            {
                vol.Optional(ATTR_VERSION): version_tag,
                vol.Optional(ATTR_IMAGE): docker_image,
                vol.Optional(ATTR_BOOT, default=True): vol.Boolean(),
                vol.Optional(ATTR_SSL, default=False): vol.Boolean(),
                vol.Optional(ATTR_PORT, default=8123): network_port,
                vol.Optional(ATTR_REFRESH_TOKEN): vol.Maybe(vol.Coerce(str)),
                vol.Optional(ATTR_WATCHDOG, default=True): vol.Boolean(),
                vol.Optional(ATTR_WAIT_BOOT, default=600): vol.All(
                    vol.Coerce(int), vol.Range(min=60)
                ),
                vol.Optional(ATTR_AUDIO_OUTPUT, default=None): vol.Maybe(
                    vol.Coerce(str)
                ),
                vol.Optional(ATTR_AUDIO_INPUT, default=None): vol.Maybe(
                    vol.Coerce(str)
                ),
            },
            extra=vol.REMOVE_EXTRA,
예제 #18
0
    ATTR_VERSION_LATEST,
    ATTR_WAIT_BOOT,
    ATTR_WATCHDOG,
    CONTENT_TYPE_BINARY,
)
from ..coresys import CoreSysAttributes
from ..exceptions import APIError
from ..validate import docker_image, network_port, version_tag
from .utils import api_process, api_process_raw, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)

# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema(
    {
        vol.Optional(ATTR_BOOT): vol.Boolean(),
        vol.Optional(ATTR_IMAGE): docker_image,
        vol.Optional(ATTR_PORT): network_port,
        vol.Optional(ATTR_SSL): vol.Boolean(),
        vol.Optional(ATTR_WATCHDOG): vol.Boolean(),
        vol.Optional(ATTR_WAIT_BOOT): vol.All(vol.Coerce(int), vol.Range(min=60)),
        vol.Optional(ATTR_REFRESH_TOKEN): vol.Maybe(vol.Coerce(str)),
        vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(vol.Coerce(str)),
        vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(vol.Coerce(str)),
    }
)

SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): version_tag})


class APIOpenPeerPower(CoreSysAttributes):
예제 #19
0
    def _single_validate(self, typ: str, value: Any, key: str):
        """Validate a single element."""
        # if required argument
        if value is None:
            raise vol.Invalid(
                f"Missing required option '{key}' in {self._name} ({self._slug})"
            ) from None

        # Lookup secret
        if str(value).startswith("!secret "):
            secret: str = value.partition(" ")[2]
            value = self.sys_homeassistant.secrets.get(secret)
            if value is None:
                raise vol.Invalid(
                    f"Unknown secret '{secret}' in {self._name} ({self._slug})"
                ) from None

        # parse extend data from type
        match = RE_SCHEMA_ELEMENT.match(typ)

        if not match:
            raise vol.Invalid(
                f"Unknown type '{typ}' in {self._name} ({self._slug})"
            ) from None

        # prepare range
        range_args = {}
        for group_name in _SCHEMA_LENGTH_PARTS:
            group_value = match.group(group_name)
            if group_value:
                range_args[group_name[2:]] = float(group_value)

        if typ.startswith(_STR) or typ.startswith(_PASSWORD):
            if typ.startswith(_PASSWORD) and value:
                self.pwned.add(hashlib.sha1(str(value).encode()).hexdigest())
            return vol.All(str(value), vol.Range(**range_args))(value)
        elif typ.startswith(_INT):
            return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
        elif typ.startswith(_FLOAT):
            return vol.All(vol.Coerce(float), vol.Range(**range_args))(value)
        elif typ.startswith(_BOOL):
            return vol.Boolean()(value)
        elif typ.startswith(_EMAIL):
            return vol.Email()(value)
        elif typ.startswith(_URL):
            return vol.Url()(value)
        elif typ.startswith(_PORT):
            return network_port(value)
        elif typ.startswith(_MATCH):
            return vol.Match(match.group("match"))(str(value))
        elif typ.startswith(_LIST):
            return vol.In(match.group("list").split("|"))(str(value))
        elif typ.startswith(_DEVICE):
            try:
                device = self.sys_hardware.get_by_path(Path(value))
            except HardwareNotFound:
                raise vol.Invalid(
                    f"Device '{value}' does not exist in {self._name} ({self._slug})"
                ) from None

            # Have filter
            if match.group("filter"):
                str_filter = match.group("filter")
                device_filter = _create_device_filter(str_filter)
                if device not in self.sys_hardware.filter_devices(
                        **device_filter):
                    raise vol.Invalid(
                        f"Device '{value}' don't match the filter {str_filter}! in {self._name} ({self._slug})"
                    )

            # Device valid
            self.devices.add(device)
            return str(device.path)

        raise vol.Invalid(
            f"Fatal error for option '{key}' with type '{typ}' in {self._name} ({self._slug})"
        ) from None
예제 #20
0
from ..coresys import CoreSysAttributes
from ..exceptions import APIError
from ..utils.validate import validate_timezone
from ..validate import CHANNELS, LOG_LEVEL, REPOSITORIES, WAIT_BOOT
from .utils import api_process, api_process_raw, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)

# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema({
    vol.Optional(ATTR_CHANNEL): CHANNELS,
    vol.Optional(ATTR_ADDONS_REPOSITORIES): REPOSITORIES,
    vol.Optional(ATTR_TIMEZONE): validate_timezone,
    vol.Optional(ATTR_WAIT_BOOT): WAIT_BOOT,
    vol.Optional(ATTR_LOGGING): LOG_LEVEL,
    vol.Optional(ATTR_DEBUG): vol.Boolean(),
    vol.Optional(ATTR_DEBUG_BLOCK): vol.Boolean(),
})

SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): vol.Coerce(str)})


class APISupervisor(CoreSysAttributes):
    """Handle RESTful API for Supervisor functions."""
    @api_process
    async def ping(self, request):
        """Return ok for signal that the API is ready."""
        return True

    @api_process
    async def info(self, request: web.Request) -> Dict[str, Any]:
예제 #21
0
    return value


# pylint: disable=no-value-for-parameter
SCHEMA_ADDON_CONFIG = vol.Schema(
    {
        vol.Required(ATTR_NAME): vol.Coerce(str),
        vol.Required(ATTR_VERSION): version_tag,
        vol.Required(ATTR_SLUG): vol.Coerce(str),
        vol.Required(ATTR_DESCRIPTON): vol.Coerce(str),
        vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)],
        vol.Optional(ATTR_MACHINE): vol.All([vol.Match(RE_MACHINE)], vol.Unique()),
        vol.Optional(ATTR_URL): vol.Url(),
        vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.Coerce(AddonStartup)),
        vol.Required(ATTR_BOOT): vol.Coerce(AddonBoot),
        vol.Optional(ATTR_INIT, default=True): vol.Boolean(),
        vol.Optional(ATTR_ADVANCED, default=False): vol.Boolean(),
        vol.Optional(ATTR_STAGE, default=AddonStage.STABLE): vol.Coerce(AddonStage),
        vol.Optional(ATTR_PORTS): docker_ports,
        vol.Optional(ATTR_PORTS_DESCRIPTION): docker_ports_description,
        vol.Optional(ATTR_WATCHDOG): vol.Match(
            r"^(?:https?|\[PROTO:\w+\]|tcp):\/\/\[HOST\]:\[PORT:\d+\].*$"
        ),
        vol.Optional(ATTR_WEBUI): vol.Match(
            r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"
        ),
        vol.Optional(ATTR_INGRESS, default=False): vol.Boolean(),
        vol.Optional(ATTR_INGRESS_PORT, default=8099): vol.Any(
            network_port, vol.Equal(0)
        ),
        vol.Optional(ATTR_INGRESS_ENTRY): vol.Coerce(str),
예제 #22
0
SHARE_DATA = PurePath("share")
TMP_DATA = PurePath("tmp")

UPSTREAM_BETA = 'upstream_beta'
API_ENDPOINT = 'api_endpoint'
TIMEZONE = 'timezone'

SECURITY_INITIALIZE = 'security_initialize'
SECURITY_TOTP = 'security_totp'
SECURITY_PASSWORD = '******'
SECURITY_SESSIONS = 'security_sessions'


# pylint: disable=no-value-for-parameter
SCHEMA_CONFIG = vol.Schema({
    vol.Optional(UPSTREAM_BETA, default=False): vol.Boolean(),
    vol.Optional(API_ENDPOINT): vol.Coerce(str),
    vol.Optional(TIMEZONE, default='UTC'): validate_timezone,
    vol.Optional(HOMEASSISTANT_LAST): vol.Coerce(str),
    vol.Optional(HOMEASSISTANT_DEVICES, default=[]): [vol.Coerce(str)],
    vol.Optional(HASSIO_LAST): vol.Coerce(str),
    vol.Optional(ADDONS_CUSTOM_LIST, default=[]): [vol.Url()],
    vol.Optional(SECURITY_INITIALIZE, default=False): vol.Boolean(),
    vol.Optional(SECURITY_TOTP): vol.Coerce(str),
    vol.Optional(SECURITY_PASSWORD): vol.Coerce(str),
    vol.Optional(SECURITY_SESSIONS, default={}):
        {vol.Coerce(str): vol.Coerce(str)},
}, extra=vol.REMOVE_EXTRA)


class Config(object):
예제 #23
0
from ..exceptions import APIError
from ..utils.validate import validate_timezone
from ..validate import repositories, version_tag, wait_boot
from .utils import api_process, api_process_raw, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)

# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema(
    {
        vol.Optional(ATTR_CHANNEL): vol.Coerce(UpdateChannel),
        vol.Optional(ATTR_ADDONS_REPOSITORIES): repositories,
        vol.Optional(ATTR_TIMEZONE): validate_timezone,
        vol.Optional(ATTR_WAIT_BOOT): wait_boot,
        vol.Optional(ATTR_LOGGING): vol.Coerce(LogLevel),
        vol.Optional(ATTR_DEBUG): vol.Boolean(),
        vol.Optional(ATTR_DEBUG_BLOCK): vol.Boolean(),
        vol.Optional(ATTR_DIAGNOSTICS): vol.Boolean(),
        vol.Optional(ATTR_CONTENT_TRUST): vol.Boolean(),
        vol.Optional(ATTR_FORCE_SECURITY): vol.Boolean(),
    }
)

SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): version_tag})


class APISupervisor(CoreSysAttributes):
    """Handle RESTful API for Supervisor functions."""

    @api_process
    async def ping(self, request):
예제 #24
0
from .utils import api_process, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)

RE_SLUGIFY_NAME = re.compile(r"[^A-Za-z0-9]+")

# Backwards compatible
# Remove: 2022.08
_ALL_FOLDERS = ALL_FOLDERS + [FOLDER_HOMEASSISTANT]

# pylint: disable=no-value-for-parameter
SCHEMA_RESTORE_PARTIAL = vol.Schema({
    vol.Optional(ATTR_PASSWORD):
    vol.Maybe(str),
    vol.Optional(ATTR_HOMEASSISTANT):
    vol.Boolean(),
    vol.Optional(ATTR_ADDONS):
    vol.All([str], vol.Unique()),
    vol.Optional(ATTR_FOLDERS):
    vol.All([vol.In(_ALL_FOLDERS)], vol.Unique()),
})

SCHEMA_RESTORE_FULL = vol.Schema({vol.Optional(ATTR_PASSWORD): vol.Maybe(str)})

SCHEMA_BACKUP_FULL = vol.Schema({
    vol.Optional(ATTR_NAME):
    str,
    vol.Optional(ATTR_PASSWORD):
    vol.Maybe(str),
    vol.Optional(ATTR_COMPRESSED):
    vol.Maybe(vol.Boolean()),
예제 #25
0
# pylint: disable=no-value-for-parameter
SCHEMA_ADDON_CONFIG = vol.Schema({
    vol.Required(ATTR_NAME): vol.Coerce(str),
    vol.Required(ATTR_VERSION): vol.Coerce(str),
    vol.Required(ATTR_SLUG): vol.Coerce(str),
    vol.Required(ATTR_DESCRIPTON): vol.Coerce(str),
    vol.Optional(ATTR_URL): vol.Url(),
    vol.Optional(ATTR_ARCH, default=ARCH_ALL): [vol.In(ARCH_ALL)],
    vol.Required(ATTR_STARTUP):
        vol.All(_simple_startup, vol.In(STARTUP_ALL)),
    vol.Required(ATTR_BOOT):
        vol.In([BOOT_AUTO, BOOT_MANUAL]),
    vol.Optional(ATTR_PORTS): DOCKER_PORTS,
    vol.Optional(ATTR_WEBUI):
        vol.Match(r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"),
    vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
    vol.Optional(ATTR_HOST_IPC, default=False): vol.Boolean(),
    vol.Optional(ATTR_HOST_DBUS, default=False): vol.Boolean(),
    vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")],
    vol.Optional(ATTR_AUTO_UART, default=False): vol.Boolean(),
    vol.Optional(ATTR_TMPFS):
        vol.Match(r"^size=(\d)*[kmg](,uid=\d{1,4})?(,rw)?$"),
    vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)],
    vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)},
    vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGED_ALL)],
    vol.Optional(ATTR_SECCOMP, default=True): vol.Boolean(),
    vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(),
    vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(),
    vol.Optional(ATTR_GPIO, default=False): vol.Boolean(),
    vol.Optional(ATTR_HASSIO_API, default=False): vol.Boolean(),
    vol.Optional(ATTR_HOMEASSISTANT_API, default=False): vol.Boolean(),
예제 #26
0
from ..exceptions import APINotSupportedError

_LOGGER = logging.getLogger(__name__)

SCHEMA_VERSION = vol.Schema({
    vol.Optional(ATTR_VERSION): vol.Coerce(str),
})

# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema({
    vol.Optional(ATTR_BOOT):
    vol.In([BOOT_AUTO, BOOT_MANUAL]),
    vol.Optional(ATTR_NETWORK):
    vol.Any(None, DOCKER_PORTS),
    vol.Optional(ATTR_AUTO_UPDATE):
    vol.Boolean(),
    vol.Optional(ATTR_AUDIO_OUTPUT):
    ALSA_DEVICE,
    vol.Optional(ATTR_AUDIO_INPUT):
    ALSA_DEVICE,
})

# pylint: disable=no-value-for-parameter
SCHEMA_SECURITY = vol.Schema({
    vol.Optional(ATTR_PROTECTED): vol.Boolean(),
})


class APIAddons(CoreSysAttributes):
    """Handle rest api for addons functions."""
    def _extract_addon(self, request, check_installed=True):
예제 #27
0
class ScopeState(base.BaseResource):
    @classmethod
    def reload(cls):
        super(ScopeState, cls).reload()
        cls._client = messaging.get_client()
        cls._storage_state = storage_state.StateManager()

    @api_utils.paginated
    @api_utils.add_input_schema(
        'query', {
            voluptuous.Optional('scope_id', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('scope_key', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('fetcher', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('collector', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('active', default=[]):
            api_utils.MultiQueryParam(int),
        })
    @api_utils.add_output_schema({
        'results': [{
            voluptuous.Required('scope_id'):
            vutils.get_string_type(),
            voluptuous.Required('scope_key'):
            vutils.get_string_type(),
            voluptuous.Required('fetcher'):
            vutils.get_string_type(),
            voluptuous.Required('collector'):
            vutils.get_string_type(),
            voluptuous.Optional('last_processed_timestamp'):
            vutils.get_string_type(),
            # This "state" property should be removed in the next release.
            voluptuous.Optional('state'):
            vutils.get_string_type(),
            voluptuous.Required('active'):
            bool,
            voluptuous.Optional('scope_activation_toggle_date'):
            vutils.get_string_type(),
        }]
    })
    def get(self,
            offset=0,
            limit=100,
            scope_id=None,
            scope_key=None,
            fetcher=None,
            collector=None,
            active=None):

        policy.authorize(
            flask.request.context, 'scope:get_state',
            {'project_id': scope_id or flask.request.context.project_id})
        results = self._storage_state.get_all(identifier=scope_id,
                                              scope_key=scope_key,
                                              fetcher=fetcher,
                                              collector=collector,
                                              offset=offset,
                                              limit=limit,
                                              active=active)

        if len(results) < 1:
            raise http_exceptions.NotFound(
                "No resource found for provided filters.")
        return {
            'results': [{
                'scope_id':
                r.identifier,
                'scope_key':
                r.scope_key,
                'fetcher':
                r.fetcher,
                'collector':
                r.collector,
                'state':
                r.last_processed_timestamp.isoformat(),
                'last_processed_timestamp':
                r.last_processed_timestamp.isoformat(),
                'active':
                r.active,
                'scope_activation_toggle_date':
                r.scope_activation_toggle_date.isoformat()
                if r.scope_activation_toggle_date else None
            } for r in results]
        }

    @api_utils.add_input_schema(
        'body',
        {
            voluptuous.Exclusive('all_scopes', 'scope_selector'):
            voluptuous.Boolean(),
            voluptuous.Exclusive('scope_id', 'scope_selector'):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('scope_key', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('fetcher', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('collector', default=[]):
            api_utils.MultiQueryParam(str),
            voluptuous.Optional('last_processed_timestamp'):
            voluptuous.Coerce(tzutils.dt_from_iso),
            # This "state" property should be removed in the next release.
            voluptuous.Optional('state'):
            voluptuous.Coerce(tzutils.dt_from_iso),
        })
    def put(self,
            all_scopes=False,
            scope_id=None,
            scope_key=None,
            fetcher=None,
            collector=None,
            last_processed_timestamp=None,
            state=None):

        policy.authorize(
            flask.request.context, 'scope:reset_state',
            {'project_id': scope_id or flask.request.context.project_id})

        if not all_scopes and scope_id is None:
            raise http_exceptions.BadRequest(
                "Either all_scopes or a scope_id should be specified.")

        if not state and not last_processed_timestamp:
            raise http_exceptions.BadRequest(
                "Variables 'state' and 'last_processed_timestamp' cannot be "
                "empty/None. We expect at least one of them.")
        if state:
            LOG.warning("The use of 'state' variable is deprecated, and will "
                        "be removed in the next upcomming release. You should "
                        "consider using 'last_processed_timestamp' variable.")

        results = self._storage_state.get_all(
            identifier=scope_id,
            scope_key=scope_key,
            fetcher=fetcher,
            collector=collector,
        )

        if len(results) < 1:
            raise http_exceptions.NotFound(
                "No resource found for provided filters.")

        serialized_results = [{
            'scope_id': r.identifier,
            'scope_key': r.scope_key,
            'fetcher': r.fetcher,
            'collector': r.collector,
        } for r in results]

        if not last_processed_timestamp:
            last_processed_timestamp = state
        self._client.cast({},
                          'reset_state',
                          res_data={
                              'scopes':
                              serialized_results,
                              'last_processed_timestamp':
                              last_processed_timestamp.isoformat()
                          })

        return {}, 202

    @api_utils.add_input_schema(
        'body', {
            voluptuous.Required('scope_id'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('scope_key'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('fetcher'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('collector'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('active'): api_utils.SingleQueryParam(bool),
        })
    @api_utils.add_output_schema({
        voluptuous.Required('scope_id'):
        vutils.get_string_type(),
        voluptuous.Required('scope_key'):
        vutils.get_string_type(),
        voluptuous.Required('fetcher'):
        vutils.get_string_type(),
        voluptuous.Required('collector'):
        vutils.get_string_type(),
        # This "state" property should be removed in the next release.
        voluptuous.Required('state'):
        vutils.get_string_type(),
        voluptuous.Optional('last_processed_timestamp'):
        voluptuous.Coerce(tzutils.dt_from_iso),
        voluptuous.Required('active'):
        bool,
        voluptuous.Required('scope_activation_toggle_date'):
        vutils.get_string_type()
    })
    def patch(self,
              scope_id,
              scope_key=None,
              fetcher=None,
              collector=None,
              active=None):

        policy.authorize(
            flask.request.context, 'scope:patch_state',
            {'tenant_id': scope_id or flask.request.context.project_id})
        results = self._storage_state.get_all(identifier=scope_id, active=None)

        if len(results) < 1:
            raise http_exceptions.NotFound(
                "No resource found for provided filters.")

        if len(results) > 1:
            LOG.debug(
                "Too many resources found with the same scope_id [%s], "
                "scopes found: [%s].", scope_id, results)
            raise http_exceptions.NotFound("Too many resources found with "
                                           "the same scope_id: %s." % scope_id)

        scope_to_update = results[0]
        LOG.debug("Executing update of storage scope: [%s].", scope_to_update)

        self._storage_state.update_storage_scope(scope_to_update,
                                                 scope_key=scope_key,
                                                 fetcher=fetcher,
                                                 collector=collector,
                                                 active=active)

        storage_scopes = self._storage_state.get_all(identifier=scope_id,
                                                     active=active)
        update_storage_scope = storage_scopes[0]
        return {
            'scope_id':
            update_storage_scope.identifier,
            'scope_key':
            update_storage_scope.scope_key,
            'fetcher':
            update_storage_scope.fetcher,
            'collector':
            update_storage_scope.collector,
            'state':
            update_storage_scope.state.isoformat(),
            'last_processed_timestamp':
            update_storage_scope.last_processed_timestamp.isoformat(),
            'active':
            update_storage_scope.active,
            'scope_activation_toggle_date':
            update_storage_scope.scope_activation_toggle_date.isoformat()
        }

    @api_utils.add_input_schema(
        'body', {
            voluptuous.Required('scope_id'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('scope_key'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('fetcher'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('collector'): api_utils.SingleQueryParam(str),
            voluptuous.Optional('active'): api_utils.SingleQueryParam(bool),
        })
    @api_utils.add_output_schema({
        voluptuous.Required('scope_id'):
        vutils.get_string_type(),
        voluptuous.Required('scope_key'):
        vutils.get_string_type(),
        voluptuous.Required('fetcher'):
        vutils.get_string_type(),
        voluptuous.Required('collector'):
        vutils.get_string_type(),
        # This "state" property should be removed in the next release.
        voluptuous.Required('state'):
        vutils.get_string_type(),
        voluptuous.Optional('last_processed_timestamp'):
        voluptuous.Coerce(tzutils.dt_from_iso),
        voluptuous.Required('active'):
        bool,
        voluptuous.Required('scope_activation_toggle_date'):
        vutils.get_string_type()
    })
    def post(self,
             scope_id,
             scope_key=None,
             fetcher=None,
             collector=None,
             active=None):

        policy.authorize(
            flask.request.context, 'scope:post_state',
            {'tenant_id': scope_id or flask.request.context.project_id})
        results = self._storage_state.get_all(identifier=scope_id)

        if len(results) >= 1:
            LOG.debug(
                "There is already a scope with ID [%s], "
                "scopes found: [%s].", scope_id, results)
            raise http_exceptions.NotFound("Cannot create a scope with an "
                                           "already existing scope_id: %s." %
                                           scope_id)

        LOG.debug(
            "Creating storage scope with data: [scope_id=%s, "
            "scope_key=%s, fetcher=%s, collector=%s, active=%s].", scope_id,
            scope_key, fetcher, collector, active)

        self._storage_state.create_scope(scope_id,
                                         None,
                                         fetcher=fetcher,
                                         collector=collector,
                                         scope_key=scope_key,
                                         active=active)

        storage_scopes = self._storage_state.get_all(identifier=scope_id)

        update_storage_scope = storage_scopes[0]
        last_processed_timestamp = None
        if update_storage_scope.last_processed_timestamp.isoformat():
            last_processed_timestamp =\
                update_storage_scope.last_processed_timestamp.isoformat()

        return {
            'scope_id':
            update_storage_scope.identifier,
            'scope_key':
            update_storage_scope.scope_key,
            'fetcher':
            update_storage_scope.fetcher,
            'collector':
            update_storage_scope.collector,
            'state':
            last_processed_timestamp,
            'last_processed_timestamp':
            last_processed_timestamp,
            'active':
            update_storage_scope.active,
            'scope_activation_toggle_date':
            update_storage_scope.scope_activation_toggle_date.isoformat()
        }
예제 #28
0
파일: addons.py 프로젝트: pssc/supervisor
from ..coresys import CoreSysAttributes
from ..docker.stats import DockerStats
from ..exceptions import APIError
from ..validate import DOCKER_PORTS
from .utils import api_process, api_process_raw, api_validate

_LOGGER: logging.Logger = logging.getLogger(__name__)

SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): vol.Coerce(str)})

# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema(
    {
        vol.Optional(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
        vol.Optional(ATTR_NETWORK): vol.Maybe(DOCKER_PORTS),
        vol.Optional(ATTR_AUTO_UPDATE): vol.Boolean(),
        vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(vol.Coerce(str)),
        vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(vol.Coerce(str)),
        vol.Optional(ATTR_INGRESS_PANEL): vol.Boolean(),
    }
)

# pylint: disable=no-value-for-parameter
SCHEMA_SECURITY = vol.Schema({vol.Optional(ATTR_PROTECTED): vol.Boolean()})


class APIAddons(CoreSysAttributes):
    """Handle RESTful API for add-on functions."""

    def _extract_addon(
        self, request: web.Request, check_installed: bool = True
예제 #29
0
 vol.Required(ATTR_NAME): vol.Coerce(str),
 vol.Required(ATTR_VERSION): vol.Coerce(str),
 vol.Required(ATTR_SLUG): vol.Coerce(str),
 vol.Required(ATTR_DESCRIPTON): vol.Coerce(str),
 vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)],
 vol.Optional(ATTR_MACHINE): [vol.In(MACHINE_ALL)],
 vol.Optional(ATTR_URL): vol.Url(),
 vol.Required(ATTR_STARTUP):
     vol.All(_simple_startup, vol.In(STARTUP_ALL)),
 vol.Required(ATTR_BOOT):
     vol.In([BOOT_AUTO, BOOT_MANUAL]),
 vol.Optional(ATTR_PORTS): DOCKER_PORTS,
 vol.Optional(ATTR_PORTS_DESCRIPTION): DOCKER_PORTS_DESCRIPTION,
 vol.Optional(ATTR_WEBUI):
     vol.Match(r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"),
 vol.Optional(ATTR_INGRESS, default=False): vol.Boolean(),
 vol.Optional(ATTR_INGRESS_PORT, default=8099): vol.Any(NETWORK_PORT, vol.Equal(0)),
 vol.Optional(ATTR_INGRESS_ENTRY): vol.Coerce(str),
 vol.Optional(ATTR_PANEL_ICON, default="mdi:puzzle"): vol.Coerce(str),
 vol.Optional(ATTR_PANEL_TITLE): vol.Coerce(str),
 vol.Optional(ATTR_PANEL_ADMIN, default=True): vol.Boolean(),
 vol.Optional(ATTR_HOMEASSISTANT): vol.Maybe(vol.Coerce(str)),
 vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
 vol.Optional(ATTR_HOST_PID, default=False): vol.Boolean(),
 vol.Optional(ATTR_HOST_IPC, default=False): vol.Boolean(),
 vol.Optional(ATTR_HOST_DBUS, default=False): vol.Boolean(),
 vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")],
 vol.Optional(ATTR_AUTO_UART, default=False): vol.Boolean(),
 vol.Optional(ATTR_TMPFS):
     vol.Match(r"^size=(\d)*[kmg](,uid=\d{1,4})?(,rw)?$"),
 vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)],
예제 #30
0
 vol.Required(ATTR_DESCRIPTON):
 vol.Coerce(str),
 vol.Optional(ATTR_URL):
 vol.Url(),
 vol.Optional(ATTR_ARCH, default=ARCH_ALL): [vol.In(ARCH_ALL)],
 vol.Optional(ATTR_MACHINE): [vol.In(MACHINE_ALL)],
 vol.Required(ATTR_STARTUP):
 vol.All(_simple_startup, vol.In(STARTUP_ALL)),
 vol.Required(ATTR_BOOT):
 vol.In([BOOT_AUTO, BOOT_MANUAL]),
 vol.Optional(ATTR_PORTS):
 DOCKER_PORTS,
 vol.Optional(ATTR_WEBUI):
 vol.Match(r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"),
 vol.Optional(ATTR_HOST_NETWORK, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_HOST_PID, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_HOST_IPC, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_HOST_DBUS, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")],
 vol.Optional(ATTR_AUTO_UART, default=False):
 vol.Boolean(),
 vol.Optional(ATTR_TMPFS):
 vol.Match(r"^size=(\d)*[kmg](,uid=\d{1,4})?(,rw)?$"),
 vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)],
 vol.Optional(ATTR_ENVIRONMENT): {
     vol.Match(r"\w*"): vol.Coerce(str)
 },