Compare commits
10 Commits
491b2265d2
...
f55deb0b67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f55deb0b67 | ||
|
|
b7bf85593f | ||
|
|
ebfe98f87e | ||
| 5eeb9deae4 | |||
|
|
ec0420439d | ||
|
|
13467b75d2 | ||
|
|
f8dbe17c6a | ||
|
|
d422735062 | ||
|
|
50ca69c958 | ||
|
|
d0b379eab1 |
52
data/etcd/etc/etcd.conf
Normal file
52
data/etcd/etc/etcd.conf
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# [member]
|
||||||
|
ETCD_NAME=default
|
||||||
|
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
|
||||||
|
#ETCD_WAL_DIR=""
|
||||||
|
ETCD_SNAPSHOT_COUNT="10000"
|
||||||
|
#ETCD_HEARTBEAT_INTERVAL="100"
|
||||||
|
#ETCD_ELECTION_TIMEOUT="1000"
|
||||||
|
#ETCD_LISTEN_PEER_URLS="http://localhost:2380"
|
||||||
|
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"
|
||||||
|
#ETCD_MAX_SNAPSHOTS="5"
|
||||||
|
#ETCD_MAX_WALS="5"
|
||||||
|
#ETCD_CORS=""
|
||||||
|
|
||||||
|
#
|
||||||
|
#[cluster]
|
||||||
|
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
|
||||||
|
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."
|
||||||
|
#ETCD_INITIAL_CLUSTER="default=http://localhost:2380"
|
||||||
|
#ETCD_INITIAL_CLUSTER_STATE="new"
|
||||||
|
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
|
||||||
|
ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"
|
||||||
|
#ETCD_DISCOVERY=""
|
||||||
|
#ETCD_DISCOVERY_SRV=""
|
||||||
|
#ETCD_DISCOVERY_FALLBACK="proxy"
|
||||||
|
#ETCD_DISCOVERY_PROXY=""
|
||||||
|
#ETCD_STRICT_RECONFIG_CHECK="false"
|
||||||
|
#ETCD_AUTO_COMPACTION_RETENTION="0"
|
||||||
|
#
|
||||||
|
#[proxy]
|
||||||
|
#ETCD_PROXY="off"
|
||||||
|
#ETCD_PROXY_FAILURE_WAIT="5000"
|
||||||
|
#ETCD_PROXY_REFRESH_INTERVAL="30000"
|
||||||
|
#ETCD_PROXY_DIAL_TIMEOUT="1000"
|
||||||
|
#ETCD_PROXY_WRITE_TIMEOUT="5000"
|
||||||
|
#ETCD_PROXY_READ_TIMEOUT="0"
|
||||||
|
#
|
||||||
|
#[security]
|
||||||
|
#ETCD_CERT_FILE=""
|
||||||
|
#ETCD_KEY_FILE=""
|
||||||
|
#ETCD_CLIENT_CERT_AUTH="false"
|
||||||
|
#ETCD_TRUSTED_CA_FILE=""
|
||||||
|
#ETCD_AUTO_TLS="false"
|
||||||
|
#ETCD_PEER_CERT_FILE=""
|
||||||
|
#ETCD_PEER_KEY_FILE=""
|
||||||
|
#ETCD_PEER_CLIENT_CERT_AUTH="false"
|
||||||
|
#ETCD_PEER_TRUSTED_CA_FILE=""
|
||||||
|
#ETCD_PEER_AUTO_TLS="false"
|
||||||
|
#
|
||||||
|
#[logging]
|
||||||
|
#ETCD_DEBUG="false"
|
||||||
|
# examples for -log-package-levels etcdserver=WARNING,security=DEBUG
|
||||||
|
#ETCD_LOG_PACKAGE_LEVELS=""
|
||||||
13
data/prometheus/etc/prometheus/prometheus.yml
Normal file
13
data/prometheus/etc/prometheus/prometheus.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: 'node_exporter'
|
||||||
|
scrape_interval: 10s
|
||||||
|
static_configs:
|
||||||
|
- targets: [ '127.0.0.1:9100' ]
|
||||||
|
|
||||||
|
- job_name: 'opcua_exporter'
|
||||||
|
scrape_interval: 10s
|
||||||
|
static_configs:
|
||||||
|
- targets: [ '127.0.0.1:8191' ]
|
||||||
20
data/prometheus/etc/supervisord/supervisord.conf
Normal file
20
data/prometheus/etc/supervisord/supervisord.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true ; 让 supervisor 运行在前台,保持容器不退出
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:confd]
|
||||||
|
command=/usr/local/bin/confd -config-file /etc/confd/confd.toml
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stderr_logfile=/var/log/confd.err.log
|
||||||
|
stdout_logfile=/var/log/confd.out.log
|
||||||
|
|
||||||
|
[program:prometheus]
|
||||||
|
command=/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stderr_logfile=/var/log/prometheus.err.log
|
||||||
|
stdout_logfile=/var/log/prometheus.out.log
|
||||||
|
|
||||||
|
|
||||||
@@ -5,8 +5,14 @@ services:
|
|||||||
- 2379:2379
|
- 2379:2379
|
||||||
- 2380:2370
|
- 2380:2370
|
||||||
network_mode: host
|
network_mode: host
|
||||||
|
volumes:
|
||||||
|
- ./data/etcd/data:/var/lib/etcd
|
||||||
|
- ./data/etcd/etc:/etc/etcd
|
||||||
prometheus:
|
prometheus:
|
||||||
build: docker/prometheus
|
build: docker/prometheus
|
||||||
|
volumes:
|
||||||
|
- ./data/prometheus/etc/prometheus:/etc/prometheus
|
||||||
|
- ./data/prometheus/etc/supervisord:/etc/supervisord
|
||||||
ports:
|
ports:
|
||||||
- 9090:9090
|
- 9090:9090
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -14,8 +20,9 @@ services:
|
|||||||
network_mode: host
|
network_mode: host
|
||||||
panel:
|
panel:
|
||||||
build: management-panel
|
build: management-panel
|
||||||
# volumes:
|
volumes:
|
||||||
# - ./management-panel:/app
|
- ./data/panel/storage/app:/app/storage/app
|
||||||
|
- /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
|
||||||
entrypoint: /app/entrypoint.sh
|
entrypoint: /app/entrypoint.sh
|
||||||
command: php artisan octane:start --server=swoole --workers=4 --host=0.0.0.0 --port=8000
|
command: php artisan octane:start --server=swoole --workers=4 --host=0.0.0.0 --port=8000
|
||||||
ports:
|
ports:
|
||||||
@@ -25,6 +32,7 @@ services:
|
|||||||
- prometheus
|
- prometheus
|
||||||
restart: always
|
restart: always
|
||||||
network_mode: host
|
network_mode: host
|
||||||
|
privileged: true
|
||||||
node-exporter:
|
node-exporter:
|
||||||
build: docker/node_exporter
|
build: docker/node_exporter
|
||||||
# privileged: true
|
# privileged: true
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ RUN dnf update -y \
|
|||||||
|
|
||||||
# 设置环境变量
|
# 设置环境变量
|
||||||
ENV ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" \
|
ENV ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" \
|
||||||
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379"
|
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379" \
|
||||||
|
ETCD_DATA_DIR=/var/lib/etcd/
|
||||||
|
|
||||||
# 暴露端口
|
# 暴露端口
|
||||||
EXPOSE 2379 2380
|
EXPOSE 2379 2380
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ keys = [
|
|||||||
"/time/",
|
"/time/",
|
||||||
"/remote_write/",
|
"/remote_write/",
|
||||||
]
|
]
|
||||||
|
reload_cmd = "pkill -9 -f '/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml'"
|
||||||
@@ -4,3 +4,4 @@ dest = "/etc/supervisord/supervisord.conf"
|
|||||||
keys = [
|
keys = [
|
||||||
"/time/"
|
"/time/"
|
||||||
]
|
]
|
||||||
|
reload_cmd = "pkill -9 -f '/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml'"
|
||||||
@@ -11,6 +11,15 @@ scrape_configs:
|
|||||||
scrape_interval: {{ getv "/time/opcua_scrape_interval"}}{{ getv "/time/opcua_scrape_interval_unit" }}
|
scrape_interval: {{ getv "/time/opcua_scrape_interval"}}{{ getv "/time/opcua_scrape_interval_unit" }}
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets: [ '127.0.0.1:8191' ]
|
- targets: [ '127.0.0.1:8191' ]
|
||||||
|
labels:
|
||||||
|
__hostname__: {{ getv "/remote_write/data_source_label" }}
|
||||||
|
relabel_configs:
|
||||||
|
- source_labels:
|
||||||
|
- "__hostname__"
|
||||||
|
regex: (.*)
|
||||||
|
target_label: source
|
||||||
|
action: replace
|
||||||
|
replacement: {{ getv "/remote_write/data_source_label" }}
|
||||||
{{ if getv "/remote_write/state" }}
|
{{ if getv "/remote_write/state" }}
|
||||||
remote_write:
|
remote_write:
|
||||||
- url: {{ getv "/remote_write/url" }}
|
- url: {{ getv "/remote_write/url" }}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ stderr_logfile=/var/log/confd.err.log
|
|||||||
stdout_logfile=/var/log/confd.out.log
|
stdout_logfile=/var/log/confd.out.log
|
||||||
|
|
||||||
[program:prometheus]
|
[program:prometheus]
|
||||||
command=/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.retention.time={{ getv "/time/storage_interval"}}{{ getv "/time/storage_interval_unit")}}
|
command=/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.retention.time={{ getv "/time/storage_interval"}}{{ getv "/time/storage_interval_unit"}}
|
||||||
autostart=true
|
autostart=true
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stderr_logfile=/var/log/prometheus.err.log
|
stderr_logfile=/var/log/prometheus.err.log
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ LOG_DEPRECATIONS_CHANNEL=null
|
|||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
DB_CONNECTION=sqlite
|
DB_CONNECTION=sqlite
|
||||||
|
DB_DATABASE=/app/storage/app/database.sqlite
|
||||||
# DB_HOST=127.0.0.1
|
# DB_HOST=127.0.0.1
|
||||||
# DB_PORT=3306
|
# DB_PORT=3306
|
||||||
# DB_DATABASE=laravel
|
# DB_DATABASE=laravel
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ use App\Services\NetworkService;
|
|||||||
use App\Settings\NetworkSettings;
|
use App\Settings\NetworkSettings;
|
||||||
use Filament\Forms;
|
use Filament\Forms;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Pages\SettingsPage;
|
use Filament\Pages\SettingsPage;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Forms\Components\Select;
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Components\Fieldset;
|
use Filament\Forms\Components\Fieldset;
|
||||||
|
use Filament\Forms\Components\TagsInput;
|
||||||
|
|
||||||
class ManageNetwork extends SettingsPage
|
class ManageNetwork extends SettingsPage
|
||||||
{
|
{
|
||||||
@@ -39,12 +41,21 @@ class ManageNetwork extends SettingsPage
|
|||||||
|
|
||||||
// 当选择框的值更新时,自动填充对应的网络信息
|
// 当选择框的值更新时,自动填充对应的网络信息
|
||||||
if (isset($interfaces[$state])) {
|
if (isset($interfaces[$state])) {
|
||||||
|
$dhcp_status = NetworkService::getDHCPstatus($state);
|
||||||
|
$set('dhcp_enabled', $dhcp_status ? 'true':'false');
|
||||||
$set('ip', $interfaces[$state]['ip'] ?? '无IP地址');
|
$set('ip', $interfaces[$state]['ip'] ?? '无IP地址');
|
||||||
$set('mask', $interfaces[$state]['mask'] ?? '无子网掩码');
|
$set('mask', $interfaces[$state]['mask'] ?? '无子网掩码');
|
||||||
// 假设我们通过其他方式获取网关(如手动输入或自动获取)
|
$set('gateway', $interfaces[$state]['gateway']);
|
||||||
// $set('gateway', '自动获取或手动输入的值');
|
// $set('dns_server_1', $interfaces[$state]['dns'][0] ?? null);
|
||||||
|
// $set('dns_server_2', $interfaces[$state]['dns'][1] ??
|
||||||
|
$set('dns_servers', $interfaces[$state]['dns'] ?? []);
|
||||||
|
|
||||||
|
error_log('state:' . $state);
|
||||||
|
error_log('dhcp_enabled: ' . $dhcp_status);
|
||||||
error_log("ip " . $interfaces[$state]['ip']);
|
error_log("ip " . $interfaces[$state]['ip']);
|
||||||
error_log("mask " . $interfaces[$state]['mask']);
|
error_log("mask " . $interfaces[$state]['mask']);
|
||||||
|
error_log("gateway " . $interfaces[$state]['gateway']);
|
||||||
|
error_log("dns_servers " . print_r($interfaces[$state]['dns'], true));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
error_log("未找到接口:" . $state);
|
error_log("未找到接口:" . $state);
|
||||||
@@ -54,58 +65,194 @@ class ManageNetwork extends SettingsPage
|
|||||||
// 动态显示端口信息
|
// 动态显示端口信息
|
||||||
Fieldset::make('端口信息')
|
Fieldset::make('端口信息')
|
||||||
->schema([
|
->schema([
|
||||||
|
Select::make('dhcp_enabled')
|
||||||
|
->label('DHCP启用')
|
||||||
|
->options([
|
||||||
|
'true' => '是',
|
||||||
|
'false' => '否',
|
||||||
|
])
|
||||||
|
->reactive()
|
||||||
|
->required(), // 如果需要可以加上这个
|
||||||
TextInput::make('ip')
|
TextInput::make('ip')
|
||||||
->label("IP地址")
|
->label("IP地址")
|
||||||
->readOnly() // 禁用以表示这是自动填充的字段
|
->disabled(fn($get) => $get('dhcp_enabled') === 'true')
|
||||||
|
->required()
|
||||||
->reactive(),
|
->reactive(),
|
||||||
TextInput::make('mask')
|
Select::make('mask')
|
||||||
->label('子网掩码')
|
->label('子网掩码')
|
||||||
->readOnly()
|
->options([
|
||||||
|
8 => "255.0.0.0 /8",
|
||||||
|
9 => "255.128.0.0 /9",
|
||||||
|
10 => "255.192.0.0 /10",
|
||||||
|
11 => "255.224.0.0 /11",
|
||||||
|
12 => "255.240.0.0 /12",
|
||||||
|
13 => "255.248.0.0 /13",
|
||||||
|
14 => "255.252.0.0 /14",
|
||||||
|
15 => "255.254.0.0 /15",
|
||||||
|
16 => "255.255.0.0 /16",
|
||||||
|
17 => "255.255.128.0 /17",
|
||||||
|
18 => "255.255.192.0 /18",
|
||||||
|
19 => "255.255.224.0 /19",
|
||||||
|
20 => "255.255.240.0 /20",
|
||||||
|
21 => "255.255.248.0 /21",
|
||||||
|
22 => "255.255.252.0 /22",
|
||||||
|
23 => "255.255.254.0 /23",
|
||||||
|
24 => "255.255.255.0 /24",
|
||||||
|
25 => "255.255.255.128 /25",
|
||||||
|
26 => "255.255.255.192 /26",
|
||||||
|
27 => "255.255.255.224 /27",
|
||||||
|
28 => "255.255.255.240 /28",
|
||||||
|
29 => "255.255.255.248 /29",
|
||||||
|
30 => "255.255.255.252 /30",
|
||||||
|
31 => "255.255.255.254 /31",
|
||||||
|
32 => "255.255.255.255 /32",
|
||||||
|
])
|
||||||
|
->required()
|
||||||
|
->disabled(fn($get) => $get('dhcp_enabled') === 'true')
|
||||||
->reactive(),
|
->reactive(),
|
||||||
|
TextInput::make('gateway')
|
||||||
|
->label('网关')
|
||||||
|
->disabled(fn($get) => $get('dhcp_enabled') === 'true'),
|
||||||
|
TagsInput::make('dns_servers')
|
||||||
|
->label('DNS地址')
|
||||||
|
->disabled(fn($get) => $get('dhcp_enabled') === 'true')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(function ($state, callable $set) {
|
||||||
|
// 保留合法的DNS地址
|
||||||
|
$validDns = array_filter($state, function ($dns) {
|
||||||
|
// 验证是否是合法的IPv4地址
|
||||||
|
return filter_var($dns, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果有非法的DNS地址,显示提示并移除它们
|
||||||
|
if (count($validDns) !== count($state)) {
|
||||||
|
Notification::make()
|
||||||
|
->title('无效的DNS地址 已自动移除')
|
||||||
|
->warning() // 设置消息类型为警告
|
||||||
|
->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限制最多只能有3个合法的DNS地址
|
||||||
|
if (count($validDns) > 3) {
|
||||||
|
$validDns = array_slice($validDns, 0, 3);
|
||||||
|
Notification::make()
|
||||||
|
->title('最多只能输入3个DNS地址')
|
||||||
|
->warning()
|
||||||
|
->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新字段状态
|
||||||
|
$set('dns_servers', $validDns);
|
||||||
|
})
|
||||||
])
|
])
|
||||||
->visible(fn($get) => !is_null($get('network_interface'))) // 检查是否有选择的接口
|
->visible(fn($get) => !is_null($get('network_interface'))) // 检查是否有选择的接口
|
||||||
->reactive(),
|
->reactive(),
|
||||||
|
|
||||||
// DHCP选项
|
|
||||||
Select::make('dhcp_enabled')
|
|
||||||
->options([
|
|
||||||
true => "是",
|
|
||||||
false => "否"
|
|
||||||
])
|
|
||||||
->default(false)
|
|
||||||
->label("DHCP启用")
|
|
||||||
->required()
|
|
||||||
->reactive(),
|
|
||||||
|
|
||||||
// 动态显示的网络信息字段
|
|
||||||
Fieldset::make('网络配置')
|
|
||||||
->schema([
|
|
||||||
TextInput::make('ip_address')
|
|
||||||
->label("IP地址")
|
|
||||||
->placeholder('如127.0.0.1')
|
|
||||||
->required(),
|
|
||||||
|
|
||||||
TextInput::make('subnet_mask')
|
|
||||||
->label('子网掩码')
|
|
||||||
->placeholder('如255.255.255.0')
|
|
||||||
->required(),
|
|
||||||
|
|
||||||
TextInput::make('gateway')
|
|
||||||
->label('网关')
|
|
||||||
->placeholder('如192.168.1.1')
|
|
||||||
->required(),
|
|
||||||
|
|
||||||
TextInput::make('dns_server_1')
|
|
||||||
->label('DNS地址')
|
|
||||||
->placeholder('如6.6.6.6')
|
|
||||||
->required(),
|
|
||||||
|
|
||||||
TextInput::make('dns_server_2')
|
|
||||||
->label('DNS备用地址')
|
|
||||||
->placeholder('如114.114.114.114')
|
|
||||||
->required(),
|
|
||||||
])
|
|
||||||
->visible(fn($get) => in_array($get('dhcp_enabled'), [false])),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function save(): void
|
||||||
|
{
|
||||||
|
// 获取用户输入的网络配置
|
||||||
|
$ipAddress = $this->form->getState()['ip'] ?? '';
|
||||||
|
$gateway = $this->form->getState()['gateway'] ?? '';
|
||||||
|
$dhcpEnabled = $this->form->getState()['dhcp_enabled'];
|
||||||
|
if ($dhcpEnabled !== 'true'){
|
||||||
|
if (!filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||||
|
Notification::make()
|
||||||
|
->title('无效的 IP 地址格式')
|
||||||
|
->warning()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return; // 返回,不执行保存操作
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证网关地址格式
|
||||||
|
if (!filter_var($gateway, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||||
|
Notification::make()
|
||||||
|
->title('无效的网关地址格式')
|
||||||
|
->warning()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return; // 返回,不执行保存操作
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 验证 IP 地址格式
|
||||||
|
|
||||||
|
|
||||||
|
// 调用父类的保存方法以持久化设置
|
||||||
|
parent::save();
|
||||||
|
|
||||||
|
// 保存后执行终端命令
|
||||||
|
$this->executeCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function executeCommands(): void
|
||||||
|
{
|
||||||
|
// 获取用户输入的网络配置
|
||||||
|
$networkInterface = $this->form->getState()['network_interface'] ?? '';
|
||||||
|
$dhcpEnabled = $this->form->getState()['dhcp_enabled'];
|
||||||
|
|
||||||
|
error_log('接口名称:' . $networkInterface);
|
||||||
|
error_log('dhcp:' . $dhcpEnabled);
|
||||||
|
|
||||||
|
$ipAddress = $this->form->getState()['ip'] ?? '';
|
||||||
|
$mask = $this->form->getState()['mask'] ?? '';
|
||||||
|
$gateway = $this->form->getState()['gateway'] ?? '';
|
||||||
|
|
||||||
|
$dnsServers = $this->form->getState()['dns_servers'] ?? [];
|
||||||
|
$dnsString = implode(',', $dnsServers); // 合并 DNS 地址为字符串
|
||||||
|
|
||||||
|
if ($dhcpEnabled=='true') {
|
||||||
|
|
||||||
|
// 如果启用 DHCP,设置为使用 DHCP
|
||||||
|
$commands = [
|
||||||
|
"nmcli con mod '$networkInterface' ipv4.method auto ipv4.addresses \"\" ipv4.gateway \"\" ipv4.dns \"\"",
|
||||||
|
"nmcli con down '$networkInterface'",
|
||||||
|
"nmcli con up '$networkInterface'"
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($commands as $command) {
|
||||||
|
$output = [];
|
||||||
|
$returnVar = 0;
|
||||||
|
exec($command, $output, $returnVar);
|
||||||
|
|
||||||
|
// 记录输出和返回状态以便调试
|
||||||
|
error_log("命令: $command");
|
||||||
|
error_log("输出: " . implode("\n", $output));
|
||||||
|
error_log("返回状态: $returnVar");
|
||||||
|
|
||||||
|
// 如果需要,处理错误
|
||||||
|
if ($returnVar !== 0) {
|
||||||
|
error_log("执行命令出错: $command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 根据接口和用户输入构建命令
|
||||||
|
$commands = [
|
||||||
|
"nmcli con mod '$networkInterface' ipv4.method manual ipv4.addresses $ipAddress/$mask ipv4.gateway $gateway ipv4.dns $dnsString",
|
||||||
|
"nmcli con down '$networkInterface'",
|
||||||
|
"nmcli con up '$networkInterface'", // 重新激活连接
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($commands as $command) {
|
||||||
|
$output = [];
|
||||||
|
$returnVar = 0;
|
||||||
|
exec($command, $output, $returnVar);
|
||||||
|
|
||||||
|
// 记录输出和返回状态以便调试
|
||||||
|
error_log("命令: $command");
|
||||||
|
error_log("输出: " . implode("\n", $output));
|
||||||
|
error_log("返回状态: $returnVar");
|
||||||
|
|
||||||
|
// 如果需要,处理错误
|
||||||
|
if ($returnVar !== 0) {
|
||||||
|
error_log("执行命令出错: $command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ class ManageRemoteWrite extends SettingsPage
|
|||||||
|
|
||||||
protected static string $settings = RemoteWriteSettings::class;
|
protected static string $settings = RemoteWriteSettings::class;
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = '远程写入配置管理';
|
||||||
|
|
||||||
|
protected static ?string $title = '远程写入配置管理';
|
||||||
|
|
||||||
public function form(Form $form): Form
|
public function form(Form $form): Form
|
||||||
{
|
{
|
||||||
return $form
|
return $form
|
||||||
@@ -32,6 +36,11 @@ class ManageRemoteWrite extends SettingsPage
|
|||||||
->url()
|
->url()
|
||||||
->placeholder("http://remote-storage.example.com/api/v1/write"),
|
->placeholder("http://remote-storage.example.com/api/v1/write"),
|
||||||
|
|
||||||
|
// 数据源名陈
|
||||||
|
Forms\Components\TextInput::make('data_source_label')
|
||||||
|
->label("数据源名称")
|
||||||
|
->required(),
|
||||||
|
|
||||||
// 每个分片的最大队列容量
|
// 每个分片的最大队列容量
|
||||||
Forms\Components\TextInput::make('queue_config_capacity')
|
Forms\Components\TextInput::make('queue_config_capacity')
|
||||||
->label("队列容量")
|
->label("队列容量")
|
||||||
|
|||||||
@@ -13,49 +13,78 @@ class SystemStats extends BaseWidget
|
|||||||
{
|
{
|
||||||
$prometheus = new PrometheusService();
|
$prometheus = new PrometheusService();
|
||||||
|
|
||||||
|
try {
|
||||||
// 获取内存总量
|
// 获取内存总量
|
||||||
$memoryTotalQuery = 'node_memory_MemTotal_bytes';
|
$memoryTotalQuery = 'node_memory_MemTotal_bytes';
|
||||||
$memoryTotalResult = $prometheus->query($memoryTotalQuery);
|
$memoryTotalResult = $prometheus->query($memoryTotalQuery);
|
||||||
$memoryTotal = $memoryTotalResult['data']['result'][0]['value'][1] ?? 0;
|
$memoryTotal = $memoryTotalResult['data']['result'][0]['value'][1] ?? 0;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve memory total: ' . $e->getMessage());
|
||||||
|
$memoryTotal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
// 获取已用内存
|
// 获取已用内存
|
||||||
$memoryAvailableQuery = 'node_memory_MemAvailable_bytes';
|
$memoryAvailableQuery = 'node_memory_MemAvailable_bytes';
|
||||||
$memoryAvailableResult = $prometheus->query($memoryAvailableQuery);
|
$memoryAvailableResult = $prometheus->query($memoryAvailableQuery);
|
||||||
$memoryAvailable = $memoryAvailableResult['data']['result'][0]['value'][1] ?? 0;
|
$memoryAvailable = $memoryAvailableResult['data']['result'][0]['value'][1] ?? 0;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve memory available: ' . $e->getMessage());
|
||||||
|
$memoryAvailable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
$memoryUsed = $memoryTotal - $memoryAvailable;
|
$memoryUsed = $memoryTotal - $memoryAvailable;
|
||||||
$memoryDisplay = round($memoryUsed / (1024 * 1024 * 1024), 2) . ' GB / ' . round($memoryTotal / (1024 * 1024 * 1024), 2) . ' GB';
|
$memoryDisplay = round($memoryUsed / (1024 * 1024 * 1024), 2) . ' GB / ' . round($memoryTotal / (1024 * 1024 * 1024), 2) . ' GB';
|
||||||
|
|
||||||
|
try {
|
||||||
// 获取硬盘总量
|
// 获取硬盘总量
|
||||||
$diskTotalQuery = 'node_filesystem_size_bytes{fstype!="rootfs",fstype!="tmpfs",fstype!="squashfs",mountpoint=~"/|/home|/boot"}';
|
$diskTotalQuery = 'node_filesystem_size_bytes{fstype!="rootfs",fstype!="tmpfs",fstype!="squashfs",mountpoint=~"/|/home|/boot"}';
|
||||||
$diskTotalResult = $prometheus->query($diskTotalQuery);
|
$diskTotalResult = $prometheus->query($diskTotalQuery);
|
||||||
$diskTotal = array_sum(array_map(function ($item) {
|
$diskTotal = array_sum(array_map(function ($item) {
|
||||||
return $item['value'][1] ?? 0;
|
return $item['value'][1] ?? 0;
|
||||||
}, $diskTotalResult['data']['result']));
|
}, $diskTotalResult['data']['result']));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve disk total: ' . $e->getMessage());
|
||||||
|
$diskTotal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
// 获取已用硬盘
|
// 获取已用硬盘
|
||||||
$diskFreeQuery = 'node_filesystem_free_bytes{fstype!="rootfs",fstype!="tmpfs",fstype!="squashfs",mountpoint=~"/|/home|/boot"}';
|
$diskFreeQuery = 'node_filesystem_free_bytes{fstype!="rootfs",fstype!="tmpfs",fstype!="squashfs",mountpoint=~"/|/home|/boot"}';
|
||||||
$diskFreeResult = $prometheus->query($diskFreeQuery);
|
$diskFreeResult = $prometheus->query($diskFreeQuery);
|
||||||
$diskFree = array_sum(array_map(function ($item) {
|
$diskFree = array_sum(array_map(function ($item) {
|
||||||
return $item['value'][1] ?? 0;
|
return $item['value'][1] ?? 0;
|
||||||
}, $diskFreeResult['data']['result']));
|
}, $diskFreeResult['data']['result']));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve disk free: ' . $e->getMessage());
|
||||||
|
$diskFree = 0;
|
||||||
|
}
|
||||||
|
|
||||||
$diskUsed = $diskTotal - $diskFree;
|
$diskUsed = $diskTotal - $diskFree;
|
||||||
$diskDisplay = round($diskUsed / (1024 * 1024 * 1024), 2) . ' GB / ' . round($diskTotal / (1024 * 1024 * 1024), 2) . ' GB';
|
$diskDisplay = round($diskUsed / (1024 * 1024 * 1024), 2) . ' GB / ' . round($diskTotal / (1024 * 1024 * 1024), 2) . ' GB';
|
||||||
|
|
||||||
|
try {
|
||||||
// 获取系统启动时间
|
// 获取系统启动时间
|
||||||
$uptimeQuery = 'node_boot_time_seconds';
|
$uptimeQuery = 'node_boot_time_seconds';
|
||||||
$uptimeResult = $prometheus->query($uptimeQuery);
|
$uptimeResult = $prometheus->query($uptimeQuery);
|
||||||
$bootTime = $uptimeResult['data']['result'][0]['value'][1] ?? 0;
|
$bootTime = $uptimeResult['data']['result'][0]['value'][1] ?? 0;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve boot time: ' . $e->getMessage());
|
||||||
|
$bootTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
$uptime = now()->timestamp - $bootTime;
|
$uptime = now()->timestamp - $bootTime;
|
||||||
$uptimeDisplay = gmdate('H:i:s', $uptime);
|
$uptimeDisplay = gmdate('H:i:s', $uptime);
|
||||||
|
|
||||||
|
try {
|
||||||
// 获取CPU核心数量
|
// 获取CPU核心数量
|
||||||
$cpuCoresQuery = 'count(node_cpu_seconds_total{mode="system"})';
|
$cpuCoresQuery = 'count(node_cpu_seconds_total{mode="system"})';
|
||||||
$cpuCoresResult = $prometheus->query($cpuCoresQuery);
|
$cpuCoresResult = $prometheus->query($cpuCoresQuery);
|
||||||
$cpuCores = $cpuCoresResult['data']['result'][0]['value'][1] ?? 0;
|
$cpuCores = $cpuCoresResult['data']['result'][0]['value'][1] ?? 0;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve CPU cores: ' . $e->getMessage());
|
||||||
|
$cpuCores = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
BaseWidget\Stat::make('内存占用', $memoryDisplay),
|
BaseWidget\Stat::make('内存占用', $memoryDisplay),
|
||||||
@@ -65,6 +94,7 @@ class SystemStats extends BaseWidget
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function getPollingInterval(): ?string
|
protected function getPollingInterval(): ?string
|
||||||
{
|
{
|
||||||
return "1s";
|
return "1s";
|
||||||
|
|||||||
@@ -19,28 +19,23 @@ class MetricWidgetChart extends InlineChartWidget
|
|||||||
protected function getData(): array
|
protected function getData(): array
|
||||||
{
|
{
|
||||||
$prometheus = new PrometheusService();
|
$prometheus = new PrometheusService();
|
||||||
|
$labels = [];
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
try {
|
||||||
$query1 = $this->record->name . '{data="real"}';
|
$query1 = $this->record->name . '{data="real"}';
|
||||||
|
|
||||||
|
$start = now()->subMinutes(2)->timestamp;
|
||||||
$start = now()->now()->subMinutes(2)->timestamp;
|
|
||||||
$end = now()->timestamp;
|
$end = now()->timestamp;
|
||||||
$step = 5;
|
$step = 5;
|
||||||
|
|
||||||
|
// 查询 Prometheus 数据
|
||||||
$realdata = $prometheus->queryRange($query1, $start, $end, $step);
|
$realdata = $prometheus->queryRange($query1, $start, $end, $step);
|
||||||
|
|
||||||
|
|
||||||
// 检查查询结果是否有数据
|
// 检查查询结果是否有数据
|
||||||
if (empty($realdata['data']['result'])) {
|
if (!empty($realdata['data']['result']) && !empty($realdata['data']['result'][0]['values'][1])) {
|
||||||
// 如果没有数据,返回一个空数据集或提示信息
|
|
||||||
return [
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($realdata['data']['result'][0]['values'][1])) {
|
// 获取数据
|
||||||
|
|
||||||
// 获取内存使用率数据
|
|
||||||
$realdataValue = array_column($realdata['data']['result'][0]['values'], 1, 0);
|
$realdataValue = array_column($realdata['data']['result'][0]['values'], 1, 0);
|
||||||
|
|
||||||
// 只保留最新的 MAX_POINTS 个数据点
|
// 只保留最新的 MAX_POINTS 个数据点
|
||||||
@@ -48,15 +43,20 @@ class MetricWidgetChart extends InlineChartWidget
|
|||||||
$timestamps = array_slice($timestamps, -self::MAX_POINTS);
|
$timestamps = array_slice($timestamps, -self::MAX_POINTS);
|
||||||
|
|
||||||
foreach ($timestamps as $timestamp) {
|
foreach ($timestamps as $timestamp) {
|
||||||
$labels[] = date('H:i:s', $timestamp); // 格式化时间戳为小时:分钟:秒
|
$labels[] = date('H:i:s', $timestamp); // 格式化时间戳
|
||||||
$data[] = round(floatval($realdataValue[$timestamp]), 2); // 取出每个时间点的内存使用率,并保留两位小数
|
$data[] = round(floatval($realdataValue[$timestamp]), 2); // 保留两位小数
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('Failed to retrieve data from Prometheus: ' . $e->getMessage());
|
||||||
|
// 处理错误,返回默认的空数据集或提示信息
|
||||||
|
return [
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// 将数据格式化为 InlineChartWidget 所需的格式
|
// 返回格式化后的数据
|
||||||
// $formattedRealData = $this->formatData($realdata, 'Real Data');
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'labels' => $labels,
|
'labels' => $labels,
|
||||||
'datasets' => [
|
'datasets' => [
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ class NetworkService
|
|||||||
{
|
{
|
||||||
public static function getNetworkInterfaces()
|
public static function getNetworkInterfaces()
|
||||||
{
|
{
|
||||||
// 使用 `ifconfig` 来获取接口和 IP 地址
|
// 使用 `nmcli dev show` 来获取接口信息
|
||||||
$output = shell_exec('ifconfig');
|
$output = shell_exec('nmcli dev show');
|
||||||
return self::parseNetworkInfo($output);
|
return self::parseNetworkInfo($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,20 +19,30 @@ class NetworkService
|
|||||||
|
|
||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
// 匹配接口名称
|
// 匹配接口名称
|
||||||
if (preg_match('/^([a-zA-Z0-9-]+): flags=/', $line, $matches)) {
|
if (preg_match('/^GENERAL.DEVICE: *(.+)$/', $line, $matches)) {
|
||||||
$interface = $matches[1];
|
$interface = trim($matches[1]);
|
||||||
$interfaces[$interface] = [
|
$interfaces[$interface] = [
|
||||||
'ip' => null,
|
'ip' => null,
|
||||||
'mask' => null,
|
'mask' => null,
|
||||||
|
'gateway' => null,
|
||||||
|
'dns' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// 匹配 IPv4 地址
|
// 匹配 IPv4 地址
|
||||||
if ($interface && preg_match('/inet ([\d\.]+)/', $line, $matches)) {
|
if ($interface && preg_match('/IP4.ADDRESS\[1\]: *([\d\.]+)\/(\d+)/', $line, $matches)) {
|
||||||
$interfaces[$interface]['ip'] = $matches[1];
|
$ip = $matches[1];
|
||||||
|
$prefix = $matches[2];
|
||||||
|
// $mask = self::prefixToMask($prefix); // 获取子网掩码
|
||||||
|
$interfaces[$interface]['ip'] = $ip;
|
||||||
|
$interfaces[$interface]['mask'] = $prefix; // 设置掩码格式
|
||||||
}
|
}
|
||||||
// 匹配子网掩码
|
// 匹配网关
|
||||||
if ($interface && preg_match('/netmask ([\d\.]+)/', $line, $matches)) {
|
if ($interface && preg_match('/IP4.GATEWAY: *([\d\.]+)/', $line, $matches)) {
|
||||||
$interfaces[$interface]['mask'] = $matches[1];
|
$interfaces[$interface]['gateway'] = $matches[1];
|
||||||
|
}
|
||||||
|
// 匹配 DNS
|
||||||
|
if ($interface && preg_match('/IP4.DNS\[\d+\]: *([\d\.]+)/', $line, $matches)) {
|
||||||
|
$interfaces[$interface]['dns'][] = $matches[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,4 +52,19 @@ class NetworkService
|
|||||||
return $interfaces;
|
return $interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getDHCPstatus($state)
|
||||||
|
{
|
||||||
|
// 调试:检查传递的 state 参数
|
||||||
|
error_log("正在获取DHCP状态的接口: " . $state);
|
||||||
|
|
||||||
|
// 执行 nmcli 命令,获取指定连接的详细信息
|
||||||
|
$output = shell_exec('nmcli con show ' . escapeshellarg($state));
|
||||||
|
|
||||||
|
// 使用正则表达式匹配 'ipv4.method: auto'
|
||||||
|
if (preg_match('/ipv4\.method:\s+auto/', $output)) {
|
||||||
|
return true; // 如果匹配到,说明启用了 DHCP
|
||||||
|
} else {
|
||||||
|
return false; // 否则未启用 DHCP
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,18 @@ class PrometheusService
|
|||||||
*/
|
*/
|
||||||
public function query($query)
|
public function query($query)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$response = $this->client->get('query', [
|
$response = $this->client->get('query', [
|
||||||
'query' => ['query' => $query],
|
'query' => ['query' => $query],
|
||||||
]);
|
]);
|
||||||
return json_decode($response->getBody()->getContents(), true);
|
return json_decode($response->getBody()->getContents(), true);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// 处理异常,记录日志或返回错误信息
|
||||||
|
error_log('Query failed: ' . $e->getMessage());
|
||||||
|
return ['error' => 'Failed to execute query', 'message' => $e->getMessage()];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行 Prometheus 区间查询
|
* 执行 Prometheus 区间查询
|
||||||
@@ -38,6 +45,7 @@ class PrometheusService
|
|||||||
*/
|
*/
|
||||||
public function queryRange($query, $start, $end, $step)
|
public function queryRange($query, $start, $end, $step)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$response = $this->client->get('query_range', [
|
$response = $this->client->get('query_range', [
|
||||||
'query' => [
|
'query' => [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
@@ -47,7 +55,13 @@ class PrometheusService
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
return json_decode($response->getBody()->getContents(), true);
|
return json_decode($response->getBody()->getContents(), true);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// 处理异常,记录日志或返回错误信息
|
||||||
|
error_log('Query range failed: ' . $e->getMessage());
|
||||||
|
return ['error' => 'Failed to execute query range', 'message' => $e->getMessage()];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 Prometheus 监控的所有目标
|
* 获取 Prometheus 监控的所有目标
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class RemoteWriteSettings extends Settings
|
|||||||
public bool $state;
|
public bool $state;
|
||||||
public string $auth_mode;
|
public string $auth_mode;
|
||||||
public string $url;
|
public string $url;
|
||||||
|
public ?string $data_source_label;
|
||||||
public int $queue_config_capacity;
|
public int $queue_config_capacity;
|
||||||
public int $queue_config_max_samples_per_send;
|
public int $queue_config_max_samples_per_send;
|
||||||
public string $queue_config_batch_send_deadline;
|
public string $queue_config_batch_send_deadline;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ return new class extends SettingsMigration
|
|||||||
|
|
||||||
// 添加 Prometheus remote_write 配置参数
|
// 添加 Prometheus remote_write 配置参数
|
||||||
$this->migrator->add('remote_write.url', 'http://remote-storage.example.com/api/v1/write'); // 远程存储的URL
|
$this->migrator->add('remote_write.url', 'http://remote-storage.example.com/api/v1/write'); // 远程存储的URL
|
||||||
|
$this->migrator->add('remote_write.data_source_label',); // 数据源名称
|
||||||
$this->migrator->add('remote_write.queue_config_capacity', 10000); // 每个分片的最大队列容量
|
$this->migrator->add('remote_write.queue_config_capacity', 10000); // 每个分片的最大队列容量
|
||||||
$this->migrator->add('remote_write.queue_config_max_samples_per_send', 2000); // 每次发送的最大样本数
|
$this->migrator->add('remote_write.queue_config_max_samples_per_send', 2000); // 每次发送的最大样本数
|
||||||
$this->migrator->add('remote_write.queue_config_batch_send_deadline', '5s'); // 每次发送批次的最大等待时间
|
$this->migrator->add('remote_write.queue_config_batch_send_deadline', '5s'); // 每次发送批次的最大等待时间
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ keys = [
|
|||||||
"/exporter/",
|
"/exporter/",
|
||||||
"/metrics/",
|
"/metrics/",
|
||||||
]
|
]
|
||||||
reload_cmd = "pkill -f opcua-exporter"
|
reload_cmd = "pkill -f opcua_exporter"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user