feat: 自动生成fluent bit配置文件创建data view
This commit is contained in:
parent
b9af54bba5
commit
f87bc045ad
@ -4,6 +4,7 @@
|
|||||||
支持配置文件变更检测和Fluent Bit热重启
|
支持配置文件变更检测和Fluent Bit热重启
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
@ -30,7 +31,7 @@ class KibanaDataViewManager:
|
|||||||
"""Kibana Data View 管理器"""
|
"""Kibana Data View 管理器"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.kibana_host = os.environ.get("KIBANA_HOST", "localhost")
|
self.kibana_host = os.environ.get("KIBANA_HOST", "kibana")
|
||||||
self.kibana_port = os.environ.get("KIBANA_PORT", "5601")
|
self.kibana_port = os.environ.get("KIBANA_PORT", "5601")
|
||||||
self.kibana_user = os.environ.get("KIBANA_USER", "elastic")
|
self.kibana_user = os.environ.get("KIBANA_USER", "elastic")
|
||||||
self.kibana_password = os.environ.get("KIBANA_PASSWORD", "")
|
self.kibana_password = os.environ.get("KIBANA_PASSWORD", "")
|
||||||
@ -100,7 +101,8 @@ class KibanaDataViewManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data_views = response.json()
|
response_data = response.json()
|
||||||
|
data_views = response_data.get("data_view", [])
|
||||||
logger.info(f"获取到 {len(data_views)} 个Data View")
|
logger.info(f"获取到 {len(data_views)} 个Data View")
|
||||||
return data_views
|
return data_views
|
||||||
else:
|
else:
|
||||||
@ -138,14 +140,7 @@ class KibanaDataViewManager:
|
|||||||
"data_view": {
|
"data_view": {
|
||||||
"title": self.data_view_pattern,
|
"title": self.data_view_pattern,
|
||||||
"name": self.data_view_name,
|
"name": self.data_view_name,
|
||||||
"timeFieldName": "@timestamp",
|
"timeFieldName": "@timestamp"
|
||||||
"allowNoIndex": True, # 允许不存在索引
|
|
||||||
"allowHidden": False,
|
|
||||||
"namespace": "default",
|
|
||||||
"fieldFormats": {},
|
|
||||||
"runtimeFieldMap": {},
|
|
||||||
"fieldAttrs": {},
|
|
||||||
"allowHidden": False
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,60 +186,6 @@ class KibanaDataViewManager:
|
|||||||
logger.warning(f"检查索引存在失败: {e}")
|
logger.warning(f"检查索引存在失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_default_data_view(self):
|
|
||||||
"""设置为默认Data View(可选)"""
|
|
||||||
try:
|
|
||||||
# 首先获取Data View的ID
|
|
||||||
url = f"{self.base_url}/api/data_views"
|
|
||||||
response = requests.get(
|
|
||||||
url,
|
|
||||||
auth=self.auth,
|
|
||||||
timeout=self.timeout,
|
|
||||||
headers=self._get_headers()
|
|
||||||
)
|
|
||||||
|
|
||||||
if response.status_code != 200:
|
|
||||||
return False
|
|
||||||
|
|
||||||
data_views = response.json()
|
|
||||||
data_view_id = None
|
|
||||||
|
|
||||||
for dv in data_views:
|
|
||||||
if dv.get("name") == self.data_view_name:
|
|
||||||
data_view_id = dv.get("id")
|
|
||||||
break
|
|
||||||
|
|
||||||
if not data_view_id:
|
|
||||||
logger.warning(f"未找到Data View: {self.data_view_name}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 更新为默认Data View
|
|
||||||
update_url = f"{self.base_url}/api/data_views/data_view/{data_view_id}"
|
|
||||||
update_data = {
|
|
||||||
"data_view": {
|
|
||||||
"name": self.data_view_name,
|
|
||||||
"isDefault": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.patch(
|
|
||||||
update_url,
|
|
||||||
auth=self.auth,
|
|
||||||
json=update_data,
|
|
||||||
timeout=self.timeout,
|
|
||||||
headers=self._get_headers()
|
|
||||||
)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
logger.info(f"成功将 '{self.data_view_name}' 设置为默认Data View")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
logger.warning(f"设置默认Data View失败: {response.status_code}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"设置默认Data View异常: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def manage_data_view(self):
|
def manage_data_view(self):
|
||||||
"""管理Data View:检查并创建"""
|
"""管理Data View:检查并创建"""
|
||||||
@ -265,12 +206,6 @@ class KibanaDataViewManager:
|
|||||||
if self.create_data_view():
|
if self.create_data_view():
|
||||||
logger.info(f"Data View '{self.data_view_name}' 创建成功")
|
logger.info(f"Data View '{self.data_view_name}' 创建成功")
|
||||||
|
|
||||||
# 可选:设置为默认Data View
|
|
||||||
try:
|
|
||||||
self.set_default_data_view()
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"设置默认Data View失败: {e}")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.error(f"Data View '{self.data_view_name}' 创建失败")
|
logger.error(f"Data View '{self.data_view_name}' 创建失败")
|
||||||
@ -285,13 +220,13 @@ class ConfigGenerator:
|
|||||||
self.fb_user = self._get_fb_user()
|
self.fb_user = self._get_fb_user()
|
||||||
|
|
||||||
# 基础路径
|
# 基础路径
|
||||||
self.base_path = Path("private/argus/agent")
|
self.base_path = Path("/private/argus/agent")
|
||||||
self.inputs_dir = Path("/etc/fluent-bit/inputs.d")
|
self.inputs_dir = Path("/etc/fluent-bit/inputs.d")
|
||||||
self.outputs_dir = Path("/etc/fluent-bit/outputs.d")
|
self.outputs_dir = Path("/etc/fluent-bit/outputs.d")
|
||||||
|
|
||||||
# 配置文件路径
|
# 配置文件路径
|
||||||
self.config_file = self.base_path / self.hostname / "node.json"
|
self.config_file = self.base_path / self.hostname / "node.json"
|
||||||
|
# 配置文件hash值,校验配置是否发生变更
|
||||||
hash_file = self.base_path / self.hostname / "node_json_hash.txt"
|
hash_file = self.base_path / self.hostname / "node_json_hash.txt"
|
||||||
|
|
||||||
# 配置文件哈希值存储文件
|
# 配置文件哈希值存储文件
|
||||||
@ -622,16 +557,17 @@ class ConfigGenerator:
|
|||||||
|
|
||||||
logger.info(f"生成 {len(input_files)} 个input配置,{len(output_files)} 个output配置")
|
logger.info(f"生成 {len(input_files)} 个input配置,{len(output_files)} 个output配置")
|
||||||
|
|
||||||
# 5. 重新加载Fluent Bit
|
# 重新加载Fluent Bit
|
||||||
logger.info("配置文件已更新,重新加载Fluent Bit...")
|
logger.info("配置文件已更新,重新加载Fluent Bit...")
|
||||||
if self._reload_fluentbit():
|
if self._reload_fluentbit():
|
||||||
logger.info("Fluent Bit重载成功")
|
logger.info("Fluent Bit重载成功")
|
||||||
|
|
||||||
logger.info("开始管理Kibana Data View...")
|
|
||||||
self.kibana_manager.manage_data_view()
|
|
||||||
else:
|
else:
|
||||||
logger.warning("Fluent Bit重载失败,但配置文件已更新")
|
logger.warning("Fluent Bit重载失败,但配置文件已更新")
|
||||||
|
|
||||||
|
# 不论配置是否变更,每次执行都检查custom视图是否存在,避免视图创建失败后,若配置不再变更则无法创建
|
||||||
|
# 检查kibana data view 并进行创建data view
|
||||||
|
logger.info("开始管理Kibana Data View...")
|
||||||
|
self.kibana_manager.manage_data_view()
|
||||||
|
|
||||||
logger.info("任务完成")
|
logger.info("任务完成")
|
||||||
return True
|
return True
|
||||||
@ -672,7 +608,7 @@ class Scheduler:
|
|||||||
# 等待到下次执行时间
|
# 等待到下次执行时间
|
||||||
logger.info(f"下次执行时间: {next_time_str}")
|
logger.info(f"下次执行时间: {next_time_str}")
|
||||||
|
|
||||||
# 使用递减等待,以便可以响应停止信号
|
# 使用递减等待
|
||||||
for _ in range(self.interval_seconds):
|
for _ in range(self.interval_seconds):
|
||||||
if not self.running:
|
if not self.running:
|
||||||
break
|
break
|
||||||
@ -690,7 +626,7 @@ class Scheduler:
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# 定时调度
|
# 定时调度,设置调度周期
|
||||||
scheduler = Scheduler(3600)
|
scheduler = Scheduler(3600)
|
||||||
|
|
||||||
# 启动调度器
|
# 启动调度器
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[SERVICE]
|
[SERVICE]
|
||||||
Daemon Off
|
Daemon Off
|
||||||
Parsers_File parsers.conf
|
Parsers_File /etc/fluent-bit/parsers.conf
|
||||||
HTTP_Server On
|
HTTP_Server On
|
||||||
HTTP_Listen 0.0.0.0
|
HTTP_Listen 0.0.0.0
|
||||||
HTTP_Port 2020
|
HTTP_Port 2020
|
||||||
@ -33,7 +33,7 @@
|
|||||||
[FILTER]
|
[FILTER]
|
||||||
Name lua
|
Name lua
|
||||||
Match app.*
|
Match app.*
|
||||||
script inject_labels.lua
|
script /etc/fluent-bit/inject_labels.lua
|
||||||
call add_labels
|
call add_labels
|
||||||
|
|
||||||
@INCLUDE outputs.d/*.conf
|
@INCLUDE outputs.d/*.conf
|
||||||
|
|||||||
@ -69,10 +69,6 @@ if [[ -n "$MISSING" ]]; then
|
|||||||
apt-get install -f -y -qq || true
|
apt-get install -f -y -qq || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 安装 Python
|
|
||||||
apt-get install -y python3 python3-pip
|
|
||||||
pip3 install pymysql pyyaml
|
|
||||||
|
|
||||||
echo "[INFO] Fluent Bit version:"
|
echo "[INFO] Fluent Bit version:"
|
||||||
/opt/fluent-bit/bin/fluent-bit --version || { echo "[ERROR] fluent-bit not installed or libraries missing" >&2; exit 1; }
|
/opt/fluent-bit/bin/fluent-bit --version || { echo "[ERROR] fluent-bit not installed or libraries missing" >&2; exit 1; }
|
||||||
|
|
||||||
@ -101,10 +97,138 @@ chmod 770 /buffers || true
|
|||||||
# 目录属主设置为 fluent-bit(不影响 1777 粘滞位)
|
# 目录属主设置为 fluent-bit(不影响 1777 粘滞位)
|
||||||
chown -R fluent-bit:fluent-bit /logs /buffers 2>/dev/null || true
|
chown -R fluent-bit:fluent-bit /logs /buffers 2>/dev/null || true
|
||||||
|
|
||||||
|
# 检查Python基础环境
|
||||||
|
echo "[INFO] Checking Python environment..."
|
||||||
|
|
||||||
|
echo "[INFO] Fixing broken dependencies..."
|
||||||
|
apt-get -f install -y -qq 2>/dev/null || true
|
||||||
|
|
||||||
|
# 检查python3是否安装
|
||||||
|
if ! command -v python3 >/dev/null 2>&1; then
|
||||||
|
echo "[INFO] Installing python3..."
|
||||||
|
apt-get update -qq || true
|
||||||
|
# 尝试安装最小化的python3(不安装推荐包,减少依赖冲突)
|
||||||
|
apt-get install -y -qq --no-install-recommends python3-minimal 2>/dev/null || {
|
||||||
|
echo "[WARN] Failed to install python3 via apt, trying alternative approach..."
|
||||||
|
|
||||||
|
# 如果apt安装失败,检查是否已有python3二进制文件
|
||||||
|
if [ -f /usr/bin/python3 ] && python3 --version 2>/dev/null; then
|
||||||
|
echo "[INFO] Python3 binary exists but not in PATH"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查pip是否可用
|
||||||
|
if ! command -v pip3 >/dev/null 2>&1; then
|
||||||
|
# 尝试安装pip
|
||||||
|
echo "[INFO] Installing pip..."
|
||||||
|
apt-get update -qq || true
|
||||||
|
apt-get install -y -qq python3-pip 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查Python脚本依赖的包
|
||||||
|
check_python_packages() {
|
||||||
|
local missing_packages=""
|
||||||
|
|
||||||
|
# 根据脚本内容确定需要的包
|
||||||
|
local required_packages=(
|
||||||
|
"requests" # HTTP请求库(脚本中最关键的依赖)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 检查requests是否安装(必须)
|
||||||
|
if ! python3 -c "import requests" 2>/dev/null; then
|
||||||
|
echo "[WARN] 'requests' package not found, installing..."
|
||||||
|
if command -v pip3 >/dev/null 2>&1; then
|
||||||
|
# 尝试使用清华镜像源
|
||||||
|
PIP_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||||
|
echo "[INFO] Installing requests using pip with mirror..."
|
||||||
|
pip3 install --no-cache-dir --index-url "$PIP_INDEX_URL" requests 2>/dev/null || {
|
||||||
|
# 如果镜像失败,尝试官方源
|
||||||
|
echo "[INFO] Trying official PyPI source..."
|
||||||
|
pip3 install --no-cache-dir requests 2>/dev/null || {
|
||||||
|
echo "[ERROR] Failed to install requests via pip"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo "[ERROR] pip3 not available, cannot install requests"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查其他必需包
|
||||||
|
for pkg in "${required_packages[@]}"; do
|
||||||
|
if ! python3 -c "import $pkg" 2>/dev/null; then
|
||||||
|
missing_packages="$missing_packages $pkg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$missing_packages"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 安装Python包依赖
|
||||||
|
echo "[INFO] Installing Python package dependencies..."
|
||||||
|
missing_py_deps=$(check_python_packages)
|
||||||
|
|
||||||
|
if [[ -n "$missing_py_deps" ]]; then
|
||||||
|
echo "[INFO] Installing missing Python packages:$missing_py_deps"
|
||||||
|
# 如果还有缺失的包,尝试安装
|
||||||
|
if command -v pip3 >/dev/null 2>&1; then
|
||||||
|
for pkg in $missing_py_deps; do
|
||||||
|
pip3 install --no-cache-dir "$pkg" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 验证Python脚本依赖
|
||||||
|
echo "[INFO] Verifying Python dependencies..."
|
||||||
|
if python3 -c "import requests; import json; import time; import logging; import hashlib; import subprocess; from datetime import datetime; from pathlib import Path; import re; import socket; print('All required modules imported successfully')" 2>/dev/null; then
|
||||||
|
echo "[INFO] Python dependencies verified successfully"
|
||||||
|
else
|
||||||
|
echo "[WARN] Some Python modules may be missing"
|
||||||
|
# 尝试查看具体缺少什么
|
||||||
|
python3 -c "
|
||||||
|
import sys
|
||||||
|
modules = ['requests', 'json', 'time', 'logging', 'hashlib', 'subprocess', 'datetime', 'pathlib', 're', 'socket']
|
||||||
|
missing = []
|
||||||
|
for module in modules:
|
||||||
|
try:
|
||||||
|
__import__(module)
|
||||||
|
print(f'✓ {module}')
|
||||||
|
except ImportError as e:
|
||||||
|
print(f'✗ {module}: {e}')
|
||||||
|
missing.append(module)
|
||||||
|
if missing:
|
||||||
|
sys.exit(1)
|
||||||
|
" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 查找并运行Python脚本
|
||||||
|
echo "[INFO] Looking for Python configuration generator script..."
|
||||||
|
PYTHON_SCRIPT="/etc/fluent-bit/app/update_fluent_config.py"
|
||||||
|
|
||||||
|
if [ -f "$PYTHON_SCRIPT" ]; then
|
||||||
|
echo "[INFO] Found Python script: $PYTHON_SCRIPT"
|
||||||
|
|
||||||
|
# 检查脚本是否可执行,如果不可执行则添加执行权限
|
||||||
|
if [ ! -x "$PYTHON_SCRIPT" ]; then
|
||||||
|
echo "[INFO] Adding execute permission to Python script..."
|
||||||
|
chmod +x "$PYTHON_SCRIPT" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 运行Python脚本(后台运行)
|
||||||
|
echo "[INFO] Starting configuration generator script..."
|
||||||
|
python3 "$PYTHON_SCRIPT" &
|
||||||
|
CONFIG_GEN_PID=$!
|
||||||
|
echo "[INFO] Configuration generator started with PID: $CONFIG_GEN_PID"
|
||||||
|
else
|
||||||
|
echo "[WARN] Python configuration generator script not found"
|
||||||
|
fi
|
||||||
|
|
||||||
# Wait for Elasticsearch via bash /dev/tcp to avoid curl dependency
|
# Wait for Elasticsearch via bash /dev/tcp to avoid curl dependency
|
||||||
echo "[INFO] Waiting for Elasticsearch to be ready (tcp ${ES_HOST}:${ES_PORT})..."
|
echo "[INFO] Waiting for Elasticsearch to be ready (tcp ${ES_HOST}:${ES_PORT})..."
|
||||||
for i in $(seq 1 120); do
|
for i in $(seq 1 120); do
|
||||||
if exec 3<>/dev/tcp/${ES_HOST}/${ES_PORT}; then
|
if exec 3<>/dev/tcp/${ES_HOST}/${ES_PORT} 2>/dev/null; then
|
||||||
exec 3<&- 3>&-
|
exec 3<&- 3>&-
|
||||||
echo "[INFO] Elasticsearch is ready"
|
echo "[INFO] Elasticsearch is ready"
|
||||||
break
|
break
|
||||||
@ -115,8 +239,8 @@ done
|
|||||||
|
|
||||||
echo "[INFO] Command: starting python task..."
|
echo "[INFO] Command: starting python task..."
|
||||||
# 启动配置生成器
|
# 启动配置生成器
|
||||||
exec nohup python3 /etc/fluent-bit/app/update_fluent_config.py &
|
#exec nohup python3 /etc/fluent-bit/app/update_fluent_config.py &
|
||||||
|
|
||||||
echo "[INFO] Starting Fluent Bit with configuration from /etc/fluent-bit/"
|
echo "[INFO] Starting Fluent Bit with configuration from /etc/fluent-bit/"
|
||||||
echo "[INFO] Command: /opt/fluent-bit/bin/fluent-bit --config=/etc/fluent-bit/fluent-bit.conf"
|
echo "[INFO] Command: /opt/fluent-bit/bin/fluent-bit --config=/etc/fluent-bit/fluent-bit.conf"
|
||||||
exec /opt/fluent-bit/bin/fluent-bit --config=/etc/fluent-bit/fluent-bit.conf
|
exec /opt/fluent-bit/bin/fluent-bit --config=/etc/fluent-bit/fluent-bit.conf
|
||||||
Loading…
x
Reference in New Issue
Block a user