mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-24 09:36:31 +00:00
commit
7f9232d2b9
3
API.md
3
API.md
@ -512,7 +512,8 @@ Get all available addons.
|
||||
"ip_address": "ip address",
|
||||
"ingress": "bool",
|
||||
"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}"
|
||||
|
||||
@property
|
||||
def ingress_internal(self):
|
||||
"""Return Ingress host URL."""
|
||||
return f"http://{self.ip_address}:{self._mesh[ATTR_INGRESS_PORT]}"
|
||||
def ingress_port(self):
|
||||
"""Return 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
|
||||
def host_network(self):
|
||||
|
@ -148,7 +148,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema({
|
||||
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): 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_HOMEASSISTANT): vol.Maybe(vol.Coerce(str)),
|
||||
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
|
||||
|
@ -44,6 +44,7 @@ from ..const import (
|
||||
ATTR_ICON,
|
||||
ATTR_INGRESS,
|
||||
ATTR_INGRESS_ENTRY,
|
||||
ATTR_INGRESS_PORT,
|
||||
ATTR_INGRESS_URL,
|
||||
ATTR_INSTALLED,
|
||||
ATTR_IP_ADDRESS,
|
||||
@ -223,6 +224,7 @@ class APIAddons(CoreSysAttributes):
|
||||
ATTR_INGRESS: addon.with_ingress,
|
||||
ATTR_INGRESS_ENTRY: addon.ingress_entry,
|
||||
ATTR_INGRESS_URL: addon.ingress_url,
|
||||
ATTR_INGRESS_PORT: addon.ingress_port,
|
||||
}
|
||||
|
||||
@api_process
|
||||
|
@ -43,7 +43,7 @@ class APIIngress(CoreSysAttributes):
|
||||
|
||||
def _create_url(self, addon: Addon, path: str) -> str:
|
||||
"""Create URL to container."""
|
||||
return f"{addon.ingress_internal}/{path}"
|
||||
return f"http://{addon.ip_address}:{addon.ingress_port}/{path}"
|
||||
|
||||
@api_process
|
||||
async def create_session(self, request: web.Request) -> Dict[str, Any]:
|
||||
@ -131,7 +131,12 @@ class APIIngress(CoreSysAttributes):
|
||||
):
|
||||
# Return Response
|
||||
body = await result.read()
|
||||
return web.Response(headers=headers, status=result.status, body=body)
|
||||
return web.Response(
|
||||
headers=headers,
|
||||
status=result.status,
|
||||
content_type=result.content_type,
|
||||
body=body,
|
||||
)
|
||||
|
||||
# Stream response
|
||||
response = web.StreamResponse(status=result.status, headers=headers)
|
||||
@ -156,12 +161,7 @@ def _init_header(
|
||||
|
||||
# filter flags
|
||||
for name, value in request.headers.items():
|
||||
if name in (
|
||||
hdrs.CONTENT_LENGTH,
|
||||
hdrs.CONTENT_TYPE,
|
||||
hdrs.CONTENT_ENCODING,
|
||||
istr(HEADER_TOKEN),
|
||||
):
|
||||
if name in (hdrs.CONTENT_LENGTH, hdrs.CONTENT_ENCODING, istr(HEADER_TOKEN)):
|
||||
continue
|
||||
headers[name] = value
|
||||
|
||||
|
@ -3,7 +3,7 @@ from pathlib import Path
|
||||
from ipaddress import ip_network
|
||||
|
||||
|
||||
HASSIO_VERSION = "154"
|
||||
HASSIO_VERSION = "155"
|
||||
|
||||
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
|
||||
URL_HASSIO_VERSION = "https://s3.amazonaws.com/hassio-version/{channel}.json"
|
||||
|
@ -1,14 +1,15 @@
|
||||
"""Fetch last versions from webserver."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Dict, Optional
|
||||
import random
|
||||
import secrets
|
||||
from typing import Dict, Optional
|
||||
|
||||
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 .utils.dt import utc_from_timestamp, utcnow
|
||||
from .utils.json import JsonConfig
|
||||
from .utils.dt import utcnow, utc_from_timestamp
|
||||
from .validate import SCHEMA_INGRESS_CONFIG
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -34,6 +35,11 @@ class Ingress(JsonConfig, CoreSysAttributes):
|
||||
"""Return sessions."""
|
||||
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:
|
||||
"""Update internal data."""
|
||||
self._update_token_list()
|
||||
@ -101,3 +107,14 @@ class Ingress(JsonConfig, CoreSysAttributes):
|
||||
self.sessions[session] = valid_until.timestamp()
|
||||
|
||||
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_PASSWORD,
|
||||
ATTR_PORT,
|
||||
ATTR_PORTS,
|
||||
ATTR_REFRESH_TOKEN,
|
||||
ATTR_SESSION,
|
||||
ATTR_SSL,
|
||||
@ -143,6 +144,13 @@ SCHEMA_AUTH_CONFIG = vol.Schema({SHA256: SHA256})
|
||||
|
||||
|
||||
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,
|
||||
)
|
||||
|
@ -20,3 +20,22 @@ def test_session_handling(coresys):
|
||||
coresys.ingress.sessions[session] = not_valid.timestamp()
|
||||
assert not coresys.ingress.validate_session(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