diff --git a/API.md b/API.md index d1ac0ce72..fd9ab0a73 100644 --- a/API.md +++ b/API.md @@ -480,6 +480,7 @@ Get all available addons. "build": "bool", "options": "{}", "network": "{}|null", + "network_description": "{}|null", "host_network": "bool", "host_pid": "bool", "host_ipc": "bool", diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 50fc05208..c6980a24e 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -56,6 +56,7 @@ from ..const import ( ATTR_NETWORK, ATTR_OPTIONS, ATTR_PORTS, + ATTR_PORTS_DESCRIPTION, ATTR_PRIVILEGED, ATTR_PROTECTED, ATTR_REPOSITORY, @@ -364,10 +365,15 @@ class Addon(CoreSysAttributes): """Return list of discoverable components/platforms.""" return self._mesh.get(ATTR_DISCOVERY, []) + @property + def ports_description(self): + """Return descriptions of ports.""" + return self._mesh.get(ATTR_PORTS_DESCRIPTION) + @property def ports(self): """Return ports of add-on.""" - if self.host_network or ATTR_PORTS not in self._mesh: + if ATTR_PORTS not in self._mesh: return None if not self.is_installed or \ @@ -380,13 +386,15 @@ class Addon(CoreSysAttributes): """Set custom ports of add-on.""" if value is None: self._data.user[self._id].pop(ATTR_NETWORK, None) - else: - new_ports = {} - for container_port, host_port in value.items(): - if container_port in self._mesh.get(ATTR_PORTS, {}): - new_ports[container_port] = host_port + return - self._data.user[self._id][ATTR_NETWORK] = new_ports + # Secure map ports to value + new_ports = {} + for container_port, host_port in value.items(): + if container_port in self._mesh.get(ATTR_PORTS, {}): + new_ports[container_port] = host_port + + self._data.user[self._id][ATTR_NETWORK] = new_ports @property def ingress_url(self): diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index e0d0c849c..1bc5ca216 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -30,8 +30,8 @@ from ..const import ( ATTR_GPIO, ATTR_HASSIO_API, ATTR_HASSIO_ROLE, - ATTR_HOMEASSISTANT_API, ATTR_HOMEASSISTANT, + ATTR_HOMEASSISTANT_API, ATTR_HOST_DBUS, ATTR_HOST_IPC, ATTR_HOST_NETWORK, @@ -51,6 +51,7 @@ from ..const import ( ATTR_NETWORK, ATTR_OPTIONS, ATTR_PORTS, + ATTR_PORTS_DESCRIPTION, ATTR_PRIVILEGED, ATTR_PROTECTED, ATTR_REPOSITORY, @@ -81,7 +82,14 @@ from ..const import ( STATE_STOPPED, ) from ..discovery.validate import valid_discovery_service -from ..validate import ALSA_DEVICE, DOCKER_PORTS, NETWORK_PORT, TOKEN, UUID_MATCH +from ..validate import ( + ALSA_DEVICE, + DOCKER_PORTS, + DOCKER_PORTS_DESCRIPTION, + NETWORK_PORT, + TOKEN, + UUID_MATCH, +) _LOGGER = logging.getLogger(__name__) @@ -145,6 +153,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ 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(), diff --git a/hassio/api/addons.py b/hassio/api/addons.py index c99e93d67..455195f08 100644 --- a/hassio/api/addons.py +++ b/hassio/api/addons.py @@ -58,6 +58,7 @@ from ..const import ( ATTR_MEMORY_USAGE, ATTR_NAME, ATTR_NETWORK, + ATTR_NETWORK_DESCRIPTION, ATTR_NETWORK_RX, ATTR_NETWORK_TX, ATTR_OPTIONS, @@ -194,6 +195,7 @@ class APIAddons(CoreSysAttributes): ATTR_AVAILABLE: addon.available, ATTR_BUILD: addon.need_build, ATTR_NETWORK: addon.ports, + ATTR_NETWORK_DESCRIPTION: addon.ports_description, ATTR_HOST_NETWORK: addon.host_network, ATTR_HOST_PID: addon.host_pid, ATTR_HOST_IPC: addon.host_ipc, diff --git a/hassio/const.py b/hassio/const.py index e0a10bfe0..debb523ae 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -92,6 +92,7 @@ ATTR_DESCRIPTON = "description" ATTR_STARTUP = "startup" ATTR_BOOT = "boot" ATTR_PORTS = "ports" +ATTR_PORTS_DESCRIPTION = "ports_description" ATTR_PORT = "port" ATTR_SSL = "ssl" ATTR_MAP = "map" @@ -122,6 +123,7 @@ ATTR_HOST_PID = "host_pid" ATTR_HOST_IPC = "host_ipc" ATTR_HOST_DBUS = "host_dbus" ATTR_NETWORK = "network" +ATTR_NETWORK_DESCRIPTION = "network_description" ATTR_TMPFS = "tmpfs" ATTR_PRIVILEGED = "privileged" ATTR_USER = "user" diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index 6c544b826..fbda3ce60 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -147,7 +147,7 @@ class DockerAddon(DockerInterface): @property def ports(self) -> Optional[Dict[str, Union[str, int, None]]]: """Filter None from add-on ports.""" - if not self.addon.ports: + if self.addon.host_network or not self.addon.ports: return None return { diff --git a/hassio/validate.py b/hassio/validate.py index aa5504e5f..71b85c9d3 100644 --- a/hassio/validate.py +++ b/hassio/validate.py @@ -61,36 +61,18 @@ def validate_repository(repository): REPOSITORIES = vol.All([validate_repository], vol.Unique()) -# pylint: disable=inconsistent-return-statements -def convert_to_docker_ports(data): - """Convert data into Docker port list.""" - # dynamic ports - if data is None: - return None - - # single port - if isinstance(data, int): - return NETWORK_PORT(data) - - # port list - if isinstance(data, list) and len(data) > 2: - return vol.Schema([NETWORK_PORT])(data) - - # ip port mapping - if isinstance(data, list) and len(data) == 2: - return (vol.Coerce(str)(data[0]), NETWORK_PORT(data[1])) - - 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 + vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): vol.Maybe( + NETWORK_PORT + ) } ) +DOCKER_PORTS_DESCRIPTION = vol.Schema( + {vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")): vol.Coerce(str)} +) + # pylint: disable=no-value-for-parameter SCHEMA_HASS_CONFIG = vol.Schema(