mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-15 21:26:29 +00:00
Support dynamic ingress port (#1015)
* Support dynamic ingress port * Allow to remeber ports * Add tests * Fix schema * Cleanup handling / speed * Fix port
This commit is contained in:
parent
ead5993f3e
commit
c2deabb672
3
API.md
3
API.md
@ -512,7 +512,8 @@ Get all available addons.
|
|||||||
"ip_address": "ip address",
|
"ip_address": "ip address",
|
||||||
"ingress": "bool",
|
"ingress": "bool",
|
||||||
"ingress_entry": "null|/api/hassio_ingress/slug",
|
"ingress_entry": "null|/api/hassio_ingress/slug",
|
||||||
"ingress_url": "null|/api/hassio_ingress/slug/entry.html"
|
"ingress_url": "null|/api/hassio_ingress/slug/entry.html",
|
||||||
|
"ingress_port": "null|int"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -431,9 +431,15 @@ class Addon(CoreSysAttributes):
|
|||||||
return f"{proto}://[HOST]:{port}{s_suffix}"
|
return f"{proto}://[HOST]:{port}{s_suffix}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ingress_internal(self):
|
def ingress_port(self):
|
||||||
"""Return Ingress host URL."""
|
"""Return Ingress port."""
|
||||||
return f"http://{self.ip_address}:{self._mesh[ATTR_INGRESS_PORT]}"
|
if not self.is_installed or not self.with_ingress:
|
||||||
|
return None
|
||||||
|
|
||||||
|
port = self._mesh[ATTR_INGRESS_PORT]
|
||||||
|
if port == 0:
|
||||||
|
return self.sys_ingress.get_dynamic_port(self.slug)
|
||||||
|
return port
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def host_network(self):
|
def host_network(self):
|
||||||
|
@ -148,7 +148,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema({
|
|||||||
vol.Optional(ATTR_WEBUI):
|
vol.Optional(ATTR_WEBUI):
|
||||||
vol.Match(r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"),
|
vol.Match(r"^(?:https?|\[PROTO:\w+\]):\/\/\[HOST\]:\[PORT:\d+\].*$"),
|
||||||
vol.Optional(ATTR_INGRESS, default=False): vol.Boolean(),
|
vol.Optional(ATTR_INGRESS, default=False): vol.Boolean(),
|
||||||
vol.Optional(ATTR_INGRESS_PORT, default=8099): NETWORK_PORT,
|
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_INGRESS_ENTRY): vol.Coerce(str),
|
||||||
vol.Optional(ATTR_HOMEASSISTANT): vol.Maybe(vol.Coerce(str)),
|
vol.Optional(ATTR_HOMEASSISTANT): vol.Maybe(vol.Coerce(str)),
|
||||||
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
|
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
|
||||||
|
@ -44,6 +44,7 @@ from ..const import (
|
|||||||
ATTR_ICON,
|
ATTR_ICON,
|
||||||
ATTR_INGRESS,
|
ATTR_INGRESS,
|
||||||
ATTR_INGRESS_ENTRY,
|
ATTR_INGRESS_ENTRY,
|
||||||
|
ATTR_INGRESS_PORT,
|
||||||
ATTR_INGRESS_URL,
|
ATTR_INGRESS_URL,
|
||||||
ATTR_INSTALLED,
|
ATTR_INSTALLED,
|
||||||
ATTR_IP_ADDRESS,
|
ATTR_IP_ADDRESS,
|
||||||
@ -223,6 +224,7 @@ class APIAddons(CoreSysAttributes):
|
|||||||
ATTR_INGRESS: addon.with_ingress,
|
ATTR_INGRESS: addon.with_ingress,
|
||||||
ATTR_INGRESS_ENTRY: addon.ingress_entry,
|
ATTR_INGRESS_ENTRY: addon.ingress_entry,
|
||||||
ATTR_INGRESS_URL: addon.ingress_url,
|
ATTR_INGRESS_URL: addon.ingress_url,
|
||||||
|
ATTR_INGRESS_PORT: addon.ingress_port,
|
||||||
}
|
}
|
||||||
|
|
||||||
@api_process
|
@api_process
|
||||||
|
@ -43,7 +43,7 @@ class APIIngress(CoreSysAttributes):
|
|||||||
|
|
||||||
def _create_url(self, addon: Addon, path: str) -> str:
|
def _create_url(self, addon: Addon, path: str) -> str:
|
||||||
"""Create URL to container."""
|
"""Create URL to container."""
|
||||||
return f"{addon.ingress_internal}/{path}"
|
return f"http://{addon.ip_address}:{addon.ingress_port}/{path}"
|
||||||
|
|
||||||
@api_process
|
@api_process
|
||||||
async def create_session(self, request: web.Request) -> Dict[str, Any]:
|
async def create_session(self, request: web.Request) -> Dict[str, Any]:
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
"""Fetch last versions from webserver."""
|
"""Fetch last versions from webserver."""
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Optional
|
import random
|
||||||
import secrets
|
import secrets
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from .addons.addon import Addon
|
from .addons.addon import Addon
|
||||||
from .const import ATTR_SESSION, FILE_HASSIO_INGRESS
|
from .const import ATTR_PORTS, ATTR_SESSION, FILE_HASSIO_INGRESS
|
||||||
from .coresys import CoreSys, CoreSysAttributes
|
from .coresys import CoreSys, CoreSysAttributes
|
||||||
|
from .utils.dt import utc_from_timestamp, utcnow
|
||||||
from .utils.json import JsonConfig
|
from .utils.json import JsonConfig
|
||||||
from .utils.dt import utcnow, utc_from_timestamp
|
|
||||||
from .validate import SCHEMA_INGRESS_CONFIG
|
from .validate import SCHEMA_INGRESS_CONFIG
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -34,6 +35,11 @@ class Ingress(JsonConfig, CoreSysAttributes):
|
|||||||
"""Return sessions."""
|
"""Return sessions."""
|
||||||
return self._data[ATTR_SESSION]
|
return self._data[ATTR_SESSION]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ports(self) -> Dict[str, int]:
|
||||||
|
"""Return list of dynamic ports."""
|
||||||
|
return self._data[ATTR_PORTS]
|
||||||
|
|
||||||
async def load(self) -> None:
|
async def load(self) -> None:
|
||||||
"""Update internal data."""
|
"""Update internal data."""
|
||||||
self._update_token_list()
|
self._update_token_list()
|
||||||
@ -101,3 +107,14 @@ class Ingress(JsonConfig, CoreSysAttributes):
|
|||||||
self.sessions[session] = valid_until.timestamp()
|
self.sessions[session] = valid_until.timestamp()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_dynamic_port(self, addon_slug: str) -> int:
|
||||||
|
"""Get/Create a dynamic port from range."""
|
||||||
|
if addon_slug in self.ports:
|
||||||
|
return self.ports[addon_slug]
|
||||||
|
port = random.randint(62000, 65500)
|
||||||
|
|
||||||
|
# Save port for next time
|
||||||
|
self.ports[addon_slug] = port
|
||||||
|
self.save_data()
|
||||||
|
return port
|
||||||
|
@ -18,6 +18,7 @@ from .const import (
|
|||||||
ATTR_LAST_VERSION,
|
ATTR_LAST_VERSION,
|
||||||
ATTR_PASSWORD,
|
ATTR_PASSWORD,
|
||||||
ATTR_PORT,
|
ATTR_PORT,
|
||||||
|
ATTR_PORTS,
|
||||||
ATTR_REFRESH_TOKEN,
|
ATTR_REFRESH_TOKEN,
|
||||||
ATTR_SESSION,
|
ATTR_SESSION,
|
||||||
ATTR_SSL,
|
ATTR_SSL,
|
||||||
@ -143,6 +144,13 @@ SCHEMA_AUTH_CONFIG = vol.Schema({SHA256: SHA256})
|
|||||||
|
|
||||||
|
|
||||||
SCHEMA_INGRESS_CONFIG = vol.Schema(
|
SCHEMA_INGRESS_CONFIG = vol.Schema(
|
||||||
{vol.Required(ATTR_SESSION, default=dict): vol.Schema({TOKEN: vol.Coerce(float)})},
|
{
|
||||||
|
vol.Required(ATTR_SESSION, default=dict): vol.Schema(
|
||||||
|
{TOKEN: vol.Coerce(float)}
|
||||||
|
),
|
||||||
|
vol.Required(ATTR_PORTS, default=dict): vol.Schema(
|
||||||
|
{vol.Coerce(str): NETWORK_PORT}
|
||||||
|
),
|
||||||
|
},
|
||||||
extra=vol.REMOVE_EXTRA,
|
extra=vol.REMOVE_EXTRA,
|
||||||
)
|
)
|
||||||
|
@ -20,3 +20,22 @@ def test_session_handling(coresys):
|
|||||||
coresys.ingress.sessions[session] = not_valid.timestamp()
|
coresys.ingress.sessions[session] = not_valid.timestamp()
|
||||||
assert not coresys.ingress.validate_session(session)
|
assert not coresys.ingress.validate_session(session)
|
||||||
assert not coresys.ingress.validate_session("invalid session")
|
assert not coresys.ingress.validate_session("invalid session")
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamic_ports(coresys):
|
||||||
|
"""Test dyanmic port handling."""
|
||||||
|
port_test1 = coresys.ingress.get_dynamic_port("test1")
|
||||||
|
|
||||||
|
assert port_test1
|
||||||
|
assert coresys.ingress.save_data.called
|
||||||
|
assert port_test1 == coresys.ingress.get_dynamic_port("test1")
|
||||||
|
|
||||||
|
port_test2 = coresys.ingress.get_dynamic_port("test2")
|
||||||
|
|
||||||
|
assert port_test2
|
||||||
|
assert port_test2 != port_test1
|
||||||
|
|
||||||
|
assert port_test2 > 62000
|
||||||
|
assert port_test2 < 65500
|
||||||
|
assert port_test1 > 62000
|
||||||
|
assert port_test1 < 65500
|
||||||
|
Loading…
x
Reference in New Issue
Block a user