mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 06:40:45 +08:00
Fix Windows install start: writable runtime logs and robust Postgres bootstrap.
Some checks failed
Release Windows / build (push) Has been cancelled
Some checks failed
Release Windows / build (push) Has been cancelled
API logs go under ProgramData; first-run verifies CREATE ROLE/DATABASE and login. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
ca97a2a597
commit
86dfd41f44
7 changed files with 64 additions and 33 deletions
|
|
@ -148,6 +148,7 @@ function Get-NetxDataEnvMap {
|
||||||
"NETX_AUTH_MCP_TOKEN_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\mcp_token"))
|
"NETX_AUTH_MCP_TOKEN_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\mcp_token"))
|
||||||
"NETX_AUTH_SECRET_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\jwt_secret"))
|
"NETX_AUTH_SECRET_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\jwt_secret"))
|
||||||
"NETX_SCHEDULER_HEARTBEAT_PATH" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime\scheduler_heartbeat.json"))
|
"NETX_SCHEDULER_HEARTBEAT_PATH" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime\scheduler_heartbeat.json"))
|
||||||
|
"NETX_RUN_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime"))
|
||||||
"NETX_BIZ_STATE_SPOOL_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\biz_state_spool"))
|
"NETX_BIZ_STATE_SPOOL_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\biz_state_spool"))
|
||||||
"NETX_NE_COLLECTION_DATA_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_collections"))
|
"NETX_NE_COLLECTION_DATA_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_collections"))
|
||||||
"NETX_NE_EXEC_JOB_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_exec_jobs"))
|
"NETX_NE_EXEC_JOB_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_exec_jobs"))
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
; NetX Windows installer (Inno Setup 6+)
|
; NetX Windows installer (Inno Setup 6+)
|
||||||
; Compile after: packaging\build_release.ps1
|
; Compile after: packaging\build_release.ps1
|
||||||
; ISCC.exe packaging\installer\netx.iss
|
; ISCC.exe packaging\installer\netx.iss
|
||||||
|
|
||||||
#define MyAppName "NetX"
|
#define MyAppName "NetX"
|
||||||
#ifndef MyAppVersion
|
#ifndef MyAppVersion
|
||||||
#define MyAppVersion "0.4.4"
|
#define MyAppVersion "0.4.5"
|
||||||
#endif
|
#endif
|
||||||
#define MyAppPublisher "NetX"
|
#define MyAppPublisher "NetX"
|
||||||
#define MyAppURL "https://github.com/hansjone/netx"
|
#define MyAppURL "https://github.com/hansjone/netx"
|
||||||
|
|
@ -34,7 +34,7 @@ WizardStyle=modern
|
||||||
ArchitecturesAllowed=x64compatible
|
ArchitecturesAllowed=x64compatible
|
||||||
ArchitecturesInstallIn64BitMode=x64compatible
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
PrivilegesRequired=admin
|
PrivilegesRequired=admin
|
||||||
; Data lives under {commonappdata}\NetX — not overwritten by upgrades
|
; Data lives under {commonappdata}\NetX 鈥?not overwritten by upgrades
|
||||||
CloseApplications=yes
|
CloseApplications=yes
|
||||||
ShowLanguageDialog=yes
|
ShowLanguageDialog=yes
|
||||||
|
|
||||||
|
|
@ -50,20 +50,19 @@ english.StartTrayNow=Start NetX tray now
|
||||||
english.EnableAutostart=Start NetX tray at Windows logon
|
english.EnableAutostart=Start NetX tray at Windows logon
|
||||||
english.EnableAutoUpdate=Enable daily silent auto-update (needs network later)
|
english.EnableAutoUpdate=Enable daily silent auto-update (needs network later)
|
||||||
english.InstallService=Install as Windows Service (uses bundled WinSW, offline)
|
english.InstallService=Install as Windows Service (uses bundled WinSW, offline)
|
||||||
chinesesimplified.CreateDesktopIcon=创建桌面快捷方式
|
chinesesimplified.CreateDesktopIcon=鍒涘缓妗岄潰蹇嵎鏂瑰紡
|
||||||
chinesesimplified.SetupOptions=安装选项:
|
chinesesimplified.SetupOptions=瀹夎閫夐」:
|
||||||
chinesesimplified.RunFirstSetup=安装后运行首次配置(内置数据库,可离线)
|
chinesesimplified.RunFirstSetup=瀹夎鍚庤繍琛岄娆¢厤缃紙鍐呯疆鏁版嵁搴擄紝鍙绾匡級
|
||||||
chinesesimplified.StartTrayNow=立即启动 NetX 托盘
|
chinesesimplified.StartTrayNow=绔嬪嵆鍚姩 NetX 鎵樼洏
|
||||||
chinesesimplified.EnableAutostart=开机时自动启动 NetX 托盘
|
chinesesimplified.EnableAutostart=寮€鏈烘椂鑷姩鍚姩 NetX 鎵樼洏
|
||||||
chinesesimplified.EnableAutoUpdate=启用每日静默自动更新(以后需要联网)
|
chinesesimplified.EnableAutoUpdate=鍚敤姣忔棩闈欓粯鑷姩鏇存柊锛堜互鍚庨渶瑕佽仈缃戯級
|
||||||
chinesesimplified.InstallService=安装为 Windows 服务(使用已捆绑的 WinSW,可离线)
|
chinesesimplified.InstallService=瀹夎涓?Windows 鏈嶅姟锛堜娇鐢ㄥ凡鎹嗙粦鐨?WinSW锛屽彲绂荤嚎锛?
|
||||||
|
|
||||||
[Tasks]
|
[Tasks]
|
||||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce
|
||||||
Name: "firstrun"; Description: "{cm:RunFirstSetup}"; GroupDescription: "{cm:SetupOptions}"; Flags: checkedonce
|
Name: "firstrun"; Description: "{cm:RunFirstSetup}"; GroupDescription: "{cm:SetupOptions}"; Flags: checkedonce
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; Entire release stage → {app}. Exclude .portable so installed builds use ProgramData.
|
; Entire release stage 鈫?{app}. Exclude .portable so installed builds use ProgramData.
|
||||||
Source: "{#StageDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: ".portable"
|
Source: "{#StageDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: ".portable"
|
||||||
|
|
||||||
[Dirs]
|
[Dirs]
|
||||||
|
|
@ -99,5 +98,6 @@ Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\p
|
||||||
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; Description: "{cm:InstallService}"; Flags: postinstall skipifsilent unchecked
|
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; Description: "{cm:InstallService}"; Flags: postinstall skipifsilent unchecked
|
||||||
|
|
||||||
[UninstallDelete]
|
[UninstallDelete]
|
||||||
; Do NOT delete {commonappdata}\NetX — preserves DB and secrets across reinstall
|
; Do NOT delete {commonappdata}\NetX 鈥?preserves DB and secrets across reinstall
|
||||||
Type: filesandordirs; Name: "{app}"
|
Type: filesandordirs; Name: "{app}"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"channel": "stable",
|
"channel": "stable",
|
||||||
"latest": "0.4.4",
|
"latest": "0.4.5",
|
||||||
"min_compatible": "0.3.0",
|
"min_compatible": "0.3.0",
|
||||||
"notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.4",
|
"notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.5",
|
||||||
"windows": {
|
"windows": {
|
||||||
"url": "https://github.com/hansjone/netx/releases/download/v0.4.4/NetX-0.4.4-win64.zip",
|
"url": "https://github.com/hansjone/netx/releases/download/v0.4.5/NetX-0.4.5-win64.zip",
|
||||||
"setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.4/NetX-Setup-0.4.4.exe",
|
"setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.5/NetX-Setup-0.4.5.exe",
|
||||||
"sha256": "",
|
"sha256": "",
|
||||||
"size": 0
|
"size": 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,21 +153,37 @@ if ($DbMode -eq "bundled") {
|
||||||
|
|
||||||
$env:PGPASSWORD = $BundledPassword
|
$env:PGPASSWORD = $BundledPassword
|
||||||
try {
|
try {
|
||||||
$role = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='netx'"
|
function Invoke-NetxPsql {
|
||||||
if ($role -notmatch "1") {
|
param([string]$Sql, [string]$Database = "postgres")
|
||||||
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
|
$out = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d $Database -v ON_ERROR_STOP=1 -tAc $Sql 2>&1
|
||||||
-c "CREATE ROLE netx LOGIN PASSWORD '$sqlPw';"
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "psql_failed ($LASTEXITCODE): $Sql`n$out"
|
||||||
|
}
|
||||||
|
return (($out | Out-String).Trim())
|
||||||
|
}
|
||||||
|
|
||||||
|
$role = Invoke-NetxPsql -Sql "SELECT 1 FROM pg_roles WHERE rolname='netx'"
|
||||||
|
if ($role -eq "1") {
|
||||||
|
Invoke-NetxPsql -Sql "ALTER ROLE netx WITH LOGIN PASSWORD '$sqlPw'" | Out-Null
|
||||||
} else {
|
} else {
|
||||||
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
|
Invoke-NetxPsql -Sql "CREATE ROLE netx LOGIN PASSWORD '$sqlPw'" | Out-Null
|
||||||
-c "ALTER ROLE netx WITH LOGIN PASSWORD '$sqlPw';"
|
|
||||||
}
|
}
|
||||||
$db = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='netx'"
|
$db = Invoke-NetxPsql -Sql "SELECT 1 FROM pg_database WHERE datname='netx'"
|
||||||
if ($db -notmatch "1") {
|
if ($db -ne "1") {
|
||||||
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
|
Invoke-NetxPsql -Sql "CREATE DATABASE netx OWNER netx" | Out-Null
|
||||||
-c "CREATE DATABASE netx OWNER netx;"
|
}
|
||||||
|
Invoke-NetxPsql -Sql "GRANT ALL PRIVILEGES ON DATABASE netx TO netx" | Out-Null
|
||||||
|
# Verify login as app role (catches auth/hba mismatches early).
|
||||||
|
$prev = $env:PGPASSWORD
|
||||||
|
$env:PGPASSWORD = $BundledPassword
|
||||||
|
try {
|
||||||
|
$ping = & $psql -h 127.0.0.1 -p $BundledPort -U netx -d netx -v ON_ERROR_STOP=1 -tAc "SELECT 1" 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0 -or (($ping | Out-String).Trim()) -ne "1") {
|
||||||
|
throw "netx_role_login_failed: $ping"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$env:PGPASSWORD = $prev
|
||||||
}
|
}
|
||||||
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
|
|
||||||
-c "GRANT ALL PRIVILEGES ON DATABASE netx TO netx;"
|
|
||||||
} finally {
|
} finally {
|
||||||
Remove-Item Env:PGPASSWORD -ErrorAction SilentlyContinue
|
Remove-Item Env:PGPASSWORD -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "netx-ops"
|
name = "netx-ops"
|
||||||
version = "0.4.4"
|
version = "0.4.5"
|
||||||
description = "netx operations tool: alarm-centric workflows with REST API and stdio MCP"
|
description = "netx operations tool: alarm-centric workflows with REST API and stdio MCP"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|
@ -43,3 +43,4 @@ netx-topology-mcp = "netx_topology_mcp.server:main"
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
where = ["."]
|
where = ["."]
|
||||||
include = ["netx_api*"]
|
include = ["netx_api*"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,16 @@ if ($Backgtound -and -not $Background) {
|
||||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||||
Set-Location $projectRoot
|
Set-Location $projectRoot
|
||||||
|
|
||||||
$runDir = Join-Path $PSScriptRoot ".run"
|
# Prefer writable data-root runtime dir (Program Files is not writable after Setup install).
|
||||||
|
if ($env:NETX_RUN_DIR) {
|
||||||
|
$runDir = $env:NETX_RUN_DIR
|
||||||
|
} elseif ($env:NETX_SCHEDULER_HEARTBEAT_PATH) {
|
||||||
|
$runDir = Split-Path -Parent ($env:NETX_SCHEDULER_HEARTBEAT_PATH -replace '/', '\')
|
||||||
|
} else {
|
||||||
|
$runDir = Join-Path $PSScriptRoot ".run"
|
||||||
|
}
|
||||||
if (-not (Test-Path $runDir)) {
|
if (-not (Test-Path $runDir)) {
|
||||||
New-Item -ItemType Directory -Path $runDir | Out-Null
|
New-Item -ItemType Directory -Path $runDir -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
$pidFile = Join-Path $runDir "netx.pid"
|
$pidFile = Join-Path $runDir "netx.pid"
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,13 @@
|
||||||
$ErrorActionPreference = "Continue"
|
$ErrorActionPreference = "Continue"
|
||||||
$useForce = if ($NoForce) { $false } else { [bool]$Force }
|
$useForce = if ($NoForce) { $false } else { [bool]$Force }
|
||||||
|
|
||||||
$runDir = Join-Path $PSScriptRoot ".run"
|
if ($env:NETX_RUN_DIR) {
|
||||||
|
$runDir = $env:NETX_RUN_DIR
|
||||||
|
} elseif ($env:NETX_SCHEDULER_HEARTBEAT_PATH) {
|
||||||
|
$runDir = Split-Path -Parent ($env:NETX_SCHEDULER_HEARTBEAT_PATH -replace '/', '\')
|
||||||
|
} else {
|
||||||
|
$runDir = Join-Path $PSScriptRoot ".run"
|
||||||
|
}
|
||||||
$pidFile = Join-Path $runDir "netx.pid"
|
$pidFile = Join-Path $runDir "netx.pid"
|
||||||
$workerPidFile = Join-Path $runDir "worker.pid"
|
$workerPidFile = Join-Path $runDir "worker.pid"
|
||||||
$webPidFile = Join-Path $runDir "web.pid"
|
$webPidFile = Join-Path $runDir "web.pid"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue