fix bwcli when using redis sentinels, init work on linux ha and init work on static instances

This commit is contained in:
florian 2024-04-07 21:50:04 +02:00
parent 936600a0d7
commit 21be7c12ac
No known key found for this signature in database
GPG key ID: 93EE47CC3D061500
8 changed files with 281 additions and 119 deletions

View file

@ -2,17 +2,16 @@
## v1.5.7 - ????/??/??
- [LINUX] Fix potential issues when removing the bunkerweb package
- [BUGFIX] Fix rare error when the cache is not properly initialized and jobs are executed
- [FEATURE] Add an automatic renaming of old database tables when upgrading to a new version in order to avoid data loss
- [FEATURE] Add the possibility to add custom bwcli commands in plugins
- [BUGFIX] Fix bug when downloading new mmdb files
- [BUGFIX] Remove potential false positives with ModSecurity on the jobs page of the web UI
- [BUGFIX] Fix bwcli not working with Redis sentinel
- [BUGFIX] Fix potential issues when removing the bunkerweb Linux package
- [FEATURE] Add backup plugin to backup and restore easily the database
- [FEATURE] Add LETS_ENCRYPT_CLEAR_OLD_CERTS setting to control if old certificates should be removed when generating Let's Encrypt certificates (default is no)
- [FEATURE] Add DISABLE_DEFAULT_SERVER_STRICT_SNI setting to allow/block requests when SNI is unknown or unset (default is no)
- [MISC] Remove potential false positives with ModSecurity on the jobs page of the web UI
- [MISC] Fix rare bug when downloading new mmdb files
- [DOCUMENTATION] Add procedure to follow when upgrading from 1.5.7+
- [DOCUMENTATION] Add documentation about the procedure to follow when upgrading from a version prior to 1.5.0
- [DOCUMENTATION] Add upgrade procedure for 1.5.7+
- [MISC] Support custom bwcli commands using plugins
- [DEPS] Updated LuaJIT version to v2.1-20240314
## v1.5.6 - 2024/03/25

View file

@ -77,7 +77,8 @@ class CLI(ApiCaller):
if self.__use_redis:
self.__logger.info("Fetching redis configuration")
redis_host = self.__get_variable("REDIS_HOST")
if redis_host:
sentinel_hosts = self.__get_variable("REDIS_SENTINEL_HOSTS")
if redis_host or sentinel_hosts:
redis_port = self.__get_variable("REDIS_PORT", "6379")
assert isinstance(redis_port, str), "REDIS_PORT is not a string"
if not redis_port.isdigit():
@ -107,8 +108,6 @@ class CLI(ApiCaller):
redis_keepalive_pool = "10"
redis_keepalive_pool = int(redis_keepalive_pool)
self.__logger.info("Redis configuration is valid")
redis_ssl = self.__get_variable("REDIS_SSL", "no") == "yes"
username = self.__get_variable("REDIS_USERNAME", None) or None
password = self.__get_variable("REDIS_PASSWORD", None) or None
@ -177,7 +176,7 @@ class CLI(ApiCaller):
self.__use_redis = False
self.__logger.info("Connected to redis")
else:
self.__logger.error("USE_REDIS is set to yes but REDIS_HOST is not set, disabling redis")
self.__logger.error("USE_REDIS is set to yes but REDIS_HOST or REDIS_SENTINEL_HOSTS is not set, disabling redis")
self.__use_redis = False
if self.__integration == "linux":

View file

@ -197,6 +197,8 @@ class Configurator:
"NJS_VERSION",
"PKG_RELEASE",
"DOCKER_HOST",
"SLAVE_MODE",
"MASTER_MODE",
)
):
self.__logger.warning(f"Ignoring variable {variable} : {err}")

View file

@ -317,12 +317,12 @@
"emerg"
]
},
"STATIC_INSTANCES": {
"OVERRIDE_INSTANCES": {
"context": "global",
"default": "",
"help": "List of additional BunkerWeb instances separated with spaces (format : fqdn-or-ip:5000 fqdn-or-ip:5000)",
"id": "static-instances",
"label": "Static instances",
"help": "List of BunkerWeb instances separated with spaces (format : fqdn-or-ip:5000 fqdn-or-ip:5000)",
"id": "override-instances",
"label": "Override instances",
"regex": "^.*$",
"type": "text"
}

View file

@ -100,98 +100,104 @@ function start() {
log "SYSTEMCTL" "" "Created dummy variables.env file"
fi
# Create PID folder
if [ ! -f /var/run/bunkerweb ] ; then
mkdir -p /var/run/bunkerweb
chown nginx:nginx /var/run/bunkerweb
fi
# Stop scheduler if it's running
stop_scheduler
# Stop nginx if it's running
stop_nginx
# Generate temp conf for jobs and start nginx
DNS_RESOLVERS="$(grep "^DNS_RESOLVERS=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$DNS_RESOLVERS" = "" ] ; then
DNS_RESOLVERS="8.8.8.8 8.8.4.4"
fi
API_LISTEN_IP="$(grep "^API_LISTEN_IP=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_LISTEN_IP" = "" ] ; then
API_LISTEN_IP="127.0.0.1"
fi
API_HTTP_PORT="$(grep "^API_HTTP_PORT=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_HTTP_PORT" = "" ] ; then
API_HTTP_PORT="5000"
fi
API_SERVER_NAME="$(grep "^API_SERVER_NAME=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_SERVER_NAME" = "" ] ; then
API_SERVER_NAME="bwapi"
fi
API_WHITELIST_IP="$(grep "^API_WHITELIST_IP=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_WHITELIST_IP" = "" ] ; then
API_WHITELIST_IP="127.0.0.0/8"
fi
USE_REAL_IP="$(grep "^USE_REAL_IP=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$USE_REAL_IP" = "" ] ; then
USE_REAL_IP="no"
fi
USE_PROXY_PROTOCOL="$(grep "^USE_PROXY_PROTOCOL=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$USE_PROXY_PROTOCOL" = "" ] ; then
USE_PROXY_PROTOCOL="no"
fi
REAL_IP_FROM="$(grep "^REAL_IP_FROM=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$REAL_IP_FROM" = "" ] ; then
REAL_IP_FROM="192.168.0.0/16 172.16.0.0/12 10.0.0.0/8"
fi
REAL_IP_HEADER="$(grep "^REAL_IP_HEADER=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$REAL_IP_HEADER" = "" ] ; then
REAL_IP_HEADER="X-Forwarded-For"
fi
HTTP_PORT="$(grep "^HTTP_PORT=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$HTTP_PORT" = "" ] ; then
HTTP_PORT="80"
fi
HTTPS_PORT="$(grep "^HTTPS_PORT=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$HTTPS_PORT" = "" ] ; then
HTTPS_PORT="443"
fi
MODSECURITY_CRS_VERSION="$(grep "^MODSECURITY_CRS_VERSION=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$MODSECURITY_CRS_VERSION" = "" ] ; then
MODSECURITY_CRS_VERSION="4"
fi
sudo -E -u nginx -g nginx /bin/bash -c "echo -ne 'IS_LOADING=yes\nUSE_BUNKERNET=no\nSEND_ANONYMOUS_REPORT=no\nSERVER_NAME=\nMODSECURITY_CRS_VERSION=${MODSECURITY_CRS_VERSION}\nDNS_RESOLVERS=${DNS_RESOLVERS}\nAPI_HTTP_PORT=${API_HTTP_PORT}\nAPI_LISTEN_IP=${API_LISTEN_IP}\nAPI_SERVER_NAME=${API_SERVER_NAME}\nAPI_WHITELIST_IP=${API_WHITELIST_IP}\nUSE_REAL_IP=${USE_REAL_IP}\nUSE_PROXY_PROTOCOL=${USE_PROXY_PROTOCOL}\nREAL_IP_FROM=${REAL_IP_FROM}\nREAL_IP_HEADER=${REAL_IP_HEADER}\nHTTP_PORT=${HTTP_PORT}\nHTTPS_PORT=${HTTPS_PORT}\n' > /var/tmp/bunkerweb/tmp.env"
sudo -E -u nginx -g nginx /bin/bash -c "PYTHONPATH=/usr/share/bunkerweb/deps/python/ /usr/share/bunkerweb/gen/main.py --variables /var/tmp/bunkerweb/tmp.env --no-linux-reload"
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
log "SYSTEMCTL" "❌" "Error while generating config from /var/tmp/bunkerweb/tmp.env"
exit 1
fi
# Check if we are in slave/master mode
export MASTER_MODE="$(grep "^MASTER_MODE=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
export SLAVE_MODE="$(grep "^SLAVE_MODE=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ ! -f /var/run/bunkerweb ] ; then
mkdir -p /var/run/bunkerweb
chown nginx:nginx /var/run/bunkerweb
fi
# Start nginx
log "SYSTEMCTL" "" "Starting nginx ..."
sudo -E -u nginx -g nginx /usr/sbin/nginx -e /var/log/bunkerweb/error.log
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
log "SYSTEMCTL" "❌" "Error while executing temp nginx"
exit 1
fi
count=0
while [ $count -lt 10 ] ; do
check="$(curl -s -H "Host: healthcheck.bunkerweb.io" http://127.0.0.1:6000/healthz 2>&1)"
# shellcheck disable=SC2181
if [ $? -eq 0 ] && [ "$check" = "ok" ] ; then
break
if [ "$MASTER_MODE" != "yes" ] ; then
# Generate temp conf for jobs and start nginx
DNS_RESOLVERS="$(grep "^DNS_RESOLVERS=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$DNS_RESOLVERS" = "" ] ; then
DNS_RESOLVERS="8.8.8.8 8.8.4.4"
fi
count=$((count + 1))
sleep 1
log "SYSTEMCTL" "" "Waiting for nginx to start ..."
done
if [ $count -ge 10 ] ; then
log "SYSTEMCTL" "❌" "nginx is not started"
exit 1
API_LISTEN_IP="$(grep "^API_LISTEN_IP=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_LISTEN_IP" = "" ] ; then
API_LISTEN_IP="127.0.0.1"
fi
API_HTTP_PORT="$(grep "^API_HTTP_PORT=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_HTTP_PORT" = "" ] ; then
API_HTTP_PORT="5000"
fi
API_SERVER_NAME="$(grep "^API_SERVER_NAME=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_SERVER_NAME" = "" ] ; then
API_SERVER_NAME="bwapi"
fi
API_WHITELIST_IP="$(grep "^API_WHITELIST_IP=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$API_WHITELIST_IP" = "" ] ; then
API_WHITELIST_IP="127.0.0.0/8"
fi
USE_REAL_IP="$(grep "^USE_REAL_IP=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$USE_REAL_IP" = "" ] ; then
USE_REAL_IP="no"
fi
USE_PROXY_PROTOCOL="$(grep "^USE_PROXY_PROTOCOL=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$USE_PROXY_PROTOCOL" = "" ] ; then
USE_PROXY_PROTOCOL="no"
fi
REAL_IP_FROM="$(grep "^REAL_IP_FROM=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$REAL_IP_FROM" = "" ] ; then
REAL_IP_FROM="192.168.0.0/16 172.16.0.0/12 10.0.0.0/8"
fi
REAL_IP_HEADER="$(grep "^REAL_IP_HEADER=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$REAL_IP_HEADER" = "" ] ; then
REAL_IP_HEADER="X-Forwarded-For"
fi
HTTP_PORT="$(grep "^HTTP_PORT=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$HTTP_PORT" = "" ] ; then
HTTP_PORT="80"
fi
HTTPS_PORT="$(grep "^HTTPS_PORT=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$HTTPS_PORT" = "" ] ; then
HTTPS_PORT="443"
fi
MODSECURITY_CRS_VERSION="$(grep "^MODSECURITY_CRS_VERSION=" /etc/bunkerweb/variables.env | cut -d '=' -f 2)"
if [ "$MODSECURITY_CRS_VERSION" = "" ] ; then
MODSECURITY_CRS_VERSION="3"
fi
sudo -E -u nginx -g nginx /bin/bash -c "echo -ne 'IS_LOADING=yes\nUSE_BUNKERNET=no\nSEND_ANONYMOUS_REPORT=no\nSERVER_NAME=\nMODSECURITY_CRS_VERSION=${MODSECURITY_CRS_VERSION}\nDNS_RESOLVERS=${DNS_RESOLVERS}\nAPI_HTTP_PORT=${API_HTTP_PORT}\nAPI_LISTEN_IP=${API_LISTEN_IP}\nAPI_SERVER_NAME=${API_SERVER_NAME}\nAPI_WHITELIST_IP=${API_WHITELIST_IP}\nUSE_REAL_IP=${USE_REAL_IP}\nUSE_PROXY_PROTOCOL=${USE_PROXY_PROTOCOL}\nREAL_IP_FROM=${REAL_IP_FROM}\nREAL_IP_HEADER=${REAL_IP_HEADER}\nHTTP_PORT=${HTTP_PORT}\nHTTPS_PORT=${HTTPS_PORT}\n' > /var/tmp/bunkerweb/tmp.env"
sudo -E -u nginx -g nginx /bin/bash -c "PYTHONPATH=/usr/share/bunkerweb/deps/python/ /usr/share/bunkerweb/gen/main.py --variables /var/tmp/bunkerweb/tmp.env --no-linux-reload"
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
log "SYSTEMCTL" "❌" "Error while generating config from /var/tmp/bunkerweb/tmp.env"
exit 1
fi
# Start nginx
log "SYSTEMCTL" "" "Starting nginx ..."
sudo -E -u nginx -g nginx /usr/sbin/nginx -e /var/log/bunkerweb/error.log
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
log "SYSTEMCTL" "❌" "Error while executing temp nginx"
exit 1
fi
count=0
while [ $count -lt 10 ] ; do
check="$(curl -s -H "Host: healthcheck.bunkerweb.io" http://127.0.0.1:6000/healthz 2>&1)"
# shellcheck disable=SC2181
if [ $? -eq 0 ] && [ "$check" = "ok" ] ; then
break
fi
count=$((count + 1))
sleep 1
log "SYSTEMCTL" "" "Waiting for nginx to start ..."
done
if [ $count -ge 10 ] ; then
log "SYSTEMCTL" "❌" "nginx is not started"
exit 1
fi
log "SYSTEMCTL" "" "nginx started ..."
fi
log "SYSTEMCTL" "" "nginx started ..."
# Execute scheduler
log "SYSTEMCTL" " " "Executing scheduler ..."

View file

@ -30,6 +30,7 @@ from common_utils import bytes_hash, dict_to_frozenset, get_integration # type:
from logger import setup_logger # type: ignore
from Database import Database # type: ignore
from JobScheduler import JobScheduler
from API import API
RUN = True
SCHEDULER: Optional[JobScheduler] = None
@ -70,6 +71,9 @@ SCHEDULER_TMP_ENV_PATH.touch()
DB_LOCK_FILE = Path(sep, "var", "lib", "bunkerweb", "db.lock")
logger = setup_logger("Scheduler", getenv("LOG_LEVEL", "INFO"))
SLAVE_MODE = environ.get("SLAVE_MODE", "no") == "yes"
MASTER_MODE = environ.get("MASTER_MODE", "no") == "yes"
def handle_stop(signum, frame):
if SCHEDULER is not None:
@ -198,6 +202,53 @@ def generate_external_plugins(plugins: List[Dict[str, Any]], *, original_path: U
if not ret:
logger.error(f"Sending {'pro ' if pro else ''}external plugins failed, configuration will not work as expected...")
def generate_caches(plugins: List[Any], db: Database):
for plugin in plugins:
job_cache_files = db.get_jobs_cache_files(plugin_id=plugin["id"])
plugin_cache_files = set()
ignored_dirs = set()
job_path = Path(sep, "var", "cache", "bunkerweb", plugin["id"])
for job_cache_file in job_cache_files:
cache_path = job_path.joinpath(job_cache_file["service_id"] or "", job_cache_file["file_name"])
plugin_cache_files.add(cache_path)
try:
if job_cache_file["file_name"].endswith(".tgz"):
extract_path = cache_path.parent
if job_cache_file["file_name"].startswith("folder:"):
extract_path = Path(job_cache_file["file_name"].split("folder:", 1)[1].rsplit(".tgz", 1)[0])
ignored_dirs.add(extract_path.as_posix())
rmtree(extract_path, ignore_errors=True)
extract_path.mkdir(parents=True, exist_ok=True)
with tar_open(fileobj=BytesIO(job_cache_file["data"]), mode="r:gz") as tar:
try:
tar.extractall(extract_path, filter="fully_trusted")
except TypeError:
tar.extractall(extract_path)
else:
cache_path.parent.mkdir(parents=True, exist_ok=True)
cache_path.write_bytes(job_cache_file["data"])
except BaseException as e:
logger.error(f"Exception while restoring cache file {job_cache_file['file_name']} :\n{e}")
if job_path.is_dir():
for file in job_path.rglob("*"):
skipped = False
if file.as_posix().startswith(tuple(ignored_dirs)):
skipped = True
if skipped:
continue
logger.debug(f"Checking if {file} should be removed")
if file not in plugin_cache_files and file.is_file():
logger.debug(f"Removing non-cached file {file}")
file.unlink(missing_ok=True)
if file.parent.is_dir() and not list(file.parent.iterdir()):
logger.debug(f"Removing empty directory {file.parent}")
rmtree(file.parent, ignore_errors=True)
if file.parent == job_path:
break
elif file.is_dir() and not list(file.iterdir()):
logger.debug(f"Removing empty directory {file}")
rmtree(file, ignore_errors=True)
def api_to_instance(api):
hostname_port = api.endpoint.replace("http://", "").replace("https://", "").replace("/", "").split(":")
@ -206,6 +257,62 @@ def api_to_instance(api):
"env": {"API_HTTP_PORT": int(hostname_port[1]), "API_SERVER_NAME": api.host},
}
def run_in_slave_mode(db: Database, dotenv_env: Dict[str, Any]):
# Instantiate db
db = Database(logger, sqlalchemy_string=dotenv_env.get("DATABASE_URI", getenv("DATABASE_URI", None)))
# Wait for init
while not db.is_initialized():
logger.warning("Database is not initialized, retrying in 5s ...")
sleep(5)
# Wait for first config
env = db.get_config()
while not db.is_first_config_saved() or not env:
logger.warning("Database doesn't have any config saved yet, retrying in 5s ...")
sleep(5)
env = db.get_config()
# Download plugins
pro_plugins = db.get_plugins(_type="pro", with_data=True)
generate_external_plugins(pro_plugins, original_path=PRO_PLUGINS_PATH)
external_plugins = db.get_plugins(_type="external", with_data=True)
generate_external_plugins(external_plugins)
# Download custom configs
generate_custom_configs(db.get_custom_configs())
# Download caches
generate_caches(pro_plugins + external_plugins, db)
# Gen config
content = ""
for k, v in env.items():
content += f"{k}={v}\n"
SCHEDULER_TMP_ENV_PATH.write_text(content)
proc = subprocess_run(
[
"python3",
join(sep, "usr", "share", "bunkerweb", "gen", "main.py"),
"--settings",
join(sep, "usr", "share", "bunkerweb", "settings.json"),
"--templates",
join(sep, "usr", "share", "bunkerweb", "confs"),
"--output",
join(sep, "etc", "nginx"),
"--variables",
str(SCHEDULER_TMP_ENV_PATH),
],
stdin=DEVNULL,
stderr=STDOUT,
check=False,
)
if proc.returncode != 0:
logger.error("Config generator failed, configuration will not work as expected...")
# TODO : check nginx status + check DB status
while True:
sleep(5)
if __name__ == "__main__":
try:
@ -232,6 +339,10 @@ if __name__ == "__main__":
db = Database(logger, sqlalchemy_string=dotenv_env.get("DATABASE_URI", getenv("DATABASE_URI", None)))
if SLAVE_MODE:
run_in_slave_mode(db, dotenv_env)
stop(1)
if INTEGRATION in ("Swarm", "Kubernetes", "Autoconf"):
while not db.is_initialized():
logger.warning("Database is not initialized, retrying in 5s ...")
@ -280,8 +391,15 @@ if __name__ == "__main__":
env["DATABASE_URI"] = db.database_uri
# Override instances if needed
override_instances = env.get("OVERRIDE_INSTANCES", "")
apis=[]
if override_instances:
for instance in override_instances.split(" "):
apis.append(API(instance))
# Instantiate scheduler
SCHEDULER = JobScheduler(env | environ, logger, INTEGRATION, db=db)
SCHEDULER = JobScheduler(env | environ, logger, INTEGRATION, db=db, apis=apis)
if INTEGRATION in ("Docker", "Swarm", "Kubernetes", "Autoconf"):
# Automatically setup the scheduler apis
@ -462,7 +580,7 @@ if __name__ == "__main__":
if event["Action"] == "start":
db.checked_changes(value=True)
if INTEGRATION == "Docker":
if INTEGRATION == "Docker" and not override_instances:
Thread(target=listen_for_instances_reload, args=(db,), name="listen_for_instances_reload").start()
while True:
@ -490,19 +608,22 @@ if __name__ == "__main__":
content += f"{k}={v}\n"
SCHEDULER_TMP_ENV_PATH.write_text(content)
# run the generator
args = [
"python3",
join(sep, "usr", "share", "bunkerweb", "gen", "main.py"),
"--settings",
join(sep, "usr", "share", "bunkerweb", "settings.json"),
"--templates",
join(sep, "usr", "share", "bunkerweb", "confs"),
"--output",
join(sep, "etc", "nginx"),
"--variables",
str(SCHEDULER_TMP_ENV_PATH),
]
if MASTER_MODE:
args.append("--no-linux-reload")
proc = subprocess_run(
[
"python3",
join(sep, "usr", "share", "bunkerweb", "gen", "main.py"),
"--settings",
join(sep, "usr", "share", "bunkerweb", "settings.json"),
"--templates",
join(sep, "usr", "share", "bunkerweb", "confs"),
"--output",
join(sep, "etc", "nginx"),
"--variables",
str(SCHEDULER_TMP_ENV_PATH),
],
args,
stdin=DEVNULL,
stderr=STDOUT,
check=False,

View file

@ -194,7 +194,7 @@ bw_version = Path(sep, "usr", "share", "bunkerweb", "VERSION").read_text(encodin
try:
app.config.update(
DEBUG=True,
INSTANCES=Instances(docker_client, kubernetes_client, INTEGRATION),
INSTANCES=Instances(docker_client, kubernetes_client, INTEGRATION, db),
CONFIG=Config(db),
CONFIGFILES=ConfigFiles(),
WTF_CSRF_SSL_STRICT=False,
@ -634,8 +634,10 @@ def home():
if r and r.status_code == 200:
remote_version = basename(r.url).strip().replace("v", "")
instances = app.config["INSTANCES"].get_instances()
config = app.config["CONFIG"].get_config(with_drafts=True)
override_instances = config["OVERRIDE_INSTANCES"]["value"] != ""
instances = app.config["INSTANCES"].get_instances(override_instances=override_instances)
instance_health_count = 0
for instance in instances:
@ -848,7 +850,9 @@ def instances():
)
# Display instances
instances = app.config["INSTANCES"].get_instances()
config = app.config["CONFIG"].get_config()
override_instances = config["OVERRIDE_INSTANCES"]["value"] != ""
instances = app.config["INSTANCES"].get_instances(override_instances=override_instances)
return render_template("instances.html", title="Instances", instances=instances, username=current_user.get_id())
@ -1664,7 +1668,10 @@ def cache():
@app.route("/logs", methods=["GET"])
@login_required
def logs():
return render_template("logs.html", instances=app.config["INSTANCES"].get_instances(), username=current_user.get_id())
config = app.config["CONFIG"].get_config(with_drafts=True)
override_instances = config["OVERRIDE_INSTANCES"]["value"] != ""
instances = app.config["INSTANCES"].get_instances(override_instances=override_instances)
return render_template("logs.html", instances=instances, username=current_user.get_id())
@app.route("/logs/local", methods=["GET"])

View file

@ -8,7 +8,8 @@ from typing import Any, List, Optional, Tuple, Union
from API import API # type: ignore
from ApiCaller import ApiCaller # type: ignore
from dotenv import dotenv_values
from dotenv import dotenv_values # type: ignore
from Database import Database # type: ignore
class Instance:
@ -134,10 +135,11 @@ class Instance:
class Instances:
def __init__(self, docker_client, kubernetes_client, integration: str):
def __init__(self, docker_client, kubernetes_client, integration: str, db):
self.__docker_client = docker_client
self.__kubernetes_client = kubernetes_client
self.__integration = integration
self.__db = db
def __instance_from_id(self, _id) -> Instance:
instances: list[Instance] = self.get_instances()
@ -147,8 +149,34 @@ class Instances:
raise ValueError(f"Can't find instance with _id {_id}")
def get_instances(self) -> list[Instance]:
def get_instances(self, override_instances=None) -> list[Instance]:
instances = []
# Override case : only return instances from DB
if override_instances is None:
config = self.__db.get_config()
override_instances = config["OVERRIDE_INSTANCES"]["value"] != ""
if override_instances:
for instance in self.__db.get_instances():
instances.append(
Instance(
instance["hostname"],
instance["hostname"],
instance["hostname"],
"override",
"up",
None,
ApiCaller(
[
API(
f"http://{instance["hostname"]}:{str(instance["port"])}",
instance.server_name,
)
]
)
)
)
return instances
# Docker instances (containers or services)
if self.__docker_client is not None:
for instance in self.__docker_client.containers.list(all=True, filters={"label": "bunkerweb.INSTANCE"}):