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))
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}")
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
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))
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), }
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) }
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()))
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}")
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)), },
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):
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)), } )
'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(
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):
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."""
"""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,
# 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,
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):
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
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]:
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),
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):
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):
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()),
# 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(),
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):
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() }
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
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)],
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) },