Merge pull request #621 from bunkerity/dev

Merge branch "dev" into branch "staging"
This commit is contained in:
Théophile Diot 2023-09-06 11:56:12 +02:00 committed by GitHub
commit f59476c26d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 179 deletions

View file

@ -7,51 +7,35 @@ on:
branches: [ui]
jobs:
# Containers
build-bw:
build-containers:
permissions:
contents: read
packages: write
strategy:
matrix:
image: [bunkerweb, scheduler, ui]
include:
- image: bunkerweb
dockerfile: src/bw/Dockerfile
- image: scheduler
dockerfile: src/scheduler/Dockerfile
- image: ui
dockerfile: src/ui/Dockerfile
uses: ./.github/workflows/container-build.yml
with:
RELEASE: ui
CACHE: true
ARCH: linux/amd64
IMAGE: bunkerweb
DOCKERFILE: src/bw/Dockerfile
IMAGE: ${{ matrix.image }}
DOCKERFILE: ${{ matrix.dockerfile }}
secrets:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }}
PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }}
build-sc:
uses: ./.github/workflows/container-build.yml
with:
RELEASE: ui
ARCH: linux/amd64
IMAGE: scheduler
DOCKERFILE: src/scheduler/Dockerfile
secrets:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }}
PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }}
build-ui:
uses: ./.github/workflows/container-build.yml
with:
RELEASE: ui
ARCH: linux/amd64
IMAGE: ui
DOCKERFILE: src/ui/Dockerfile
secrets:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }}
PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }}
# UI tests
tests-ui:
needs: [build-bw, build-sc, build-ui]
needs: [build-containers]
uses: ./.github/workflows/tests-ui.yml
with:
RELEASE: ui
secrets:
PRIVATE_REGISTRY: ${{ secrets.PRIVATE_REGISTRY }}
PRIVATE_REGISTRY_TOKEN: ${{ secrets.PRIVATE_REGISTRY_TOKEN }}

View file

@ -102,7 +102,7 @@ A volume is needed to store the SQLite database that will be used by the schedul
```yaml
...
services:
mybunker:
bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.5.1
volumes:
- bw-data:/data

View file

@ -1475,7 +1475,7 @@ Some integrations provide more convenient ways to apply configurations, such as
default_type 'text/plain';
content_by_lua_block {
ngx.say('world')
}
}
}
...
```
@ -1509,8 +1509,8 @@ Some integrations provide more convenient ways to apply configurations, such as
When starting the scheduler container, you will need to mount the folder on /data :
```yaml
mybunker:
image: bunkerity/bunkerweb:1.5.1
bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.5.1
volumes:
- ./bw-data:/data
...
@ -1545,7 +1545,8 @@ Some integrations provide more convenient ways to apply configurations, such as
default_type 'text/plain';
content_by_lua_block {
ngx.say('world')
}
}
}
...
```
@ -1578,7 +1579,7 @@ Some integrations provide more convenient ways to apply configurations, such as
When starting the scheduler container, you will need to mount the folder on /data :
```yaml
myautoconf:
bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.5.1
volumes:
- ./bw-data:/data

View file

@ -90,7 +90,7 @@ function start() {
# Create dummy variables.env
if [ ! -f /etc/bunkerweb/variables.env ]; then
sudo -E -u nginx -g nginx /bin/bash -c "echo -ne '# remove IS_LOADING=yes when your config is ready\nIS_LOADING=yes\nDNS_RESOLVERS=8.8.8.8 8.8.4.4\nHTTP_PORT=80\nHTTPS_PORT=443\nAPI_LISTEN_IP=127.0.0.1\nSERVER_NAME=\n' > /etc/bunkerweb/variables.env"
sudo -E -u nginx -g nginx /bin/bash -c "echo -ne '# remove IS_LOADING=yes when your config is ready\nIS_LOADING=yes\nUSE_BUNKERNET=no\nDNS_RESOLVERS=8.8.8.8 8.8.4.4\nHTTP_PORT=80\nHTTPS_PORT=443\nAPI_LISTEN_IP=127.0.0.1\nSERVER_NAME=\n' > /etc/bunkerweb/variables.env"
log "SYSTEMCTL" "" "Created dummy variables.env file"
fi

View file

@ -242,6 +242,10 @@ app.jinja_env.globals.update(check_settings=check_settings)
csrf = CSRFProtect()
csrf.init_app(app)
LOG_RX = re_compile(
r"^(?P<date>\d+/\d+/\d+\s\d+:\d+:\d+)\s\[(?P<level>[a-z]+)\]\s\d+#\d+:\s(?P<message>[^\n]+)$"
)
def manage_bunkerweb(method: str, *args, operation: str = "reloads"):
# Do the operation
@ -537,11 +541,11 @@ def services():
message = ""
if request.form["operation"] == "new":
message = f"Creating service {variables['SERVER_NAME'].split(' ')[0]}"
message = f"Creating service {variables.get('SERVER_NAME', '').split(' ')[0]}"
elif request.form["operation"] == "edit":
message = f"Saving configuration for service {request.form['OLD_SERVER_NAME'].split(' ')[0]}"
message = f"Saving configuration for service {request.form.get('OLD_SERVER_NAME', '').split(' ')[0]}"
elif request.form["operation"] == "delete":
message = f"Deleting service {request.form['SERVER_NAME'].split(' ')[0]}"
message = f"Deleting service {request.form.get('SERVER_NAME', '').split(' ')[0]}"
return redirect(url_for("loading", next=url_for("services"), message=message))
@ -724,7 +728,7 @@ def configs():
join(sep, "etc", "bunkerweb", "configs"),
db_data=db.get_custom_configs(),
services=app.config["CONFIG"]
.get_config(methods=False)["SERVER_NAME"]
.get_config(methods=False).get("SERVER_NAME", "")
.split(" "),
)
],
@ -1170,7 +1174,7 @@ def cache():
is_cache=True,
db_data=db.get_jobs_cache_files(),
services=app.config["CONFIG"]
.get_config(methods=False)["SERVER_NAME"]
.get_config(methods=False).get("SERVER_NAME", "")
.split(" "),
)
],
@ -1202,22 +1206,9 @@ def logs_linux():
404,
)
last_update = request.args.get("last_update")
raw_logs_access = []
raw_logs_error = []
nginx_error_file = Path(sep, "var", "log", "nginx", "error.log")
if nginx_error_file.is_file():
raw_logs_access = nginx_error_file.read_text(encoding="utf-8").splitlines()[
int(last_update.split(".")[0]) if last_update else 0 :
]
nginx_access_file = Path(sep, "var", "log", "nginx", "access.log")
if nginx_access_file.is_file():
raw_logs_error = nginx_access_file.read_text(encoding="utf-8").splitlines()[
int(last_update.split(".")[1]) if last_update else 0 :
]
last_update = request.args.get("last_update", "0.0")
from_date = request.args.get("from_date", None)
to_date = request.args.get("to_date", None)
logs_error = []
temp_multiple_lines = []
NGINX_LOG_LEVELS = [
@ -1230,44 +1221,69 @@ def logs_linux():
"alert",
"emerg",
]
for line in raw_logs_error:
line_lower = line.lower()
if (
("[info]" in line_lower or "" in line_lower)
and line.endswith(":")
or ("[error]" in line_lower or "" in line_lower)
):
if temp_multiple_lines:
logs_error.append("\n".join(temp_multiple_lines))
nginx_error_file = Path(sep, "var", "log", "bunkerweb", "error.log")
if nginx_error_file.is_file():
with open(nginx_error_file, encoding="utf-8") as f:
for line in f.readlines()[
int(last_update.split(".")[0]) if last_update else 0 :
]:
match = LOG_RX.search(line)
if not match:
continue
date = match.group("date")
level = match.group("level")
temp_multiple_lines = [
f"{datetime.strptime(' '.join(line.strip().split(' ')[0:2]), '%Y/%m/%d %H:%M:%S').replace(tzinfo=timezone.utc).timestamp()} {line}"
]
elif (
all(f"[{log_level}]" not in line_lower for log_level in NGINX_LOG_LEVELS)
and temp_multiple_lines
):
temp_multiple_lines.append(line)
else:
logs_error.append(
f"{datetime.strptime(' '.join(line.strip().split(' ')[0:2]), '%Y/%m/%d %H:%M:%S').replace(tzinfo=timezone.utc).timestamp()} {line}"
)
if not date:
if logs_error:
logs_error[-1] += f"\n{line}"
continue
logs_error.append(line)
elif (
all(f"[{log_level}]" != level for log_level in NGINX_LOG_LEVELS)
and temp_multiple_lines
):
temp_multiple_lines.append(line)
else:
logs_error.append(
f"{datetime.strptime(date, '%Y/%m/%d %H:%M:%S').replace(tzinfo=timezone.utc).timestamp()} {line}"
)
if temp_multiple_lines:
logs_error.append("\n".join(temp_multiple_lines))
logs_access = [
f"{datetime.strptime(line[line.find('[') + 1: line.find(']')], '%d/%b/%Y:%H:%M:%S %z').timestamp()} {line}"
for line in raw_logs_access
]
logs_access = []
nginx_access_file = Path(sep, "var", "log", "bunkerweb", "access.log")
if nginx_access_file.is_file():
with open(nginx_access_file, encoding="utf-8") as f:
for line in f.readlines()[
int(last_update.split(".")[1]) if last_update else 0 :
]:
logs_access.append(
f"{datetime.strptime(line[line.find('[') + 1: line.find(']')], '%d/%b/%Y:%H:%M:%S %z').replace(tzinfo=timezone.utc).timestamp()} {line}"
)
raw_logs = logs_error + logs_access
raw_logs.sort(
key=lambda x: float(x.split(" ")[0]) if x.split(" ")[0].isdigit() else 0
)
if from_date and from_date.isdigit():
from_date = int(from_date) // 1000
else:
from_date = 0
if to_date and to_date.isdigit():
to_date = int(to_date) // 1000
else:
to_date = None
def date_filter(log: str):
log_date = log.split(" ")[0]
log_date = float(log_date) if regex_match(r"^\d+\.\d+$", log_date) else 0
if to_date is not None and log_date > int(to_date):
return False
return log_date > from_date
logs = []
for log in raw_logs:
for log in filter(date_filter, raw_logs):
if "[48;2" in log or not log.strip():
continue

View file

@ -1,84 +0,0 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.default = {}));
}(this, (function (exports) { 'use strict';
var english = {
weekdays: {
shorthand: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
longhand: [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
],
},
months: {
shorthand: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
],
longhand: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
],
},
daysInMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
firstDayOfWeek: 0,
ordinal: function (nth) {
var s = nth % 100;
if (s > 3 && s < 21)
return "th";
switch (s % 10) {
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
},
rangeSeparator: " to ",
weekAbbreviation: "Wk",
scrollTitle: "Scroll to increment",
toggleTitle: "Click to toggle",
amPM: ["AM", "PM"],
yearAriaLabel: "Year",
monthAriaLabel: "Month",
hourAriaLabel: "Hour",
minuteAriaLabel: "Minute",
time_24hr: false,
};
exports.default = english;
exports.english = english;
Object.defineProperty(exports, '__esModule', { value: true });
})));

View file

@ -33,12 +33,8 @@
{% elif current_endpoint == "logs" %}
<link rel="stylesheet" type="text/css" href="./css/flatpickr.css" />
<link rel="stylesheet" type="text/css" href="./css/flatpickr.dark.css" />
<script type="module" src="./js/utils/flatpickr.js"></script>
<script type="module" src="./js/utils/fr.js"></script>
<script type="module" src="./js/logs.js"></script>
<script type="module" src="./js/datepicker/datepicker.js"></script>
<link
rel="stylesheet"
type="text/css"