Use UTC for all our internal dates

This commit is contained in:
Théophile Diot 2024-08-19 13:14:29 +01:00
parent b1ce5cde1d
commit a93c332a61
No known key found for this signature in database
GPG key ID: FA995104A0BA376A
15 changed files with 62 additions and 62 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
from contextlib import suppress
from datetime import datetime
from datetime import datetime, timezone
from os import getenv
from time import sleep
from typing import Any, Dict, List, Optional
@ -82,9 +82,9 @@ class Config:
)
def wait_applying(self, startup: bool = False):
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
ready = False
while not ready and (datetime.now() - current_time).seconds < 240:
while not ready and (datetime.now(timezone.utc) - current_time).seconds < 240:
db_metadata = self._db.get_metadata()
if isinstance(db_metadata, str):
if not startup:

View file

@ -264,7 +264,7 @@ class CLI(ApiCaller):
banned_date = ""
remaining = "for eternity"
if ban["date"] != -1:
banned_date = f"the {datetime.fromtimestamp(ban['date']).strftime('%d-%m-%Y at %H:%M:%S')} "
banned_date = f"the {datetime.fromtimestamp(ban['date']).strftime('%Y-%m-%d at %H:%M:%S %Z')} "
if ban["exp"] != -1:
remaining = f"for {format_remaining_time(ban['exp'])} remaining"
cli_str += f"- {ban['ip']} ; banned {banned_date}{remaining} with reason \"{ban.get('reason', 'no reason given')}\"\n"

View file

@ -23,7 +23,7 @@ try:
for backup in backups:
database = backup.name.split("-")[1]
date = datetime.strptime("-".join(backup.stem.split("-")[2:]), "%Y-%m-%d_%H-%M-%S")
message += f"\n| {database:<10} | {date.strftime('%d/%m/%Y %H:%M:%S')} |"
message += f"\n| {database:<10} | {date.strftime('%Y/%m/%d %H:%M:%S %Z')} |"
message += "\n+------------+---------------------+"
else:
message = f"No backup found in {BACKUP_DIR}"

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
from datetime import datetime
from datetime import datetime, timezone
from os.path import join, sep
from pathlib import Path
from sys import exit as sys_exit, path as sys_path
@ -49,7 +49,7 @@ try:
sys_exit(1)
LOGGER.info("Backing up the current database before restoring the backup ...")
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
tmp_backup_dir = Path(sep, "tmp", "bunkerweb", "backups")
tmp_backup_dir.mkdir(parents=True, exist_ok=True)
db = backup_database(current_time, backup_dir=tmp_backup_dir)

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
from datetime import datetime
from datetime import datetime, timezone
from os.path import join, sep
from pathlib import Path
from sys import exit as sys_exit, path as sys_path
@ -39,7 +39,7 @@ try:
LOGGER.info(f"Creating directory {directory} as it does not exist")
directory.mkdir(parents=True, exist_ok=True)
backup_database(datetime.now(), backup_dir=directory)
backup_database(datetime.now(timezone.utc), backup_dir=directory)
except SystemExit as se:
status = se.code
except:

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from json import dumps, loads
from os import getenv, sep
from os.path import join
@ -35,7 +35,7 @@ try:
if last_backup_date:
last_backup_date = datetime.fromisoformat(last_backup_date)
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
backup_period = getenv("BACKUP_SCHEDULE", "daily")
PERIOD_STAMPS = {
"daily": timedelta(days=1).total_seconds(),

View file

@ -12,7 +12,7 @@ def pre_render(app, *args, **kwargs):
data = loads(backup_file or "{}")
if data.get("date", None):
data["date"] = datetime.fromisoformat(data["date"]).strftime("%Y-%m-%d %H:%M:%S")
data["date"] = datetime.fromisoformat(data["date"]).strftime("%Y-%m-%d %H:%M:%S %Z")
return data
except BaseException:

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from datetime import datetime
from datetime import datetime, timezone
from json import dumps, loads
from os import environ, getenv
from os.path import join, sep
@ -30,7 +30,7 @@ DB_LOCK_FILE = Path(sep, "var", "lib", "bunkerweb", "db.lock")
def acquire_db_lock():
"""Acquire the database lock to prevent concurrent access to the database."""
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
while DB_LOCK_FILE.is_file() and DB_LOCK_FILE.stat().st_ctime + 30 > current_time.timestamp():
LOGGER.warning("Database is locked, waiting for it to be unlocked (timeout: 30s) ...")
sleep(1)
@ -46,9 +46,9 @@ def backup_database(current_time: datetime, db: Database = None, backup_dir: Pat
backup_file = backup_dir.joinpath(f"backup-{database}-{current_time.strftime('%Y-%m-%d_%H-%M-%S')}.zip")
LOGGER.debug(f"Backup file path: {backup_file}")
stderr = "Table 'db.test_"
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
while "Table 'db.test_" in stderr and (datetime.now() - current_time).total_seconds() < 10:
while "Table 'db.test_" in stderr and (datetime.now(timezone.utc) - current_time).total_seconds() < 10:
if database == "sqlite":
match = DB_STRING_RX.search(db.database_uri)
if not match:
@ -94,7 +94,7 @@ def backup_database(current_time: datetime, db: Database = None, backup_dir: Pat
LOGGER.error(f"Failed to dump the database: {stderr}")
sys_exit(1)
if (datetime.now() - current_time).total_seconds() >= 10:
if (datetime.now(timezone.utc) - current_time).total_seconds() >= 10:
LOGGER.error("Failed to dump the database: Timeout reached")
sys_exit(1)

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from datetime import date, datetime, timedelta
from datetime import date, datetime, timedelta, timezone
from gzip import decompress
from io import BytesIO
from os import getenv, sep
@ -62,7 +62,7 @@ try:
if response and response.status_code == 200:
skip_dl = response.content.find(bytes_hash(job_cache["data"], algorithm="sha1").encode()) != -1
elif job_cache["last_update"] < (datetime.now() - timedelta(weeks=1)).timestamp():
elif job_cache["last_update"] < (datetime.now(timezone.utc) - timedelta(weeks=1)).timestamp():
LOGGER.warning("Unable to check if the cache file is the latest version from db-ip.com and file is older than 1 week, checking anyway...")
skip_dl = False

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from datetime import date, datetime, timedelta
from datetime import date, datetime, timedelta, timezone
from gzip import decompress
from io import BytesIO
from os import getenv, sep
@ -62,7 +62,7 @@ try:
if response and response.status_code == 200:
skip_dl = response.content.find(bytes_hash(job_cache["data"], algorithm="sha1").encode()) != -1
elif job_cache["last_update"] < (datetime.now() - timedelta(weeks=1)).timestamp():
elif job_cache["last_update"] < (datetime.now(timezone.utc) - timedelta(weeks=1)).timestamp():
LOGGER.warning("Unable to check if the cache file is the latest version from db-ip.com and file is older than 1 week, checking anyway...")
skip_dl = False

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from datetime import datetime
from datetime import datetime, timezone
from io import BytesIO
from itertools import chain
from os import getenv, sep
@ -95,7 +95,7 @@ def install_plugin(plugin_path: Path, db, preview: bool = True) -> bool:
try:
db = Database(LOGGER, sqlalchemy_string=getenv("DATABASE_URI"))
db_metadata = db.get_metadata()
current_date = datetime.now()
current_date = datetime.now(timezone.utc)
pro_license_key = getenv("PRO_LICENSE_KEY", "").strip()
LOGGER.info("Checking BunkerWeb Pro status...")

View file

@ -2,7 +2,7 @@
from contextlib import contextmanager, suppress
from copy import deepcopy
from datetime import datetime
from datetime import datetime, timezone
from io import BytesIO
from json import JSONDecodeError, loads
from logging import Logger
@ -168,7 +168,7 @@ class Database:
DATABASE_RETRY_TIMEOUT = int(DATABASE_RETRY_TIMEOUT)
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
not_connected = True
fallback = False
@ -185,7 +185,7 @@ class Database:
not_connected = False
except (OperationalError, DatabaseError) as e:
if (datetime.now() - current_time).total_seconds() > DATABASE_RETRY_TIMEOUT:
if (datetime.now(timezone.utc) - current_time).total_seconds() > DATABASE_RETRY_TIMEOUT:
if not fallback and self.database_uri_readonly:
self.logger.error(f"Can't connect to database after {DATABASE_RETRY_TIMEOUT} seconds. Falling back to read-only database connection")
self.sql_engine.dispose(close=True)
@ -241,7 +241,7 @@ class Database:
def retry_connection(self, *, readonly: bool = False, fallback: bool = False, log: bool = True, **kwargs) -> None:
"""Retry the connection to the database"""
self.last_connection_retry = datetime.now()
self.last_connection_retry = datetime.now(timezone.utc)
if log:
self.logger.debug(f"Retrying the connection to the database{' in read-only mode' if readonly else ''}{' with fallback' if fallback else ''} ...")
@ -476,7 +476,7 @@ class Database:
if not metadata:
return "The metadata are not set yet, try again"
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
if "config" in changes:
if not metadata.first_config_saved:
@ -536,7 +536,7 @@ class Database:
db_ui_version = db_version
self.logger.warning(f"Database version ({db_version}) is different from Bunkerweb version ({bunkerweb_version}), migrating ...")
current_time = datetime.now()
current_time = datetime.now(timezone.utc)
error = True
# ? Wait for the metadata to be available
while error:
@ -545,7 +545,7 @@ class Database:
metadata.reflect(self.sql_engine)
error = False
except BaseException as e:
if (datetime.now() - current_time).total_seconds() > 10:
if (datetime.now(timezone.utc) - current_time).total_seconds() > 10:
raise e
sleep(1)
@ -1328,7 +1328,7 @@ class Database:
session.query(Custom_configs).filter(Custom_configs.service_id.in_(missing_ids)).delete()
session.query(Jobs_cache).filter(Jobs_cache.service_id.in_(missing_ids)).delete()
session.query(Metadata).filter_by(id=1).update(
{Metadata.custom_configs_changed: True, Metadata.last_custom_configs_change: datetime.now()}
{Metadata.custom_configs_changed: True, Metadata.last_custom_configs_change: datetime.now(timezone.utc)}
)
changed_services = True
@ -1672,7 +1672,7 @@ class Database:
metadata = session.query(Metadata).get(1)
if metadata is not None:
metadata.custom_configs_changed = True
metadata.last_custom_configs_change = datetime.now()
metadata.last_custom_configs_change = datetime.now(timezone.utc)
try:
session.add_all(to_put)
@ -1994,7 +1994,7 @@ class Database:
if self.readonly:
return "The database is read-only, the changes will not be saved"
session.add(Jobs_runs(job_name=job_name, success=success, start_date=start_date, end_date=end_date or datetime.now()))
session.add(Jobs_runs(job_name=job_name, success=success, start_date=start_date, end_date=end_date or datetime.now(timezone.utc)))
try:
session.commit()
@ -2062,13 +2062,13 @@ class Database:
service_id=service_id,
file_name=file_name,
data=data,
last_update=datetime.now(),
last_update=datetime.now(timezone.utc),
checksum=checksum,
)
)
else:
cache.data = data
cache.last_update = datetime.now()
cache.last_update = datetime.now(timezone.utc)
cache.checksum = checksum
try:
@ -2856,10 +2856,10 @@ class Database:
if metadata is not None:
if _type == "external":
metadata.external_plugins_changed = True
metadata.last_external_plugins_change = datetime.now()
metadata.last_external_plugins_change = datetime.now(timezone.utc)
elif _type == "pro":
metadata.pro_plugins_changed = True
metadata.last_pro_plugins_change = datetime.now()
metadata.last_pro_plugins_change = datetime.now(timezone.utc)
try:
session.add_all(to_put)
@ -2966,8 +2966,8 @@ class Database:
"reload": job.reload,
"history": [
{
"start_date": job_run.start_date.strftime("%d/%m/%Y, %I:%M:%S %p"),
"end_date": job_run.end_date.strftime("%d/%m/%Y, %I:%M:%S %p"),
"start_date": job_run.start_date.strftime("%Y/%m/%d, %H:%M:%S %Z"),
"end_date": job_run.end_date.strftime("%Y/%m/%d, %H:%M:%S %Z"),
"success": job_run.success,
}
for job_run in session.query(Jobs_runs)
@ -2980,7 +2980,7 @@ class Database:
{
"service_id": cache.service_id,
"file_name": cache.file_name,
"last_update": cache.last_update.strftime("%d/%m/%Y, %I:%M:%S %p") if cache.last_update else "Never",
"last_update": cache.last_update.strftime("%Y/%m/%d, %H:%M:%S %Z") if cache.last_update else "Never",
"checksum": cache.checksum,
}
for cache in session.query(Jobs_cache)
@ -3088,7 +3088,7 @@ class Database:
metadata = session.query(Metadata).get(1)
if metadata is not None:
metadata.instances_changed = True
metadata.last_instances_change = datetime.now()
metadata.last_instances_change = datetime.now(timezone.utc)
try:
session.commit()
@ -3115,7 +3115,7 @@ class Database:
metadata = session.query(Metadata).get(1)
if metadata is not None:
metadata.instances_changed = True
metadata.last_instances_change = datetime.now()
metadata.last_instances_change = datetime.now(timezone.utc)
try:
session.commit()
@ -3154,7 +3154,7 @@ class Database:
metadata = session.query(Metadata).get(1)
if metadata is not None:
metadata.instances_changed = True
metadata.last_instances_change = datetime.now()
metadata.last_instances_change = datetime.now(timezone.utc)
try:
session.add_all(to_put)
@ -3176,7 +3176,7 @@ class Database:
return f"Instance {hostname} does not exist, will not be updated."
db_instance.status = status
db_instance.last_seen = datetime.now()
db_instance.last_seen = datetime.now(timezone.utc)
try:
session.commit()

View file

@ -52,7 +52,7 @@ class Plugins(Base):
data = Column(LargeBinary(length=(2**32) - 1), nullable=True)
checksum = Column(String(128), nullable=True)
config_changed = Column(Boolean, default=False, nullable=True)
last_config_change = Column(DateTime, nullable=True)
last_config_change = Column(DateTime(timezone=True), nullable=True)
settings = relationship("Settings", back_populates="plugin", cascade="all, delete-orphan")
jobs = relationship("Jobs", back_populates="plugin", cascade="all, delete-orphan")
@ -161,7 +161,7 @@ class Jobs_cache(Base):
service_id = Column(String(64), ForeignKey("bw_services.id", onupdate="cascade", ondelete="cascade"), nullable=True)
file_name = Column(String(256), nullable=False)
data = Column(LargeBinary(length=(2**32) - 1), nullable=True)
last_update = Column(DateTime, nullable=True)
last_update = Column(DateTime(timezone=True), nullable=True)
checksum = Column(String(128), nullable=True)
job = relationship("Jobs", back_populates="cache")
@ -174,8 +174,8 @@ class Jobs_runs(Base):
id = Column(Integer, Identity(start=1, increment=1), primary_key=True)
job_name = Column(String(128), ForeignKey("bw_jobs.name", onupdate="cascade", ondelete="cascade"), nullable=False)
success = Column(Boolean, nullable=True, default=False)
start_date = Column(DateTime(), nullable=False)
end_date = Column(DateTime(), nullable=True, server_default=func.now())
start_date = Column(DateTime(timezone=True), nullable=False)
end_date = Column(DateTime(timezone=True), nullable=True, server_default=func.now())
job = relationship("Jobs", back_populates="runs")
@ -205,8 +205,8 @@ class Instances(Base):
type = Column(INSTANCE_TYPE_ENUM, nullable=False, default="static")
status = Column(INSTANCE_STATUS_ENUM, nullable=False, default="loading")
method = Column(METHODS_ENUM, nullable=False, default="manual")
creation_date = Column(DateTime, nullable=False, server_default=func.now())
last_seen = Column(DateTime, nullable=True, server_default=func.now())
creation_date = Column(DateTime(timezone=True), nullable=False, server_default=func.now())
last_seen = Column(DateTime(timezone=True), nullable=True, server_default=func.now())
class Bw_cli_commands(Base):
@ -282,22 +282,22 @@ class Metadata(Base):
is_initialized = Column(Boolean, nullable=False)
is_pro = Column(Boolean, default=False, nullable=False)
pro_license = Column(String(128), default="", nullable=True)
pro_expire = Column(DateTime, nullable=True)
pro_expire = Column(DateTime(timezone=True), nullable=True)
pro_status = Column(PRO_STATUS_ENUM, default="invalid", nullable=False)
pro_services = Column(Integer, default=0, nullable=False)
pro_overlapped = Column(Boolean, default=False, nullable=False)
last_pro_check = Column(DateTime, nullable=True)
last_pro_check = Column(DateTime(timezone=True), nullable=True)
first_config_saved = Column(Boolean, nullable=False)
autoconf_loaded = Column(Boolean, default=False, nullable=True)
scheduler_first_start = Column(Boolean, nullable=True)
custom_configs_changed = Column(Boolean, default=False, nullable=True)
last_custom_configs_change = Column(DateTime, nullable=True)
last_custom_configs_change = Column(DateTime(timezone=True), nullable=True)
external_plugins_changed = Column(Boolean, default=False, nullable=True)
last_external_plugins_change = Column(DateTime, nullable=True)
last_external_plugins_change = Column(DateTime(timezone=True), nullable=True)
pro_plugins_changed = Column(Boolean, default=False, nullable=True)
last_pro_plugins_change = Column(DateTime, nullable=True)
last_pro_plugins_change = Column(DateTime(timezone=True), nullable=True)
instances_changed = Column(Boolean, default=False, nullable=True)
last_instances_change = Column(DateTime, nullable=True)
last_instances_change = Column(DateTime(timezone=True), nullable=True)
failover = Column(Boolean, default=None, nullable=True)
integration = Column(INTEGRATIONS_ENUM, default="Unknown", nullable=False)
version = Column(String(32), default="1.6.0-beta", nullable=False)

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from io import BytesIO
from logging import Logger
from os import getenv
@ -144,7 +144,7 @@ class Job:
try:
cache_info = self.get_cache(name, job_name=job_name, service_id=service_id, plugin_id=plugin_id, with_info=True, with_data=False)
if isinstance(cache_info, dict):
current_time = datetime.now().timestamp()
current_time = datetime.now(timezone.utc).timestamp()
if current_time < cache_info["last_update"]:
return False
is_cached = current_time - cache_info["last_update"] < EXPIRE_TIME[expire]

View file

@ -2,7 +2,7 @@
from contextlib import suppress
from copy import deepcopy
from datetime import datetime
from datetime import datetime, timezone
from functools import partial
from glob import glob
from json import loads
@ -162,7 +162,7 @@ class JobScheduler(ApiCaller):
self.__logger.info(f"Executing job {name} from plugin {plugin} ...")
success = True
ret = -1
start_date = datetime.now()
start_date = datetime.now(timezone.utc)
try:
proc = run(join(path, "jobs", file), stdin=DEVNULL, stderr=STDOUT, env=self.__env, check=False)
ret = proc.returncode
@ -171,7 +171,7 @@ class JobScheduler(ApiCaller):
self.__logger.error(f"Exception while executing job {name} from plugin {plugin} :\n{format_exc()}")
with self.__thread_lock:
self.__job_success = False
end_date = datetime.now()
end_date = datetime.now(timezone.utc)
if ret == 1:
with self.__thread_lock:
@ -351,7 +351,7 @@ class JobScheduler(ApiCaller):
except BaseException:
self.db.readonly = True
return True
elif not force and self.db.last_connection_retry and (datetime.now() - self.db.last_connection_retry).total_seconds() > 30:
elif not force and self.db.last_connection_retry and (datetime.now(timezone.utc) - self.db.last_connection_retry).total_seconds() > 30:
return True
if self.db.database_uri and self.db.readonly: