Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Or set the following label if using `swag-auto-proxy`:
### Labels:
- `swag_ondemand=enable` - required for on-demand.
- `swag_ondemand_urls=https://wake.domain.com,https://app.domain.com/up` - *optional* - overrides the monitored URLs for starting the container on-demand. Defaults to using the value of the `swag_url` label, if you've already set it for `swag-auto-proxy`, or `https://somecontainer.,http://somecontainer.` otherwise.
- `swag_ondemand_websocket=1` - required for apps that communicate over a websocket, such as selkies based apps.

### URLs:
- Accessed URLs need to start with one of `swag_ondemand_urls` to be matched, for example, setting `swag_ondemand_urls=https://plex.` will apply to `https://plex.domain.com` and `https://plex.domain.com/something`.
Expand Down
46 changes: 31 additions & 15 deletions root/app/ondemand/container_thread.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from data_classes import DockerHost, OnDemandContainer
from shared_state import last_accessed_urls, last_accessed_urls_lock
from shared_state import last_accessed_urls, last_accessed_urls_lock, websocket_terminated_urls, websocket_terminated_urls_lock

from datetime import datetime
import logging
Expand Down Expand Up @@ -61,30 +61,41 @@ def process_containers(self):
for container in containers:
default_url = container.labels.get("swag_url", f"{container.name}.").rstrip("*")
container_urls = container.labels.get("swag_ondemand_urls", f"https://{default_url},http://{default_url}")
websocket = container.labels.get("swag_ondemand_websocket", "0").lower() in ("true", "1")

if container.name not in docker_host.ondemand_containers:
last_accessed = datetime.now()
logging.info(f"Started monitoring {container.name} on {docker_host.url} for urls: {container_urls}")
else:
existing_container = docker_host.ondemand_containers[container.name]
last_accessed = existing_container.last_accessed
if container_urls != existing_container.urls:
if container.name in docker_host.ondemand_containers:
docker_host.ondemand_containers[container.name].status = container.status
docker_host.ondemand_containers[container.name].websocket = websocket
if container_urls != docker_host.ondemand_containers[container.name].urls:
docker_host.ondemand_containers[container.name].urls = container_urls
logging.info(f"Updated urls for {container.name} on {docker_host.url} to: {container_urls}")
else:
docker_host.ondemand_containers[container.name] = OnDemandContainer(
status=container.status,
urls=container_urls,
last_accessed=datetime.now(),
websocket=websocket
)
logging.info(f"Started monitoring {container.name} on {docker_host.url} for urls: {container_urls}")

docker_host.ondemand_containers[container.name] = OnDemandContainer(
status=container.status,
urls=container_urls,
last_accessed=last_accessed
)

def stop_containers(self):
def stop_containers(self, websocket_terminated_urls_combined: str):
for docker_host in self.docker_hosts:
if not docker_host.is_connected:
continue
for container_name, ondemand_container in docker_host.ondemand_containers.items():
if ondemand_container.status != "running":
continue

if ondemand_container.websocket and not ondemand_container.terminated:
for ondemand_url in ondemand_container.urls.split(","):
if ondemand_url in websocket_terminated_urls_combined:
ondemand_container.last_accessed = datetime.now()
ondemand_container.terminated = True
break
if not ondemand_container.terminated:
continue

inactive_seconds = (datetime.now() - ondemand_container.last_accessed).total_seconds()
if inactive_seconds < STOP_THRESHOLD:
continue
Expand All @@ -109,6 +120,7 @@ def start_containers(self, last_accessed_urls_combined: str):
for ondemand_url in ondemand_container.urls.split(","):
if ondemand_url in last_accessed_urls_combined:
ondemand_container.last_accessed = datetime.now()
ondemand_container.terminated = False
accessed = True
break

Expand Down Expand Up @@ -148,10 +160,14 @@ def run(self):
last_accessed_urls_combined = ",".join(last_accessed_urls)
last_accessed_urls.clear()

with websocket_terminated_urls_lock:
websocket_terminated_urls_combined = ",".join(websocket_terminated_urls)
websocket_terminated_urls.clear()

self.send_wol(last_accessed_urls_combined)
self.process_containers()
self.start_containers(last_accessed_urls_combined)
self.stop_containers()
self.stop_containers(websocket_terminated_urls_combined)
except Exception as e:
logging.exception(e)
time.sleep(CONTAINER_QUERY_SLEEP)
6 changes: 4 additions & 2 deletions root/app/ondemand/data_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class OnDemandContainer:
status: str
urls: str
last_accessed: datetime
websocket: bool
terminated: bool = False

@dataclass
class DockerHost:
Expand Down Expand Up @@ -57,7 +59,7 @@ def get_container(self, container_name: str):
if not client or not self.is_connected:
return None
return client.containers.get(container_name)
except (docker.errors.DockerException, requests.exceptions.ConnectionError):
except (docker.errors.DockerException, requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
self.handle_disconnect()
return None

Expand All @@ -67,6 +69,6 @@ def get_containers(self):
if not client or not self.is_connected:
return None
return client.containers.list(all=True, filters={"label": ["swag_ondemand=enable"]})
except (docker.errors.DockerException, requests.exceptions.ConnectionError):
except (docker.errors.DockerException, requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
self.handle_disconnect()
return None
10 changes: 7 additions & 3 deletions root/app/ondemand/log_reader_thread.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from shared_state import last_accessed_urls, last_accessed_urls_lock
from shared_state import last_accessed_urls, last_accessed_urls_lock, websocket_terminated_urls, websocket_terminated_urls_lock

import logging
import os
Expand Down Expand Up @@ -43,8 +43,12 @@ def run(self):
for part in line.split():
if not part.startswith("http"):
continue
with last_accessed_urls_lock:
last_accessed_urls.add(part)
if '" 101 ' in line:
with websocket_terminated_urls_lock:
websocket_terminated_urls.add(part)
else:
with last_accessed_urls_lock:
last_accessed_urls.add(part)
break
except Exception as e:
logging.exception(e)
Expand Down
2 changes: 2 additions & 0 deletions root/app/ondemand/shared_state.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import threading

websocket_terminated_urls = set()
websocket_terminated_urls_lock = threading.Lock()
last_accessed_urls = set()
last_accessed_urls_lock = threading.Lock()
Loading