mirror of
https://github.com/bunkerity/bunkerized-nginx
synced 2023-12-13 21:30:18 +01:00
Adapt everything so that the UI can work with every integration (some more tests are needed)
This commit is contained in:
parent
66fb266f8e
commit
5f8353c114
11 changed files with 816 additions and 185 deletions
267
db/Database.py
267
db/Database.py
|
@ -86,7 +86,9 @@ class Database:
|
||||||
break
|
break
|
||||||
|
|
||||||
if not sqlalchemy_string:
|
if not sqlalchemy_string:
|
||||||
sqlalchemy_string = getenv("DATABASE_URI", "sqlite:////data/db.sqlite3")
|
sqlalchemy_string = getenv(
|
||||||
|
"DATABASE_URI", "sqlite:////opt/bunkerweb/cache/db.sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
if sqlalchemy_string.startswith("sqlite"):
|
if sqlalchemy_string.startswith("sqlite"):
|
||||||
if not path.exists(sqlalchemy_string.split("///")[1]):
|
if not path.exists(sqlalchemy_string.split("///")[1]):
|
||||||
|
@ -290,24 +292,26 @@ class Database:
|
||||||
with self.__db_session() as session:
|
with self.__db_session() as session:
|
||||||
# Delete all the old config
|
# Delete all the old config
|
||||||
session.execute(
|
session.execute(
|
||||||
Services.__table__.delete().where(Services.method == method)
|
Global_values.__table__.delete().where(Global_values.method == method)
|
||||||
|
)
|
||||||
|
session.execute(
|
||||||
|
Services_settings.__table__.delete().where(
|
||||||
|
Services_settings.method == method
|
||||||
|
)
|
||||||
)
|
)
|
||||||
session.execute(Global_values.__table__.delete())
|
|
||||||
|
|
||||||
if config:
|
if config:
|
||||||
if config["MULTISITE"] == "yes":
|
if config["MULTISITE"] == "yes":
|
||||||
global_values = []
|
global_values = []
|
||||||
for server_name in config["SERVER_NAME"].split(" "):
|
for server_name in config["SERVER_NAME"].split(" "):
|
||||||
if (
|
if (
|
||||||
session.query(Services)
|
server_name
|
||||||
.with_entities(Services.id)
|
and session.query(Services)
|
||||||
.filter_by(id=server_name)
|
.filter_by(id=server_name)
|
||||||
.first()
|
.first()
|
||||||
|
is None
|
||||||
):
|
):
|
||||||
continue
|
to_put.append(Services(id=server_name))
|
||||||
|
|
||||||
if server_name:
|
|
||||||
to_put.append(Services(id=server_name, method=method))
|
|
||||||
|
|
||||||
for key, value in deepcopy(config).items():
|
for key, value in deepcopy(config).items():
|
||||||
suffix = None
|
suffix = None
|
||||||
|
@ -315,35 +319,73 @@ class Database:
|
||||||
suffix = int(key.split("_")[-1])
|
suffix = int(key.split("_")[-1])
|
||||||
key = key[: -len(str(suffix)) - 1]
|
key = key[: -len(str(suffix)) - 1]
|
||||||
|
|
||||||
|
setting = (
|
||||||
|
session.query(Settings)
|
||||||
|
.with_entities(Settings.default)
|
||||||
|
.filter_by(id=key.replace(f"{server_name}_", ""))
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
if server_name and key.startswith(server_name):
|
if server_name and key.startswith(server_name):
|
||||||
key = key.replace(f"{server_name}_", "")
|
key = key.replace(f"{server_name}_", "")
|
||||||
|
service_setting = (
|
||||||
to_put.append(
|
session.query(Services_settings)
|
||||||
Services_settings(
|
.filter_by(
|
||||||
service_id=server_name,
|
service_id=server_name,
|
||||||
setting_id=key,
|
setting_id=key,
|
||||||
value=value,
|
|
||||||
suffix=suffix,
|
suffix=suffix,
|
||||||
)
|
)
|
||||||
)
|
|
||||||
elif key not in global_values:
|
|
||||||
setting = (
|
|
||||||
session.query(Settings)
|
|
||||||
.with_entities(Settings.default)
|
|
||||||
.filter_by(id=key)
|
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
if setting and value != setting.default:
|
if not setting or (
|
||||||
global_values.append(key)
|
value == setting.default and service_setting is None
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if service_setting is None:
|
||||||
to_put.append(
|
to_put.append(
|
||||||
Global_values(
|
Services_settings(
|
||||||
setting_id=key, value=value, suffix=suffix
|
service_id=server_name,
|
||||||
|
setting_id=key,
|
||||||
|
value=value,
|
||||||
|
suffix=suffix,
|
||||||
|
method=method,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
elif method == "autoconf":
|
||||||
|
service_setting.value = value
|
||||||
|
service_setting.method = method
|
||||||
|
to_put.append(service_setting)
|
||||||
|
elif key not in global_values:
|
||||||
|
global_values.append(key)
|
||||||
|
global_value = (
|
||||||
|
session.query(Global_values)
|
||||||
|
.filter_by(setting_id=key, suffix=suffix)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
if not setting or (
|
||||||
|
value == setting.default and global_value is None
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if global_value is None:
|
||||||
|
to_put.append(
|
||||||
|
Global_values(
|
||||||
|
setting_id=key,
|
||||||
|
value=value,
|
||||||
|
suffix=suffix,
|
||||||
|
method=method,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif method == "autoconf":
|
||||||
|
global_value.value = value
|
||||||
|
global_value.method = method
|
||||||
|
to_put.append(global_value)
|
||||||
else:
|
else:
|
||||||
primary_server_name = config["SERVER_NAME"].split(" ")[0]
|
primary_server_name = config["SERVER_NAME"].split(" ")[0]
|
||||||
to_put.append(Services(id=primary_server_name, method=method))
|
to_put.append(Services(id=primary_server_name))
|
||||||
|
|
||||||
for key, value in config.items():
|
for key, value in config.items():
|
||||||
suffix = None
|
suffix = None
|
||||||
|
@ -351,12 +393,22 @@ class Database:
|
||||||
suffix = int(key.split("_")[-1])
|
suffix = int(key.split("_")[-1])
|
||||||
key = key[: -len(str(suffix)) - 1]
|
key = key[: -len(str(suffix)) - 1]
|
||||||
|
|
||||||
|
setting = (
|
||||||
|
session.query(Settings)
|
||||||
|
.with_entities(Settings.default)
|
||||||
|
.filter_by(id=key)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
if setting and value == setting.default:
|
||||||
|
continue
|
||||||
|
|
||||||
to_put.append(
|
to_put.append(
|
||||||
Services_settings(
|
Global_values(
|
||||||
service_id=primary_server_name,
|
|
||||||
setting_id=key,
|
setting_id=key,
|
||||||
value=value,
|
value=value,
|
||||||
suffix=suffix,
|
suffix=suffix,
|
||||||
|
method=method,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -420,8 +472,20 @@ class Database:
|
||||||
"name": custom_config["exploded"][2],
|
"name": custom_config["exploded"][2],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
to_put.append(Custom_configs(**config))
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
method == "autoconf"
|
||||||
|
or session.query(Custom_configs)
|
||||||
|
.with_entities(Custom_configs.id)
|
||||||
|
.filter_by(
|
||||||
|
service_id=config.get("service_id", None),
|
||||||
|
type=config["type"],
|
||||||
|
name=config["name"],
|
||||||
|
)
|
||||||
|
.first()
|
||||||
|
is None
|
||||||
|
):
|
||||||
|
to_put.append(Custom_configs(**config))
|
||||||
try:
|
try:
|
||||||
session.add_all(to_put)
|
session.add_all(to_put)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
@ -430,60 +494,76 @@ class Database:
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_config(self) -> Dict[str, Any]:
|
def get_config(self, methods: bool = False) -> Dict[str, Any]:
|
||||||
"""Get the config from the database"""
|
"""Get the config from the database"""
|
||||||
with self.__db_session() as session:
|
with self.__db_session() as session:
|
||||||
config = {}
|
config = {}
|
||||||
settings = (
|
|
||||||
session.query(Settings)
|
|
||||||
.with_entities(
|
|
||||||
Settings.id, Settings.context, Settings.default, Settings.multiple
|
|
||||||
)
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
|
|
||||||
for setting in settings:
|
|
||||||
suffix = 0
|
|
||||||
while True:
|
|
||||||
global_value = (
|
|
||||||
session.query(Global_values)
|
|
||||||
.with_entities(Global_values.value)
|
|
||||||
.filter_by(setting_id=setting.id, suffix=suffix)
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
if global_value is None:
|
|
||||||
if suffix > 0:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
config[setting.id] = setting.default
|
|
||||||
else:
|
|
||||||
config[
|
|
||||||
setting.id + (f"_{suffix}" if suffix > 0 else "")
|
|
||||||
] = global_value.value
|
|
||||||
|
|
||||||
if not setting.multiple:
|
|
||||||
break
|
|
||||||
|
|
||||||
suffix += 1
|
|
||||||
|
|
||||||
for service in session.query(Services).with_entities(Services.id).all():
|
for service in session.query(Services).with_entities(Services.id).all():
|
||||||
for setting in settings:
|
for setting in (
|
||||||
if setting.context != "multisite":
|
session.query(Settings)
|
||||||
continue
|
.with_entities(
|
||||||
|
Settings.id,
|
||||||
|
Settings.context,
|
||||||
|
Settings.default,
|
||||||
|
Settings.multiple,
|
||||||
|
)
|
||||||
|
.all()
|
||||||
|
):
|
||||||
suffix = 0
|
suffix = 0
|
||||||
while True:
|
while True:
|
||||||
|
global_value = (
|
||||||
|
session.query(Global_values)
|
||||||
|
.with_entities(Global_values.value, Global_values.method)
|
||||||
|
.filter_by(setting_id=setting.id, suffix=suffix)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
if global_value is None:
|
||||||
|
if suffix == 0:
|
||||||
|
config[setting.id] = (
|
||||||
|
setting.default
|
||||||
|
if methods is False
|
||||||
|
else {"value": setting.default, "method": "default"}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
config[
|
||||||
|
setting.id + (f"_{suffix}" if suffix > 0 else "")
|
||||||
|
] = (
|
||||||
|
global_value.value
|
||||||
|
if methods is False
|
||||||
|
else {
|
||||||
|
"value": global_value.value,
|
||||||
|
"method": global_value.method,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if setting.context != "multisite":
|
||||||
|
break
|
||||||
|
|
||||||
if suffix == 0:
|
if suffix == 0:
|
||||||
config[f"{service.id}_{setting.id}"] = config[setting.id]
|
config[f"{service.id}_{setting.id}"] = (
|
||||||
|
config[setting.id]
|
||||||
|
if methods is False
|
||||||
|
else {
|
||||||
|
"value": config[setting.id]["value"],
|
||||||
|
"method": "default",
|
||||||
|
}
|
||||||
|
)
|
||||||
elif f"{setting.id}_{suffix}" in config:
|
elif f"{setting.id}_{suffix}" in config:
|
||||||
config[f"{service.id}_{setting.id}_{suffix}"] = config[
|
config[f"{service.id}_{setting.id}_{suffix}"] = (
|
||||||
f"{setting.id}_{suffix}"
|
config[f"{setting.id}_{suffix}"]
|
||||||
]
|
if methods is False
|
||||||
|
else {
|
||||||
|
"value": config[f"{setting.id}_{suffix}"]["value"],
|
||||||
|
"method": "default",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
service_setting = (
|
service_setting = (
|
||||||
session.query(Services_settings)
|
session.query(Services_settings)
|
||||||
.with_entities(Services_settings.value)
|
.with_entities(
|
||||||
|
Services_settings.value, Services_settings.method
|
||||||
|
)
|
||||||
.filter_by(
|
.filter_by(
|
||||||
service_id=service.id,
|
service_id=service.id,
|
||||||
setting_id=setting.id,
|
setting_id=setting.id,
|
||||||
|
@ -496,10 +576,20 @@ class Database:
|
||||||
config[
|
config[
|
||||||
f"{service.id}_{setting.id}"
|
f"{service.id}_{setting.id}"
|
||||||
+ (f"_{suffix}" if suffix > 0 else "")
|
+ (f"_{suffix}" if suffix > 0 else "")
|
||||||
] = service_setting.value
|
] = (
|
||||||
|
service_setting.value
|
||||||
|
if methods is False
|
||||||
|
else {
|
||||||
|
"value": service_setting.value,
|
||||||
|
"method": service_setting.method,
|
||||||
|
}
|
||||||
|
)
|
||||||
elif suffix > 0:
|
elif suffix > 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if not setting.multiple:
|
||||||
|
break
|
||||||
|
|
||||||
suffix += 1
|
suffix += 1
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
@ -512,28 +602,35 @@ class Database:
|
||||||
"service_id": custom_config.service_id,
|
"service_id": custom_config.service_id,
|
||||||
"type": custom_config.type,
|
"type": custom_config.type,
|
||||||
"name": custom_config.name,
|
"name": custom_config.name,
|
||||||
"data": custom_config.data.decode("utf-8"),
|
"data": custom_config.data,
|
||||||
"method": custom_config.method,
|
"method": custom_config.method,
|
||||||
}
|
}
|
||||||
for custom_config in session.query(Custom_configs)
|
for custom_config in (
|
||||||
.with_entities(
|
session.query(Custom_configs)
|
||||||
Custom_configs.service_id,
|
.with_entities(
|
||||||
Custom_configs.type,
|
Custom_configs.service_id,
|
||||||
Custom_configs.name,
|
Custom_configs.type,
|
||||||
Custom_configs.data,
|
Custom_configs.name,
|
||||||
Custom_configs.method,
|
Custom_configs.data,
|
||||||
|
Custom_configs.method,
|
||||||
|
)
|
||||||
|
.all()
|
||||||
)
|
)
|
||||||
.all()
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_services(self) -> List[Dict[str, Any]]:
|
def get_services_settings(self, methods: bool = False) -> List[Dict[str, Any]]:
|
||||||
"""Get the services' configs from the database"""
|
"""Get the services' configs from the database"""
|
||||||
services = []
|
services = []
|
||||||
|
config = self.get_config(methods=methods)
|
||||||
with self.__db_session() as session:
|
with self.__db_session() as session:
|
||||||
for service in (
|
for service in session.query(Services).with_entities(Services.id).all():
|
||||||
session.query(Services).with_entities(Services.settings).all()
|
tmp_config = deepcopy(config)
|
||||||
):
|
|
||||||
services.append(service.settings)
|
for key, value in tmp_config.items():
|
||||||
|
if key.startswith(f"{service.id}_"):
|
||||||
|
tmp_config[key.replace(f"{service.id}_", "")] = value
|
||||||
|
|
||||||
|
services.append(tmp_config)
|
||||||
|
|
||||||
return services
|
return services
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ class Global_values(Base):
|
||||||
)
|
)
|
||||||
value = Column(String(1023), nullable=False)
|
value = Column(String(1023), nullable=False)
|
||||||
suffix = Column(SmallInteger, primary_key=True, nullable=True, default=0)
|
suffix = Column(SmallInteger, primary_key=True, nullable=True, default=0)
|
||||||
|
method = Column(METHODS_ENUM, nullable=False)
|
||||||
|
|
||||||
setting = relationship("Settings", back_populates="global_value")
|
setting = relationship("Settings", back_populates="global_value")
|
||||||
|
|
||||||
|
@ -104,7 +105,6 @@ class Services(Base):
|
||||||
__tablename__ = "services"
|
__tablename__ = "services"
|
||||||
|
|
||||||
id = Column(String(64), primary_key=True)
|
id = Column(String(64), primary_key=True)
|
||||||
method = Column(METHODS_ENUM, nullable=False)
|
|
||||||
|
|
||||||
settings = relationship(
|
settings = relationship(
|
||||||
"Services_settings", back_populates="service", cascade="all, delete"
|
"Services_settings", back_populates="service", cascade="all, delete"
|
||||||
|
@ -132,6 +132,7 @@ class Services_settings(Base):
|
||||||
)
|
)
|
||||||
value = Column(String(1023), nullable=False)
|
value = Column(String(1023), nullable=False)
|
||||||
suffix = Column(SmallInteger, primary_key=True, nullable=True, default=0)
|
suffix = Column(SmallInteger, primary_key=True, nullable=True, default=0)
|
||||||
|
method = Column(METHODS_ENUM, nullable=False)
|
||||||
|
|
||||||
service = relationship("Services", back_populates="settings")
|
service = relationship("Services", back_populates="settings")
|
||||||
setting = relationship("Settings", back_populates="services")
|
setting = relationship("Settings", back_populates="services")
|
||||||
|
|
|
@ -160,7 +160,7 @@ if __name__ == "__main__":
|
||||||
tmp_path += f"/{custom_config['service_id']}"
|
tmp_path += f"/{custom_config['service_id']}"
|
||||||
tmp_path += f"/{custom_config['name']}.conf"
|
tmp_path += f"/{custom_config['name']}.conf"
|
||||||
makedirs(dirname(tmp_path), exist_ok=True)
|
makedirs(dirname(tmp_path), exist_ok=True)
|
||||||
with open(tmp_path, "w") as f:
|
with open(tmp_path, "wb") as f:
|
||||||
f.write(custom_config["data"])
|
f.write(custom_config["data"])
|
||||||
|
|
||||||
if bw_integration != "Local":
|
if bw_integration != "Local":
|
||||||
|
@ -277,7 +277,7 @@ if __name__ == "__main__":
|
||||||
tmp_path += f"/{custom_config['service_id']}"
|
tmp_path += f"/{custom_config['service_id']}"
|
||||||
tmp_path += f"/{custom_config['name']}.conf"
|
tmp_path += f"/{custom_config['name']}.conf"
|
||||||
makedirs(dirname(tmp_path), exist_ok=True)
|
makedirs(dirname(tmp_path), exist_ok=True)
|
||||||
with open(tmp_path, "w") as f:
|
with open(tmp_path, "wb") as f:
|
||||||
f.write(custom_config["data"])
|
f.write(custom_config["data"])
|
||||||
|
|
||||||
if bw_integration != "Local":
|
if bw_integration != "Local":
|
||||||
|
|
|
@ -1,32 +1,26 @@
|
||||||
FROM python:3.11-rc-alpine AS builder
|
|
||||||
|
|
||||||
# Copy python requirements
|
|
||||||
COPY bw/deps/requirements.txt /opt/bunkerweb/deps/requirements.txt
|
|
||||||
|
|
||||||
# Install python requirements
|
|
||||||
RUN apk add --no-cache --virtual build g++ gcc python3-dev musl-dev libffi-dev openssl-dev cargo && \
|
|
||||||
mkdir /opt/bunkerweb/deps/python && \
|
|
||||||
pip install --no-cache-dir --require-hashes --target /opt/bunkerweb/deps/python -r /opt/bunkerweb/deps/requirements.txt && \
|
|
||||||
apk del build
|
|
||||||
|
|
||||||
FROM python:3.11-rc-alpine
|
FROM python:3.11-rc-alpine
|
||||||
|
|
||||||
COPY --from=builder /opt/bunkerweb/deps/python /opt/bunkerweb/deps/python
|
|
||||||
|
|
||||||
# Copy files
|
# Copy files
|
||||||
# can't exclude specific files/dir from . so we are copying everything by hand
|
# can't exclude specific files/dir from . so we are copying everything by hand
|
||||||
COPY bw/api /opt/bunkerweb/api
|
COPY bw/api /opt/bunkerweb/api
|
||||||
COPY bw/confs /opt/bunkerweb/confs
|
COPY bw/confs /opt/bunkerweb/confs
|
||||||
COPY bw/core /opt/bunkerweb/core
|
COPY bw/core /opt/bunkerweb/core
|
||||||
COPY bw/gen /opt/bunkerweb/gen
|
COPY bw/gen /opt/bunkerweb/gen
|
||||||
COPY utils /opt/bunkerweb/utils
|
|
||||||
COPY bw/settings.json /opt/bunkerweb/settings.json
|
COPY bw/settings.json /opt/bunkerweb/settings.json
|
||||||
|
COPY db /opt/bunkerweb/db
|
||||||
|
COPY utils /opt/bunkerweb/utils
|
||||||
COPY VERSION /opt/bunkerweb/VERSION
|
COPY VERSION /opt/bunkerweb/VERSION
|
||||||
COPY ui/requirements.txt /opt/bunkerweb/ui/requirements.txt
|
|
||||||
|
|
||||||
# Install UI requirements
|
# Copy python requirements
|
||||||
RUN apk add --no-cache --virtual build gcc python3-dev musl-dev libffi-dev openssl-dev cargo && \
|
COPY ui/deps/requirements.txt /opt/bunkerweb/ui/deps/requirements.txt
|
||||||
pip install -r /opt/bunkerweb/ui/requirements.txt && \
|
|
||||||
|
# Install python requirements
|
||||||
|
RUN apk add --no-cache --virtual build py3-pip g++ gcc python3-dev musl-dev libffi-dev openssl-dev cargo && \
|
||||||
|
pip install --no-cache-dir --upgrade pip && \
|
||||||
|
pip install wheel && \
|
||||||
|
mkdir /opt/bunkerweb/ui/deps/python && \
|
||||||
|
pip install --no-cache-dir --require-hashes --target /opt/bunkerweb/ui/deps/python -r /opt/bunkerweb/ui/deps/requirements.txt && \
|
||||||
|
pip install --no-cache-dir gunicorn && \
|
||||||
apk del build
|
apk del build
|
||||||
|
|
||||||
COPY ui /opt/bunkerweb/ui
|
COPY ui /opt/bunkerweb/ui
|
||||||
|
@ -42,16 +36,13 @@ RUN apk add --no-cache bash file && \
|
||||||
find /opt/bunkerweb -type d -exec chmod 0750 {} \; && \
|
find /opt/bunkerweb -type d -exec chmod 0750 {} \; && \
|
||||||
chown -R ui:ui /data && \
|
chown -R ui:ui /data && \
|
||||||
chmod 770 /opt/bunkerweb/tmp && \
|
chmod 770 /opt/bunkerweb/tmp && \
|
||||||
chmod 750 /opt/bunkerweb/gen/main.py /opt/bunkerweb/deps/python/bin/* && \
|
chmod 750 /opt/bunkerweb/gen/main.py /opt/bunkerweb/ui/deps/python/bin/* && \
|
||||||
mkdir /etc/nginx && \
|
|
||||||
chown -R ui:ui /etc/nginx && \
|
|
||||||
chmod -R 770 /etc/nginx && \
|
|
||||||
ln -s /usr/local/bin/python /usr/bin/python3
|
ln -s /usr/local/bin/python /usr/bin/python3
|
||||||
|
|
||||||
# Fix CVEs
|
# Fix CVEs
|
||||||
RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "git>=2.32.3-r0" "ncurses-libs>=6.2_p20210612-r1" "ncurses-terminfo-base>=6.2_p20210612-r1" "libtirpc>=1.3.2-r1" "libtirpc-conf>=1.3.2-r1" "zlib>=1.2.12-r2" "libxml2>=2.9.14-r1"
|
RUN apk add "libssl1.1>=1.1.1q-r0" "libcrypto1.1>=1.1.1q-r0" "git>=2.32.3-r0" "ncurses-libs>=6.2_p20210612-r1" "ncurses-terminfo-base>=6.2_p20210612-r1" "libtirpc>=1.3.2-r1" "libtirpc-conf>=1.3.2-r1" "zlib>=1.2.12-r2" "libxml2>=2.9.14-r1"
|
||||||
|
|
||||||
VOLUME /data /etc/nginx
|
VOLUME /data
|
||||||
|
|
||||||
EXPOSE 7000
|
EXPOSE 7000
|
||||||
|
|
||||||
|
@ -59,4 +50,4 @@ WORKDIR /opt/bunkerweb/ui
|
||||||
|
|
||||||
USER ui:ui
|
USER ui:ui
|
||||||
|
|
||||||
CMD ["gunicorn", "--bind=0.0.0.0:7000", "--workers=1", "--threads=2", "main:app"]
|
CMD ["python", "-m", "gunicorn", "--bind=0.0.0.0:7000", "--workers=1", "--threads=2", "main:app"]
|
||||||
|
|
3
ui/deps/pip-hashes.sh
Executable file
3
ui/deps/pip-hashes.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
pip-compile --generate-hashes --allow-unsafe
|
|
@ -6,5 +6,7 @@ requests==2.28.1
|
||||||
docker==6.0.0
|
docker==6.0.0
|
||||||
python_dateutil==2.8.2
|
python_dateutil==2.8.2
|
||||||
python-magic==0.4.27
|
python-magic==0.4.27
|
||||||
bcrypt==4.0.0
|
bcrypt==4.0.1
|
||||||
gunicorn==20.1.0
|
sqlalchemy==1.4.42
|
||||||
|
pymysql==1.0.2
|
||||||
|
kubernetes==25.3.0
|
382
ui/deps/requirements.txt
Normal file
382
ui/deps/requirements.txt
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
#
|
||||||
|
# This file is autogenerated by pip-compile with python 3.10
|
||||||
|
# To update, run:
|
||||||
|
#
|
||||||
|
# pip-compile --allow-unsafe --generate-hashes
|
||||||
|
#
|
||||||
|
bcrypt==4.0.1 \
|
||||||
|
--hash=sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535 \
|
||||||
|
--hash=sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0 \
|
||||||
|
--hash=sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410 \
|
||||||
|
--hash=sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd \
|
||||||
|
--hash=sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665 \
|
||||||
|
--hash=sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab \
|
||||||
|
--hash=sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71 \
|
||||||
|
--hash=sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215 \
|
||||||
|
--hash=sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b \
|
||||||
|
--hash=sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda \
|
||||||
|
--hash=sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9 \
|
||||||
|
--hash=sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a \
|
||||||
|
--hash=sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344 \
|
||||||
|
--hash=sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f \
|
||||||
|
--hash=sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d \
|
||||||
|
--hash=sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c \
|
||||||
|
--hash=sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c \
|
||||||
|
--hash=sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2 \
|
||||||
|
--hash=sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d \
|
||||||
|
--hash=sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e \
|
||||||
|
--hash=sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3
|
||||||
|
# via -r requirements.in
|
||||||
|
beautifulsoup4==4.11.1 \
|
||||||
|
--hash=sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30 \
|
||||||
|
--hash=sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693
|
||||||
|
# via -r requirements.in
|
||||||
|
cachetools==5.2.0 \
|
||||||
|
--hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \
|
||||||
|
--hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db
|
||||||
|
# via google-auth
|
||||||
|
certifi==2022.9.24 \
|
||||||
|
--hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \
|
||||||
|
--hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382
|
||||||
|
# via
|
||||||
|
# kubernetes
|
||||||
|
# requests
|
||||||
|
charset-normalizer==2.1.1 \
|
||||||
|
--hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
|
||||||
|
--hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
|
||||||
|
# via requests
|
||||||
|
click==8.1.3 \
|
||||||
|
--hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
|
||||||
|
--hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
|
||||||
|
# via flask
|
||||||
|
docker==6.0.0 \
|
||||||
|
--hash=sha256:19e330470af40167d293b0352578c1fa22d74b34d3edf5d4ff90ebc203bbb2f1 \
|
||||||
|
--hash=sha256:6e06ee8eca46cd88733df09b6b80c24a1a556bc5cb1e1ae54b2c239886d245cf
|
||||||
|
# via -r requirements.in
|
||||||
|
flask==2.2.2 \
|
||||||
|
--hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
|
||||||
|
--hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
|
||||||
|
# via
|
||||||
|
# -r requirements.in
|
||||||
|
# flask-login
|
||||||
|
# flask-wtf
|
||||||
|
flask-login==0.6.2 \
|
||||||
|
--hash=sha256:1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f \
|
||||||
|
--hash=sha256:c0a7baa9fdc448cdd3dd6f0939df72eec5177b2f7abe6cb82fc934d29caac9c3
|
||||||
|
# via -r requirements.in
|
||||||
|
flask-wtf==1.0.1 \
|
||||||
|
--hash=sha256:34fe5c6fee0f69b50e30f81a3b7ea16aa1492a771fe9ad0974d164610c09a6c9 \
|
||||||
|
--hash=sha256:9d733658c80be551ce7d5bc13c7a7ac0d80df509be1e23827c847d9520f4359a
|
||||||
|
# via -r requirements.in
|
||||||
|
google-auth==2.13.0 \
|
||||||
|
--hash=sha256:9352dd6394093169157e6971526bab9a2799244d68a94a4a609f0dd751ef6f5e \
|
||||||
|
--hash=sha256:99510e664155f1a3c0396a076b5deb6367c52ea04d280152c85ac7f51f50eb42
|
||||||
|
# via kubernetes
|
||||||
|
greenlet==1.1.3.post0 \
|
||||||
|
--hash=sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754 \
|
||||||
|
--hash=sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136 \
|
||||||
|
--hash=sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519 \
|
||||||
|
--hash=sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403 \
|
||||||
|
--hash=sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9 \
|
||||||
|
--hash=sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809 \
|
||||||
|
--hash=sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e \
|
||||||
|
--hash=sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb \
|
||||||
|
--hash=sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05 \
|
||||||
|
--hash=sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80 \
|
||||||
|
--hash=sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b \
|
||||||
|
--hash=sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8 \
|
||||||
|
--hash=sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2 \
|
||||||
|
--hash=sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d \
|
||||||
|
--hash=sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8 \
|
||||||
|
--hash=sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3 \
|
||||||
|
--hash=sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194 \
|
||||||
|
--hash=sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e \
|
||||||
|
--hash=sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8 \
|
||||||
|
--hash=sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9 \
|
||||||
|
--hash=sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519 \
|
||||||
|
--hash=sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269 \
|
||||||
|
--hash=sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5 \
|
||||||
|
--hash=sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b \
|
||||||
|
--hash=sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5 \
|
||||||
|
--hash=sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21 \
|
||||||
|
--hash=sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd \
|
||||||
|
--hash=sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05 \
|
||||||
|
--hash=sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57 \
|
||||||
|
--hash=sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f \
|
||||||
|
--hash=sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f \
|
||||||
|
--hash=sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea \
|
||||||
|
--hash=sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a \
|
||||||
|
--hash=sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba \
|
||||||
|
--hash=sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5 \
|
||||||
|
--hash=sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa \
|
||||||
|
--hash=sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012 \
|
||||||
|
--hash=sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a \
|
||||||
|
--hash=sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10 \
|
||||||
|
--hash=sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3 \
|
||||||
|
--hash=sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743 \
|
||||||
|
--hash=sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6 \
|
||||||
|
--hash=sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7 \
|
||||||
|
--hash=sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad \
|
||||||
|
--hash=sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3 \
|
||||||
|
--hash=sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854 \
|
||||||
|
--hash=sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d \
|
||||||
|
--hash=sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be \
|
||||||
|
--hash=sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67 \
|
||||||
|
--hash=sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427 \
|
||||||
|
--hash=sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8 \
|
||||||
|
--hash=sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51 \
|
||||||
|
--hash=sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132 \
|
||||||
|
--hash=sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870 \
|
||||||
|
--hash=sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128 \
|
||||||
|
--hash=sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f \
|
||||||
|
--hash=sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392 \
|
||||||
|
--hash=sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b \
|
||||||
|
--hash=sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c \
|
||||||
|
--hash=sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589 \
|
||||||
|
--hash=sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54 \
|
||||||
|
--hash=sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9 \
|
||||||
|
--hash=sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c \
|
||||||
|
--hash=sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9 \
|
||||||
|
--hash=sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b \
|
||||||
|
--hash=sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04
|
||||||
|
# via sqlalchemy
|
||||||
|
idna==3.4 \
|
||||||
|
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
|
||||||
|
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
|
||||||
|
# via requests
|
||||||
|
itsdangerous==2.1.2 \
|
||||||
|
--hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
|
||||||
|
--hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
|
||||||
|
# via
|
||||||
|
# flask
|
||||||
|
# flask-wtf
|
||||||
|
jinja2==3.1.2 \
|
||||||
|
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
|
||||||
|
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
|
||||||
|
# via flask
|
||||||
|
kubernetes==25.3.0 \
|
||||||
|
--hash=sha256:213befbb4e5aed95f94950c7eed0c2322fc5a2f8f40932e58d28fdd42d90836c \
|
||||||
|
--hash=sha256:eb42333dad0bb5caf4e66460c6a4a1a36f0f057a040f35018f6c05a699baed86
|
||||||
|
# via -r requirements.in
|
||||||
|
markupsafe==2.1.1 \
|
||||||
|
--hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
|
||||||
|
--hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
|
||||||
|
--hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
|
||||||
|
--hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
|
||||||
|
--hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
|
||||||
|
--hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
|
||||||
|
--hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
|
||||||
|
--hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
|
||||||
|
--hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
|
||||||
|
--hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
|
||||||
|
--hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
|
||||||
|
--hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
|
||||||
|
--hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
|
||||||
|
--hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
|
||||||
|
--hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
|
||||||
|
--hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
|
||||||
|
--hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
|
||||||
|
--hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
|
||||||
|
--hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
|
||||||
|
--hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
|
||||||
|
--hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
|
||||||
|
--hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
|
||||||
|
--hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
|
||||||
|
--hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
|
||||||
|
--hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
|
||||||
|
--hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
|
||||||
|
--hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
|
||||||
|
--hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
|
||||||
|
--hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
|
||||||
|
--hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
|
||||||
|
--hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
|
||||||
|
--hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
|
||||||
|
--hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
|
||||||
|
--hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
|
||||||
|
--hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
|
||||||
|
--hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
|
||||||
|
--hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
|
||||||
|
--hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
|
||||||
|
--hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
|
||||||
|
--hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
|
||||||
|
# via
|
||||||
|
# jinja2
|
||||||
|
# werkzeug
|
||||||
|
# wtforms
|
||||||
|
oauthlib==3.2.2 \
|
||||||
|
--hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \
|
||||||
|
--hash=sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918
|
||||||
|
# via requests-oauthlib
|
||||||
|
packaging==21.3 \
|
||||||
|
--hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
|
||||||
|
--hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
|
||||||
|
# via docker
|
||||||
|
pyasn1==0.4.8 \
|
||||||
|
--hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \
|
||||||
|
--hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba
|
||||||
|
# via
|
||||||
|
# pyasn1-modules
|
||||||
|
# rsa
|
||||||
|
pyasn1-modules==0.2.8 \
|
||||||
|
--hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \
|
||||||
|
--hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74
|
||||||
|
# via google-auth
|
||||||
|
pymysql==1.0.2 \
|
||||||
|
--hash=sha256:41fc3a0c5013d5f039639442321185532e3e2c8924687abe6537de157d403641 \
|
||||||
|
--hash=sha256:816927a350f38d56072aeca5dfb10221fe1dc653745853d30a216637f5d7ad36
|
||||||
|
# via -r requirements.in
|
||||||
|
pyparsing==3.0.9 \
|
||||||
|
--hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
|
||||||
|
--hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
|
||||||
|
# via packaging
|
||||||
|
python-dateutil==2.8.2 \
|
||||||
|
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
|
||||||
|
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
|
||||||
|
# via
|
||||||
|
# -r requirements.in
|
||||||
|
# kubernetes
|
||||||
|
python-magic==0.4.27 \
|
||||||
|
--hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \
|
||||||
|
--hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3
|
||||||
|
# via -r requirements.in
|
||||||
|
pyyaml==6.0 \
|
||||||
|
--hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \
|
||||||
|
--hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \
|
||||||
|
--hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \
|
||||||
|
--hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \
|
||||||
|
--hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \
|
||||||
|
--hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \
|
||||||
|
--hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \
|
||||||
|
--hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \
|
||||||
|
--hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \
|
||||||
|
--hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \
|
||||||
|
--hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
|
||||||
|
--hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \
|
||||||
|
--hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \
|
||||||
|
--hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \
|
||||||
|
--hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
|
||||||
|
--hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
|
||||||
|
--hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \
|
||||||
|
--hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \
|
||||||
|
--hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \
|
||||||
|
--hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \
|
||||||
|
--hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
|
||||||
|
--hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \
|
||||||
|
--hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
|
||||||
|
--hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \
|
||||||
|
--hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \
|
||||||
|
--hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \
|
||||||
|
--hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \
|
||||||
|
--hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \
|
||||||
|
--hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \
|
||||||
|
--hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \
|
||||||
|
--hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \
|
||||||
|
--hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \
|
||||||
|
--hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \
|
||||||
|
--hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
|
||||||
|
--hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \
|
||||||
|
--hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \
|
||||||
|
--hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
|
||||||
|
--hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \
|
||||||
|
--hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
|
||||||
|
--hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
|
||||||
|
# via kubernetes
|
||||||
|
requests==2.28.1 \
|
||||||
|
--hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \
|
||||||
|
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
|
||||||
|
# via
|
||||||
|
# -r requirements.in
|
||||||
|
# docker
|
||||||
|
# kubernetes
|
||||||
|
# requests-oauthlib
|
||||||
|
requests-oauthlib==1.3.1 \
|
||||||
|
--hash=sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5 \
|
||||||
|
--hash=sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a
|
||||||
|
# via kubernetes
|
||||||
|
rsa==4.9 \
|
||||||
|
--hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \
|
||||||
|
--hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21
|
||||||
|
# via google-auth
|
||||||
|
six==1.16.0 \
|
||||||
|
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
|
||||||
|
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
|
||||||
|
# via
|
||||||
|
# google-auth
|
||||||
|
# kubernetes
|
||||||
|
# python-dateutil
|
||||||
|
soupsieve==2.3.2.post1 \
|
||||||
|
--hash=sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759 \
|
||||||
|
--hash=sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d
|
||||||
|
# via beautifulsoup4
|
||||||
|
sqlalchemy==1.4.42 \
|
||||||
|
--hash=sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9 \
|
||||||
|
--hash=sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049 \
|
||||||
|
--hash=sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80 \
|
||||||
|
--hash=sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d \
|
||||||
|
--hash=sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628 \
|
||||||
|
--hash=sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363 \
|
||||||
|
--hash=sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0 \
|
||||||
|
--hash=sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6 \
|
||||||
|
--hash=sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2 \
|
||||||
|
--hash=sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124 \
|
||||||
|
--hash=sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2 \
|
||||||
|
--hash=sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd \
|
||||||
|
--hash=sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3 \
|
||||||
|
--hash=sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb \
|
||||||
|
--hash=sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5 \
|
||||||
|
--hash=sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e \
|
||||||
|
--hash=sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b \
|
||||||
|
--hash=sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934 \
|
||||||
|
--hash=sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516 \
|
||||||
|
--hash=sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc \
|
||||||
|
--hash=sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a \
|
||||||
|
--hash=sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738 \
|
||||||
|
--hash=sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908 \
|
||||||
|
--hash=sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0 \
|
||||||
|
--hash=sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1 \
|
||||||
|
--hash=sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272 \
|
||||||
|
--hash=sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d \
|
||||||
|
--hash=sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95 \
|
||||||
|
--hash=sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde \
|
||||||
|
--hash=sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798 \
|
||||||
|
--hash=sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525 \
|
||||||
|
--hash=sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565 \
|
||||||
|
--hash=sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88 \
|
||||||
|
--hash=sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545 \
|
||||||
|
--hash=sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775 \
|
||||||
|
--hash=sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a \
|
||||||
|
--hash=sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565 \
|
||||||
|
--hash=sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71 \
|
||||||
|
--hash=sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471 \
|
||||||
|
--hash=sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257 \
|
||||||
|
--hash=sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a
|
||||||
|
# via -r requirements.in
|
||||||
|
urllib3==1.26.12 \
|
||||||
|
--hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \
|
||||||
|
--hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997
|
||||||
|
# via
|
||||||
|
# docker
|
||||||
|
# kubernetes
|
||||||
|
# requests
|
||||||
|
websocket-client==1.4.1 \
|
||||||
|
--hash=sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090 \
|
||||||
|
--hash=sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef
|
||||||
|
# via
|
||||||
|
# docker
|
||||||
|
# kubernetes
|
||||||
|
werkzeug==2.2.2 \
|
||||||
|
--hash=sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f \
|
||||||
|
--hash=sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5
|
||||||
|
# via
|
||||||
|
# flask
|
||||||
|
# flask-login
|
||||||
|
wtforms==3.0.1 \
|
||||||
|
--hash=sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc \
|
||||||
|
--hash=sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b
|
||||||
|
# via flask-wtf
|
||||||
|
|
||||||
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
|
setuptools==65.5.0 \
|
||||||
|
--hash=sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17 \
|
||||||
|
--hash=sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356
|
||||||
|
# via kubernetes
|
88
ui/main.py
88
ui/main.py
|
@ -1,3 +1,7 @@
|
||||||
|
from sys import path as sys_path, exit as sys_exit, modules as sys_modules
|
||||||
|
|
||||||
|
sys_path.append("/opt/bunkerweb/ui/deps/python")
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
@ -23,16 +27,15 @@ from flask_wtf.csrf import CSRFProtect, CSRFError, generate_csrf
|
||||||
from json import JSONDecodeError, load as json_load
|
from json import JSONDecodeError, load as json_load
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
from logging import getLogger, INFO, ERROR, StreamHandler, Formatter
|
from logging import getLogger, INFO, ERROR, StreamHandler, Formatter
|
||||||
from os import chmod, getpid, listdir, mkdir, walk
|
from os import chmod, getenv, getpid, listdir, mkdir, walk
|
||||||
from os.path import exists, isdir, isfile, join
|
from os.path import exists, isdir, isfile, join
|
||||||
from re import match as re_match
|
from re import match as re_match
|
||||||
from requests import get
|
from requests import get
|
||||||
from requests.utils import default_headers
|
from requests.utils import default_headers
|
||||||
from shutil import rmtree, copytree, chown
|
from shutil import rmtree, copytree, chown
|
||||||
from sys import path as sys_path, exit as sys_exit, modules as sys_modules
|
|
||||||
from tarfile import CompressionError, HeaderError, ReadError, TarError, open as tar_open
|
from tarfile import CompressionError, HeaderError, ReadError, TarError, open as tar_open
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from time import time
|
from time import sleep, time
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
@ -40,12 +43,14 @@ from zipfile import BadZipFile, ZipFile
|
||||||
|
|
||||||
sys_path.append("/opt/bunkerweb/utils")
|
sys_path.append("/opt/bunkerweb/utils")
|
||||||
sys_path.append("/opt/bunkerweb/api")
|
sys_path.append("/opt/bunkerweb/api")
|
||||||
|
sys_path.append("/opt/bunkerweb/db")
|
||||||
|
|
||||||
from src.Instances import Instances
|
from src.Instances import Instances
|
||||||
from src.ConfigFiles import ConfigFiles
|
from src.ConfigFiles import ConfigFiles
|
||||||
from src.Config import Config
|
from src.Config import Config
|
||||||
from src.ReverseProxied import ReverseProxied
|
from src.ReverseProxied import ReverseProxied
|
||||||
from src.User import User
|
from src.User import User
|
||||||
|
|
||||||
from utils import (
|
from utils import (
|
||||||
check_settings,
|
check_settings,
|
||||||
env_to_summary_class,
|
env_to_summary_class,
|
||||||
|
@ -57,20 +62,10 @@ from utils import (
|
||||||
get_variables,
|
get_variables,
|
||||||
path_to_dict,
|
path_to_dict,
|
||||||
)
|
)
|
||||||
from API import API
|
from logger import setup_logger
|
||||||
from ApiCaller import ApiCaller
|
from Database import Database
|
||||||
|
|
||||||
# Set up logger
|
logger = setup_logger("UI", getenv("LOG_LEVEL", "INFO"))
|
||||||
logger = getLogger("flask_app")
|
|
||||||
logger.setLevel(INFO)
|
|
||||||
# create console handler with a higher log level
|
|
||||||
ch = StreamHandler()
|
|
||||||
ch.setLevel(ERROR)
|
|
||||||
# create formatter and add it to the handlers
|
|
||||||
formatter = Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
||||||
ch.setFormatter(formatter)
|
|
||||||
# add the handlers to logger
|
|
||||||
logger.addHandler(ch)
|
|
||||||
|
|
||||||
# Flask app
|
# Flask app
|
||||||
app = Flask(
|
app = Flask(
|
||||||
|
@ -84,13 +79,25 @@ app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||||
# Set variables and instantiate objects
|
# Set variables and instantiate objects
|
||||||
vars = get_variables()
|
vars = get_variables()
|
||||||
|
|
||||||
|
if "ABSOLUTE_URI" not in vars:
|
||||||
|
logger.error("ABSOLUTE_URI is not set")
|
||||||
|
sys_exit(1)
|
||||||
|
elif "ADMIN_USERNAME" not in vars:
|
||||||
|
logger.error("ADMIN_USERNAME is not set")
|
||||||
|
sys_exit(1)
|
||||||
|
elif "ADMIN_PASSWORD" not in vars:
|
||||||
|
logger.error("ADMIN_PASSWORD is not set")
|
||||||
|
sys_exit(1)
|
||||||
|
|
||||||
if not vars["FLASK_ENV"] == "development" and vars["ADMIN_PASSWORD"] == "changeme":
|
if not vars["FLASK_ENV"] == "development" and vars["ADMIN_PASSWORD"] == "changeme":
|
||||||
logger.error("Please change the default admin password.")
|
logger.error("Please change the default admin password.")
|
||||||
sys_exit(1)
|
sys_exit(1)
|
||||||
|
|
||||||
if not vars["FLASK_ENV"] == "development" and (
|
if not vars["ABSOLUTE_URI"].endswith("/"):
|
||||||
vars["ABSOLUTE_URI"].endswith("/changeme/")
|
vars["ABSOLUTE_URI"] += "/"
|
||||||
or vars["ABSOLUTE_URI"].endswith("/changeme")
|
|
||||||
|
if not vars["FLASK_ENV"] == "development" and vars["ABSOLUTE_URI"].endswith(
|
||||||
|
"/changeme/"
|
||||||
):
|
):
|
||||||
logger.error("Please change the default URL.")
|
logger.error("Please change the default URL.")
|
||||||
sys_exit(1)
|
sys_exit(1)
|
||||||
|
@ -102,7 +109,6 @@ login_manager = LoginManager()
|
||||||
login_manager.init_app(app)
|
login_manager.init_app(app)
|
||||||
login_manager.login_view = "login"
|
login_manager.login_view = "login"
|
||||||
user = User(vars["ADMIN_USERNAME"], vars["ADMIN_PASSWORD"])
|
user = User(vars["ADMIN_USERNAME"], vars["ADMIN_PASSWORD"])
|
||||||
api_caller = ApiCaller()
|
|
||||||
PLUGIN_KEYS = [
|
PLUGIN_KEYS = [
|
||||||
"id",
|
"id",
|
||||||
"order",
|
"order",
|
||||||
|
@ -112,39 +118,31 @@ PLUGIN_KEYS = [
|
||||||
"settings",
|
"settings",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
bw_integration = "Local"
|
||||||
|
if getenv("KUBERNETES_MODE", "no") == "yes":
|
||||||
|
bw_integration = "Kubernetes"
|
||||||
|
elif getenv("SWARM_MODE", "no") == "yes" or getenv("AUTOCONF_MODE", "no") == "yes":
|
||||||
|
bw_integration = "Cluster"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
docker_client: DockerClient = DockerClient(base_url=vars["DOCKER_HOST"])
|
docker_client: DockerClient = DockerClient(
|
||||||
|
base_url=vars.get("DOCKER_HOST", "unix:///var/run/docker.sock")
|
||||||
|
)
|
||||||
|
bw_integration = "Cluster"
|
||||||
except (docker_APIError, DockerException):
|
except (docker_APIError, DockerException):
|
||||||
|
logger.warning("No docker host found")
|
||||||
docker_client = None
|
docker_client = None
|
||||||
|
|
||||||
|
db = Database(logger, bw_integration=bw_integration)
|
||||||
if docker_client:
|
|
||||||
apis: list[API] = []
|
|
||||||
for container in docker_client.containers.list(
|
|
||||||
filters={"label": "bunkerweb.INSTANCE"}
|
|
||||||
):
|
|
||||||
env_variables = {
|
|
||||||
x[0]: x[1]
|
|
||||||
for x in [env.split("=") for env in container.attrs["Config"]["Env"]]
|
|
||||||
}
|
|
||||||
|
|
||||||
apis.append(
|
|
||||||
API(
|
|
||||||
f"http://{container.name}:{env_variables.get('API_HTTP_PORT', '5000')}",
|
|
||||||
env_variables.get("API_SERVER_NAME", "bwapi"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
api_caller._set_apis(apis)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app.config.update(
|
app.config.update(
|
||||||
DEBUG=True,
|
DEBUG=True,
|
||||||
SECRET_KEY=vars["FLASK_SECRET"],
|
SECRET_KEY=vars["FLASK_SECRET"],
|
||||||
ABSOLUTE_URI=vars["ABSOLUTE_URI"],
|
ABSOLUTE_URI=vars["ABSOLUTE_URI"],
|
||||||
INSTANCES=Instances(docker_client),
|
INSTANCES=Instances(docker_client, bw_integration),
|
||||||
CONFIG=Config(),
|
CONFIG=Config(logger, db),
|
||||||
CONFIGFILES=ConfigFiles(),
|
CONFIGFILES=ConfigFiles(db),
|
||||||
SESSION_COOKIE_DOMAIN=vars["ABSOLUTE_URI"]
|
SESSION_COOKIE_DOMAIN=vars["ABSOLUTE_URI"]
|
||||||
.replace("http://", "")
|
.replace("http://", "")
|
||||||
.replace("https://", "")
|
.replace("https://", "")
|
||||||
|
@ -610,6 +608,10 @@ def configs():
|
||||||
|
|
||||||
flash(operation)
|
flash(operation)
|
||||||
|
|
||||||
|
error = app.config["CONFIGFILES"].save_configs()
|
||||||
|
if error:
|
||||||
|
flash("Couldn't save custom configs to database", "error")
|
||||||
|
|
||||||
# Reload instances
|
# Reload instances
|
||||||
app.config["RELOADING"] = True
|
app.config["RELOADING"] = True
|
||||||
Thread(
|
Thread(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from os import listdir
|
from os import listdir
|
||||||
|
from time import sleep
|
||||||
from flask import flash
|
from flask import flash
|
||||||
from os.path import isfile
|
from os.path import exists, isfile
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from json import load as json_load
|
from json import load as json_load
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
@ -11,10 +12,28 @@ from subprocess import run, DEVNULL, STDOUT
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
def __init__(self):
|
def __init__(self, logger, db) -> None:
|
||||||
with open("/opt/bunkerweb/settings.json", "r") as f:
|
with open("/opt/bunkerweb/settings.json", "r") as f:
|
||||||
self.__settings: dict = json_load(f)
|
self.__settings: dict = json_load(f)
|
||||||
|
|
||||||
|
self.__logger = logger
|
||||||
|
self.__db = db
|
||||||
|
|
||||||
|
if not exists("/usr/sbin/nginx"):
|
||||||
|
while not self.__db.is_initialized():
|
||||||
|
self.__logger.warning(
|
||||||
|
"Database is not initialized, retrying in 5s ...",
|
||||||
|
)
|
||||||
|
sleep(3)
|
||||||
|
|
||||||
|
env = self.__db.get_config()
|
||||||
|
while not self.__db.is_first_config_saved() or not env:
|
||||||
|
self.__logger.warning(
|
||||||
|
"Database doesn't have any config saved yet, retrying in 5s ...",
|
||||||
|
)
|
||||||
|
sleep(3)
|
||||||
|
env = self.__db.get_config()
|
||||||
|
|
||||||
self.reload_plugins()
|
self.reload_plugins()
|
||||||
|
|
||||||
def reload_plugins(self) -> None:
|
def reload_plugins(self) -> None:
|
||||||
|
@ -145,6 +164,8 @@ class Config:
|
||||||
"/etc/nginx",
|
"/etc/nginx",
|
||||||
"--variables",
|
"--variables",
|
||||||
env_file,
|
env_file,
|
||||||
|
"--method",
|
||||||
|
"ui",
|
||||||
],
|
],
|
||||||
stdin=DEVNULL,
|
stdin=DEVNULL,
|
||||||
stderr=STDOUT,
|
stderr=STDOUT,
|
||||||
|
@ -153,6 +174,12 @@ class Config:
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise Exception(f"Error from generator (return code = {proc.returncode})")
|
raise Exception(f"Error from generator (return code = {proc.returncode})")
|
||||||
|
|
||||||
|
ret = self.__db.save_config(conf, "ui")
|
||||||
|
if ret:
|
||||||
|
self.__logger.error(
|
||||||
|
f"Can't save config in database: {ret}",
|
||||||
|
)
|
||||||
|
|
||||||
def get_plugins_settings(self) -> dict:
|
def get_plugins_settings(self) -> dict:
|
||||||
return self.__plugins_settings
|
return self.__plugins_settings
|
||||||
|
|
||||||
|
@ -173,7 +200,13 @@ class Config:
|
||||||
dict
|
dict
|
||||||
The nginx variables env file as a dict
|
The nginx variables env file as a dict
|
||||||
"""
|
"""
|
||||||
return self.__env_to_dict("/etc/nginx/variables.env")
|
if exists("/usr/sbin/nginx"):
|
||||||
|
return {
|
||||||
|
k: {"value": v, "method": "ui"}
|
||||||
|
for k, v in self.__env_to_dict("/etc/nginx/variables.env").items()
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.__db.get_config(methods=True)
|
||||||
|
|
||||||
def get_services(self) -> list[dict]:
|
def get_services(self) -> list[dict]:
|
||||||
"""Get nginx's services
|
"""Get nginx's services
|
||||||
|
@ -183,12 +216,18 @@ class Config:
|
||||||
list
|
list
|
||||||
The services
|
The services
|
||||||
"""
|
"""
|
||||||
services = []
|
if exists("/usr/sbin/nginx"):
|
||||||
for filename in iglob("/etc/nginx/**/variables.env"):
|
services = []
|
||||||
env = self.__env_to_dict(filename)
|
for filename in iglob("/etc/nginx/**/variables.env"):
|
||||||
services.append(env)
|
env = {
|
||||||
|
k: {"value": v, "method": "ui"}
|
||||||
|
for k, v in self.__env_to_dict(filename).items()
|
||||||
|
}
|
||||||
|
services.append(env)
|
||||||
|
|
||||||
return services
|
return services
|
||||||
|
|
||||||
|
return self.__db.get_services_settings(methods=True)
|
||||||
|
|
||||||
def check_variables(self, variables: dict, _global: bool = False) -> int:
|
def check_variables(self, variables: dict, _global: bool = False) -> int:
|
||||||
"""Testify that the variables passed are valid
|
"""Testify that the variables passed are valid
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
from os import listdir, mkdir, remove, replace, walk
|
||||||
|
from os.path import dirname, exists, join, isfile
|
||||||
from re import compile as re_compile
|
from re import compile as re_compile
|
||||||
from shutil import rmtree, move as shutil_move
|
from shutil import rmtree, move as shutil_move
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
@ -7,13 +8,41 @@ from utils import path_to_dict
|
||||||
|
|
||||||
|
|
||||||
class ConfigFiles:
|
class ConfigFiles:
|
||||||
def __init__(self):
|
def __init__(self, db):
|
||||||
self.__name_regex = re_compile(r"^[a-zA-Z0-9_-]{1,64}$")
|
self.__name_regex = re_compile(r"^[a-zA-Z0-9_-]{1,64}$")
|
||||||
self.__root_dirs = [
|
self.__root_dirs = [
|
||||||
child["name"]
|
child["name"]
|
||||||
for child in path_to_dict("/opt/bunkerweb/configs")["children"]
|
for child in path_to_dict("/opt/bunkerweb/configs")["children"]
|
||||||
]
|
]
|
||||||
self.__file_creation_blacklist = ["http", "stream"]
|
self.__file_creation_blacklist = ["http", "stream"]
|
||||||
|
self.__db = db
|
||||||
|
|
||||||
|
def save_configs(self) -> str:
|
||||||
|
custom_configs = {}
|
||||||
|
root_dirs = listdir("/opt/bunkerweb/configs")
|
||||||
|
for (root, dirs, files) in walk("/opt/bunkerweb/configs", topdown=True):
|
||||||
|
if (
|
||||||
|
root != "configs"
|
||||||
|
and (dirs and not root.split("/")[-1] in root_dirs)
|
||||||
|
or files
|
||||||
|
):
|
||||||
|
path_exploded = root.split("/")
|
||||||
|
for file in files:
|
||||||
|
with open(join(root, file), "r") as f:
|
||||||
|
custom_configs[
|
||||||
|
(
|
||||||
|
f"{path_exploded.pop()}"
|
||||||
|
if path_exploded[-1] not in root_dirs
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
+ f"CUSTOM_CONF_{path_exploded[-1].replace('-', '_').upper()}_{file.replace('.conf', '')}"
|
||||||
|
] = f.read()
|
||||||
|
|
||||||
|
ret = self.__db.save_custom_configs(custom_configs, "ui")
|
||||||
|
if ret:
|
||||||
|
return "Couldn't save custom configs to database"
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
def check_name(self, name: str) -> bool:
|
def check_name(self, name: str) -> bool:
|
||||||
return self.__name_regex.match(name)
|
return self.__name_regex.match(name)
|
||||||
|
@ -39,7 +68,7 @@ class ConfigFiles:
|
||||||
dirs = "/".join(dirs)
|
dirs = "/".join(dirs)
|
||||||
if len(dirs) > 1:
|
if len(dirs) > 1:
|
||||||
for x in range(nbr_children - 1):
|
for x in range(nbr_children - 1):
|
||||||
if not os.path.exists(
|
if not exists(
|
||||||
f"{root_path}{root_dir}/{'/'.join(dirs.split('/')[0:-x])}"
|
f"{root_path}{root_dir}/{'/'.join(dirs.split('/')[0:-x])}"
|
||||||
):
|
):
|
||||||
return f"{root_path}{root_dir}/{'/'.join(dirs.split('/')[0:-x])} doesn't exist"
|
return f"{root_path}{root_dir}/{'/'.join(dirs.split('/')[0:-x])} doesn't exist"
|
||||||
|
@ -48,8 +77,8 @@ class ConfigFiles:
|
||||||
|
|
||||||
def delete_path(self, path: str) -> Tuple[str, int]:
|
def delete_path(self, path: str) -> Tuple[str, int]:
|
||||||
try:
|
try:
|
||||||
if os.path.isfile(path):
|
if isfile(path):
|
||||||
os.remove(path)
|
remove(path)
|
||||||
else:
|
else:
|
||||||
rmtree(path)
|
rmtree(path)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -58,23 +87,23 @@ class ConfigFiles:
|
||||||
return f"{path} was successfully deleted", 0
|
return f"{path} was successfully deleted", 0
|
||||||
|
|
||||||
def create_folder(self, path: str, name: str) -> Tuple[str, int]:
|
def create_folder(self, path: str, name: str) -> Tuple[str, int]:
|
||||||
folder_path = os.path.join(path, name)
|
folder_path = join(path, name)
|
||||||
try:
|
try:
|
||||||
os.mkdir(folder_path)
|
mkdir(folder_path)
|
||||||
except OSError:
|
except OSError:
|
||||||
return f"Could not create {folder_path}", 1
|
return f"Could not create {folder_path}", 1
|
||||||
|
|
||||||
return f"The folder {folder_path} was successfully created", 0
|
return f"The folder {folder_path} was successfully created", 0
|
||||||
|
|
||||||
def create_file(self, path: str, name: str, content: str) -> Tuple[str, int]:
|
def create_file(self, path: str, name: str, content: str) -> Tuple[str, int]:
|
||||||
file_path = os.path.join(path, name)
|
file_path = join(path, name)
|
||||||
with open(file_path, "w") as f:
|
with open(file_path, "w") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
|
|
||||||
return f"The file {file_path} was successfully created", 0
|
return f"The file {file_path} was successfully created", 0
|
||||||
|
|
||||||
def edit_folder(self, path: str, name: str) -> Tuple[str, int]:
|
def edit_folder(self, path: str, name: str) -> Tuple[str, int]:
|
||||||
new_folder_path = os.path.dirname(os.path.join(path, name))
|
new_folder_path = dirname(join(path, name))
|
||||||
|
|
||||||
if path == new_folder_path:
|
if path == new_folder_path:
|
||||||
return (
|
return (
|
||||||
|
@ -90,7 +119,7 @@ class ConfigFiles:
|
||||||
return f"The folder {path} was successfully renamed to {new_folder_path}", 0
|
return f"The folder {path} was successfully renamed to {new_folder_path}", 0
|
||||||
|
|
||||||
def edit_file(self, path: str, name: str, content: str) -> Tuple[str, int]:
|
def edit_file(self, path: str, name: str, content: str) -> Tuple[str, int]:
|
||||||
new_path = os.path.dirname(os.path.join(path, name))
|
new_path = dirname(join(path, name))
|
||||||
try:
|
try:
|
||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
|
@ -104,7 +133,7 @@ class ConfigFiles:
|
||||||
)
|
)
|
||||||
elif file_content == content:
|
elif file_content == content:
|
||||||
try:
|
try:
|
||||||
os.replace(path, new_path)
|
replace(path, new_path)
|
||||||
return f"{path} was successfully renamed to {new_path}", 0
|
return f"{path} was successfully renamed to {new_path}", 0
|
||||||
except OSError:
|
except OSError:
|
||||||
return f"Could not rename {path} into {new_path}", 1
|
return f"Could not rename {path} into {new_path}", 1
|
||||||
|
@ -112,7 +141,7 @@ class ConfigFiles:
|
||||||
new_path = path
|
new_path = path
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
remove(path)
|
||||||
except OSError:
|
except OSError:
|
||||||
return f"Could not remove {path}", 1
|
return f"Could not remove {path}", 1
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import os
|
from os import getenv
|
||||||
|
from os.path import exists
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
|
from kubernetes import client as kube_client
|
||||||
|
|
||||||
from API import API
|
from API import API
|
||||||
from ApiCaller import ApiCaller
|
from ApiCaller import ApiCaller
|
||||||
|
@ -35,7 +37,7 @@ class Instance:
|
||||||
if "Health" in data.attrs["State"]
|
if "Health" in data.attrs["State"]
|
||||||
else False
|
else False
|
||||||
)
|
)
|
||||||
if data
|
if _type == "container" and data
|
||||||
else True
|
else True
|
||||||
)
|
)
|
||||||
self.env = data
|
self.env = data
|
||||||
|
@ -44,8 +46,8 @@ class Instance:
|
||||||
def get_id(self) -> str:
|
def get_id(self) -> str:
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
def run_jobs(self) -> bool:
|
# def run_jobs(self) -> bool:
|
||||||
return self.apiCaller._send_to_apis("POST", "/jobs")
|
# return self.apiCaller._send_to_apis("POST", "/jobs")
|
||||||
|
|
||||||
def reload(self) -> bool:
|
def reload(self) -> bool:
|
||||||
return self.apiCaller._send_to_apis("POST", "/reload")
|
return self.apiCaller._send_to_apis("POST", "/reload")
|
||||||
|
@ -59,10 +61,14 @@ class Instance:
|
||||||
def restart(self) -> bool:
|
def restart(self) -> bool:
|
||||||
return self.apiCaller._send_to_apis("POST", "/restart")
|
return self.apiCaller._send_to_apis("POST", "/restart")
|
||||||
|
|
||||||
|
def send_custom_configs(self) -> bool:
|
||||||
|
return self.apiCaller._send_files("/opt/bunkerweb/configs", "/custom_configs")
|
||||||
|
|
||||||
|
|
||||||
class Instances:
|
class Instances:
|
||||||
def __init__(self, docker_client):
|
def __init__(self, docker_client, bw_integration: str):
|
||||||
self.__docker = docker_client
|
self.__docker = docker_client
|
||||||
|
self.__bw_integration = bw_integration
|
||||||
|
|
||||||
def __instance_from_id(self, _id) -> Instance:
|
def __instance_from_id(self, _id) -> Instance:
|
||||||
instances: list[Instance] = self.get_instances()
|
instances: list[Instance] = self.get_instances()
|
||||||
|
@ -106,13 +112,80 @@ class Instances:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
is_swarm = True
|
||||||
|
try:
|
||||||
|
self.__docker.swarm.version
|
||||||
|
except:
|
||||||
|
is_swarm = False
|
||||||
|
|
||||||
|
if is_swarm:
|
||||||
|
for instance in self.__docker.services.list(
|
||||||
|
filters={"label": "bunkerweb.INSTANCE"}
|
||||||
|
):
|
||||||
|
status = "down"
|
||||||
|
desired_tasks = instance.attrs["ServiceStatus"]["DesiredTasks"]
|
||||||
|
running_tasks = instance.attrs["ServiceStatus"]["RunningTasks"]
|
||||||
|
if desired_tasks > 0 and (desired_tasks == running_tasks):
|
||||||
|
status = "up"
|
||||||
|
|
||||||
|
instances.append(
|
||||||
|
Instance(
|
||||||
|
instance.id,
|
||||||
|
instance.name,
|
||||||
|
instance.name,
|
||||||
|
"service",
|
||||||
|
status,
|
||||||
|
instance,
|
||||||
|
apiCaller,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif self.__bw_integration == "Kubernetes":
|
||||||
|
corev1 = kube_client.CoreV1Api()
|
||||||
|
for pod in corev1.list_pod_for_all_namespaces(watch=False).items:
|
||||||
|
if (
|
||||||
|
pod.metadata.annotations != None
|
||||||
|
and "bunkerweb.io/INSTANCE" in pod.metadata.annotations
|
||||||
|
):
|
||||||
|
env_variables = {
|
||||||
|
e.name: e.value for e in pod.spec.containers[0].env
|
||||||
|
}
|
||||||
|
|
||||||
|
apiCaller = ApiCaller()
|
||||||
|
apiCaller._set_apis(
|
||||||
|
[
|
||||||
|
API(
|
||||||
|
f"http://{pod.status.pod_ip}:{env_variables.get('API_HTTP_PORT', '5000')}",
|
||||||
|
env_variables.get("API_SERVER_NAME", "bwapi"),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
status = "up"
|
||||||
|
if pod.status.conditions is not None:
|
||||||
|
for condition in pod.status.conditions:
|
||||||
|
if condition.type == "Ready" and condition.status == "True":
|
||||||
|
status = "down"
|
||||||
|
break
|
||||||
|
|
||||||
|
instances.append(
|
||||||
|
Instance(
|
||||||
|
pod.metadata.uid,
|
||||||
|
pod.metadata.name,
|
||||||
|
pod.status.pod_ip,
|
||||||
|
"container",
|
||||||
|
status,
|
||||||
|
pod,
|
||||||
|
apiCaller,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
instances = sorted(
|
instances = sorted(
|
||||||
instances,
|
instances,
|
||||||
key=lambda x: x.name,
|
key=lambda x: x.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Local instance
|
# Local instance
|
||||||
if os.path.exists("/usr/sbin/nginx"):
|
if exists("/usr/sbin/nginx"):
|
||||||
instances.insert(
|
instances.insert(
|
||||||
0,
|
0,
|
||||||
Instance(
|
Instance(
|
||||||
|
@ -120,12 +193,24 @@ class Instances:
|
||||||
"local",
|
"local",
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"local",
|
"local",
|
||||||
"up" if os.path.exists("/opt/bunkerweb/tmp/nginx.pid") else "down",
|
"up" if exists("/opt/bunkerweb/tmp/nginx.pid") else "down",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return instances
|
return instances
|
||||||
|
|
||||||
|
def send_custom_configs_to_instances(self) -> Union[list[str], str]:
|
||||||
|
failed_to_send: list[str] = []
|
||||||
|
for instance in self.get_instances():
|
||||||
|
if instance.health is False:
|
||||||
|
failed_to_send.append(instance.name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not instance.send_custom_configs():
|
||||||
|
failed_to_send.append(instance.name)
|
||||||
|
|
||||||
|
return failed_to_send or "Successfully sent custom configs to instances"
|
||||||
|
|
||||||
def reload_instances(self) -> Union[list[str], str]:
|
def reload_instances(self) -> Union[list[str], str]:
|
||||||
not_reloaded: list[str] = []
|
not_reloaded: list[str] = []
|
||||||
for instance in self.get_instances():
|
for instance in self.get_instances():
|
||||||
|
@ -151,7 +236,7 @@ class Instances:
|
||||||
!= 0
|
!= 0
|
||||||
)
|
)
|
||||||
elif instance._type == "container":
|
elif instance._type == "container":
|
||||||
result = instance.run_jobs()
|
# result = instance.run_jobs()
|
||||||
result = result & instance.reload()
|
result = result & instance.reload()
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
|
|
Loading…
Reference in a new issue