From 45af92090a8536c4f592936a1e8eaa79a83b4906 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Thu, 18 Dec 2025 08:45:14 -0500 Subject: [PATCH 1/4] refactor: remove deprecated agent self --- agent/self/config/const.go | 6 -- agent/self/config/linux_amd64.go | 8 --- agent/self/config/linux_arm64.go | 8 --- agent/self/config/macos.go | 8 --- agent/self/config/win_amd64.go | 8 --- agent/self/config/win_arm64.go | 8 --- agent/self/go.mod | 39 ---------- agent/self/go.sum | 94 ------------------------ agent/self/main.go | 41 ----------- agent/self/rsrc_windows_386.syso | Bin 29120 -> 0 bytes agent/self/rsrc_windows_amd64.syso | Bin 29120 -> 0 bytes agent/self/rsrc_windows_arm64.syso | Bin 205126 -> 0 bytes agent/self/update/update.go | 28 -------- agent/self/utils/cmd.go | 47 ------------ agent/self/utils/files.go | 15 ---- agent/self/utils/logger.go | 20 ------ agent/self/utils/services.go | 112 ----------------------------- 17 files changed, 442 deletions(-) delete mode 100644 agent/self/config/const.go delete mode 100644 agent/self/config/linux_amd64.go delete mode 100644 agent/self/config/linux_arm64.go delete mode 100644 agent/self/config/macos.go delete mode 100644 agent/self/config/win_amd64.go delete mode 100644 agent/self/config/win_arm64.go delete mode 100644 agent/self/go.mod delete mode 100644 agent/self/go.sum delete mode 100644 agent/self/main.go delete mode 100644 agent/self/rsrc_windows_386.syso delete mode 100644 agent/self/rsrc_windows_amd64.syso delete mode 100644 agent/self/rsrc_windows_arm64.syso delete mode 100644 agent/self/update/update.go delete mode 100644 agent/self/utils/cmd.go delete mode 100644 agent/self/utils/files.go delete mode 100644 agent/self/utils/logger.go delete mode 100644 agent/self/utils/services.go diff --git a/agent/self/config/const.go b/agent/self/config/const.go deleted file mode 100644 index 2d89a1ee5..000000000 --- a/agent/self/config/const.go +++ /dev/null @@ -1,6 +0,0 @@ -package config - -const ( - SERV_NAME = "UTMStackAgent" - SERV_LOG = "utmstack_updater_self.log" -) diff --git a/agent/self/config/linux_amd64.go b/agent/self/config/linux_amd64.go deleted file mode 100644 index 2bd4ccf23..000000000 --- a/agent/self/config/linux_amd64.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build linux && amd64 -// +build linux,amd64 - -package config - -var ( - ServiceFile = "utmstack_agent_service%s" -) diff --git a/agent/self/config/linux_arm64.go b/agent/self/config/linux_arm64.go deleted file mode 100644 index 35fbef145..000000000 --- a/agent/self/config/linux_arm64.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build linux && arm64 -// +build linux,arm64 - -package config - -var ( - ServiceFile = "utmstack_agent_service_arm64%s" -) diff --git a/agent/self/config/macos.go b/agent/self/config/macos.go deleted file mode 100644 index 9804f368b..000000000 --- a/agent/self/config/macos.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build darwin -// +build darwin - -package config - -var ( - ServiceFile = "utmstack_agent_service%s" -) diff --git a/agent/self/config/win_amd64.go b/agent/self/config/win_amd64.go deleted file mode 100644 index 87bcb5eea..000000000 --- a/agent/self/config/win_amd64.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build windows && amd64 -// +build windows,amd64 - -package config - -var ( - ServiceFile = "utmstack_agent_service%s.exe" -) diff --git a/agent/self/config/win_arm64.go b/agent/self/config/win_arm64.go deleted file mode 100644 index ccedb2f95..000000000 --- a/agent/self/config/win_arm64.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build windows && arm64 -// +build windows,arm64 - -package config - -var ( - ServiceFile = "utmstack_agent_service_arm64%s.exe" -) diff --git a/agent/self/go.mod b/agent/self/go.mod deleted file mode 100644 index f9ba38c2e..000000000 --- a/agent/self/go.mod +++ /dev/null @@ -1,39 +0,0 @@ -module github.com/utmstack/UTMStack/agent/self - -go 1.23.0 - -toolchain go1.23.4 - -require github.com/threatwinds/logger v1.2.1 - -require ( - github.com/bytedance/sonic v1.12.1 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.0 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - golang.org/x/arch v0.9.0 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/net v0.36.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/agent/self/go.sum b/agent/self/go.sum deleted file mode 100644 index 7e6037bf1..000000000 --- a/agent/self/go.sum +++ /dev/null @@ -1,94 +0,0 @@ -github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= -github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= -github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= -github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= -github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/threatwinds/logger v1.2.1 h1:uN7efZaHobMX3DRi6GOPtxESPxt5xj0bNflnmgklwII= -github.com/threatwinds/logger v1.2.1/go.mod h1:eevkhjP9wSpRekRIgi4ZAq7DMdlUMy+Shwx/QNDvOHg= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= -golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/agent/self/main.go b/agent/self/main.go deleted file mode 100644 index 51f057b6a..000000000 --- a/agent/self/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "path/filepath" - "time" - - "github.com/utmstack/UTMStack/agent/self/config" - "github.com/utmstack/UTMStack/agent/self/update" - "github.com/utmstack/UTMStack/agent/self/utils" -) - -func main() { - path := utils.GetMyPath() - utils.InitLogger(filepath.Join(path, "logs", config.SERV_LOG)) - - utils.SelfLogger.Info("Updating %s...", config.SERV_NAME) - - if isRunning, err := utils.CheckIfServiceIsActive(config.SERV_NAME); err != nil { - utils.SelfLogger.Fatal("error checking %s service: %v", config.SERV_NAME, err) - } else if isRunning { - err = utils.StopService(config.SERV_NAME) - if err != nil { - utils.SelfLogger.Fatal("error stopping %s service: %v", config.SERV_NAME, err) - } - utils.SelfLogger.Info("%s stopped correctly", config.SERV_NAME) - } - - time.Sleep(10 * time.Second) - - err := update.RunUpdate() - if err != nil { - utils.SelfLogger.Fatal("error updating new %s service: %v", config.SERV_NAME, err) - } - utils.SelfLogger.Info("New %s downloaded correctly", config.SERV_NAME) - - err = utils.RestartService(config.SERV_NAME) - if err != nil { - utils.SelfLogger.Fatal("error restarting %s service: %v", config.SERV_NAME, err) - } - utils.SelfLogger.Info("%s updated correctly", config.SERV_NAME) -} diff --git a/agent/self/rsrc_windows_386.syso b/agent/self/rsrc_windows_386.syso deleted file mode 100644 index 2aaa16e001adb2fdf5e602bb8287edcae60fa5d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29120 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

2RE?qPlPEHP^SQ!%vv^rOxkWj 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 diff --git a/agent/self/rsrc_windows_arm64.syso b/agent/self/rsrc_windows_arm64.syso deleted file mode 100644 index edf10285e23291a65d9d5ee5acb6be54899da616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205126 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�F4U7=hY^#{Q|#y{l% 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 BRp0;s diff --git a/agent/self/update/update.go b/agent/self/update/update.go deleted file mode 100644 index 22011d831..000000000 --- a/agent/self/update/update.go +++ /dev/null @@ -1,28 +0,0 @@ -package update - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/utmstack/UTMStack/agent/self/config" - "github.com/utmstack/UTMStack/agent/self/utils" -) - -func RunUpdate() error { - path := utils.GetMyPath() - - newbin := fmt.Sprintf(config.ServiceFile, "_new") - oldbin := fmt.Sprintf(config.ServiceFile, "") - err := os.Remove(filepath.Join(path, oldbin)) - if err != nil { - return fmt.Errorf("error removing old %s: %v", oldbin, err) - } - - err = os.Rename(filepath.Join(path, newbin), filepath.Join(path, oldbin)) - if err != nil { - return fmt.Errorf("error renaming new %s: %v", newbin, err) - } - - return nil -} diff --git a/agent/self/utils/cmd.go b/agent/self/utils/cmd.go deleted file mode 100644 index b1881855f..000000000 --- a/agent/self/utils/cmd.go +++ /dev/null @@ -1,47 +0,0 @@ -package utils - -import ( - "errors" - "os/exec" - "unicode/utf8" -) - -func CleanString(s string) string { - v := make([]rune, 0, len(s)) - for i, r := range s { - if r == utf8.RuneError { - _, size := utf8.DecodeRuneInString(s[i:]) - if size == 1 { - v = append(v, '?') - continue - } - } - v = append(v, r) - } - return string(v) -} - -func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { - cmd := exec.Command(c, arg...) - - cmd.Dir = dir - if errors.Is(cmd.Err, exec.ErrDot) { - cmd.Err = nil - } - - out, err := cmd.Output() - if err != nil { - return string(out[:]) + err.Error(), true - } - - validUtf8Out := CleanString(string(out[:])) - - return validUtf8Out, false -} - -func Execute(c string, dir string, arg ...string) error { - cmd := exec.Command(c, arg...) - cmd.Dir = dir - - return cmd.Run() -} diff --git a/agent/self/utils/files.go b/agent/self/utils/files.go deleted file mode 100644 index 24baf7dae..000000000 --- a/agent/self/utils/files.go +++ /dev/null @@ -1,15 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" -) - -func GetMyPath() string { - ex, err := os.Executable() - if err != nil { - return "" - } - exPath := filepath.Dir(ex) - return exPath -} diff --git a/agent/self/utils/logger.go b/agent/self/utils/logger.go deleted file mode 100644 index e2e8c7fdf..000000000 --- a/agent/self/utils/logger.go +++ /dev/null @@ -1,20 +0,0 @@ -package utils - -import ( - "sync" - - "github.com/threatwinds/logger" -) - -var ( - SelfLogger *logger.Logger - loggerOnceInstance sync.Once -) - -func InitLogger(filename string) { - loggerOnceInstance.Do(func() { - SelfLogger = logger.NewLogger( - &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, - ) - }) -} diff --git a/agent/self/utils/services.go b/agent/self/utils/services.go deleted file mode 100644 index b6009d27f..000000000 --- a/agent/self/utils/services.go +++ /dev/null @@ -1,112 +0,0 @@ -package utils - -import ( - "fmt" - "runtime" - "strings" -) - -func CheckIfServiceIsActive(serv string) (bool, error) { - var errB bool - var output string - path := GetMyPath() - - switch runtime.GOOS { - case "windows": - output, errB = ExecuteWithResult("sc", path, "query", serv) - case "linux": - output, errB = ExecuteWithResult("systemctl", path, "is-active", serv) - case "darwin": - output, errB = ExecuteWithResult("launchctl", path, "list", serv) - default: - return false, fmt.Errorf("unknown operating system") - } - - if errB { - return false, nil - } - - serviceStatus := strings.ToLower(strings.TrimSpace(output)) - - switch runtime.GOOS { - case "windows": - return strings.Contains(serviceStatus, "running"), nil - case "linux": - return serviceStatus == "active", nil - case "darwin": - // launchctl list returns a JSON-ish block or error.If the service is listed, it's running - return true, nil - default: - return false, fmt.Errorf("unsupported operating system") - } -} - -func RestartService(serv string) error { - path := GetMyPath() - isRunning, err := CheckIfServiceIsActive(serv) - if err != nil { - return fmt.Errorf("error checking if %s service is active: %v", serv, err) - } - - switch runtime.GOOS { - case "windows": - if isRunning { - err := Execute("sc", path, "stop", serv) - if err != nil { - return fmt.Errorf("error stopping service: %v", err) - } - } - err := Execute("sc", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - - case "linux": - if isRunning { - err := Execute("systemctl", path, "restart", serv) - if err != nil { - return fmt.Errorf("error restarting service: %v", err) - } - } else { - err := Execute("systemctl", path, "start", serv) - if err != nil { - return fmt.Errorf("error starting service: %v", err) - } - } - case "darwin": - plistPath := fmt.Sprintf("/Library/LaunchDaemons/%s.plist", serv) - - if isRunning { - if err := Execute("launchctl", path, "remove", serv); err != nil { - return fmt.Errorf("error stopping macOS service: %v", err) - } - } - - if err := Execute("launchctl", path, "load", plistPath); err != nil { - return fmt.Errorf("error starting macOS service: %v", err) - } - } - return nil -} - -func StopService(name string) error { - path := GetMyPath() - switch runtime.GOOS { - case "windows": - err := Execute("sc", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - case "linux": - err := Execute("systemctl", path, "stop", name) - if err != nil { - return fmt.Errorf("error stoping service: %v", err) - } - case "darwin": - err := Execute("launchctl", path, "remove", name) - if err != nil { - return fmt.Errorf("error stopping macOS service: %v", err) - } - } - return nil -} From a603c56ea7e29cde4921f820d29535d66e854472 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Thu, 18 Dec 2025 08:47:13 -0500 Subject: [PATCH 2/4] feat(agent): implement UTMStack updater service --- agent/updater/config/config.go | 54 +++++++++ agent/updater/config/const.go | 21 ++++ agent/updater/config/linux_amd64.go | 9 ++ agent/updater/config/linux_arm64.go | 9 ++ agent/updater/config/macos.go | 9 ++ agent/updater/config/windows_amd64.go | 9 ++ agent/updater/config/windows_arm64.go | 9 ++ agent/updater/go.mod | 46 ++++++++ agent/updater/go.sum | 111 +++++++++++++++++++ agent/updater/main.go | 44 ++++++++ agent/updater/models/version.go | 5 + agent/updater/rsrc_windows_386.syso | Bin 0 -> 29120 bytes agent/updater/rsrc_windows_amd64.syso | Bin 0 -> 29120 bytes agent/updater/rsrc_windows_arm64.syso | Bin 0 -> 205126 bytes agent/updater/service/config.go | 17 +++ agent/updater/service/install.go | 52 +++++++++ agent/updater/service/service.go | 43 +++++++ agent/updater/updates/update.go | 154 ++++++++++++++++++++++++++ agent/updater/utils/cmd.go | 39 +++++++ agent/updater/utils/download.go | 48 ++++++++ agent/updater/utils/files.go | 92 +++++++++++++++ agent/updater/utils/logger.go | 20 ++++ agent/updater/utils/services.go | 135 ++++++++++++++++++++++ agent/updater/utils/zip.go | 42 +++++++ 24 files changed, 968 insertions(+) create mode 100644 agent/updater/config/config.go create mode 100644 agent/updater/config/const.go create mode 100644 agent/updater/config/linux_amd64.go create mode 100644 agent/updater/config/linux_arm64.go create mode 100644 agent/updater/config/macos.go create mode 100644 agent/updater/config/windows_amd64.go create mode 100644 agent/updater/config/windows_arm64.go create mode 100644 agent/updater/go.mod create mode 100644 agent/updater/go.sum create mode 100644 agent/updater/main.go create mode 100644 agent/updater/models/version.go create mode 100644 agent/updater/rsrc_windows_386.syso create mode 100644 agent/updater/rsrc_windows_amd64.syso create mode 100644 agent/updater/rsrc_windows_arm64.syso create mode 100644 agent/updater/service/config.go create mode 100644 agent/updater/service/install.go create mode 100644 agent/updater/service/service.go create mode 100644 agent/updater/updates/update.go create mode 100644 agent/updater/utils/cmd.go create mode 100644 agent/updater/utils/download.go create mode 100644 agent/updater/utils/files.go create mode 100644 agent/updater/utils/logger.go create mode 100644 agent/updater/utils/services.go create mode 100644 agent/updater/utils/zip.go diff --git a/agent/updater/config/config.go b/agent/updater/config/config.go new file mode 100644 index 000000000..8daefeb23 --- /dev/null +++ b/agent/updater/config/config.go @@ -0,0 +1,54 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "sync" + + "gopkg.in/yaml.v3" +) + +type Config struct { + Server string `json:"server" yaml:"server"` + SkipCertValidation bool `json:"insecure" yaml:"insecure"` +} + +var ( + cnf = Config{} + confOnce sync.Once +) + +func GetCurrentConfig() (*Config, error) { + var errR error + confOnce.Do(func() { + ex, err := os.Executable() + if err != nil { + errR = fmt.Errorf("error getting executable path: %v", err) + return + } + exPath := filepath.Dir(ex) + + configPath := filepath.Join(exPath, "config.yml") + content, err := os.ReadFile(configPath) + if err != nil { + errR = fmt.Errorf("error reading config file: %v", err) + return + } + + var loadedConfig Config + err = yaml.Unmarshal(content, &loadedConfig) + if err != nil { + errR = fmt.Errorf("error parsing config file: %v", err) + return + } + + cnf.Server = loadedConfig.Server + cnf.SkipCertValidation = loadedConfig.SkipCertValidation + }) + + if errR != nil { + return nil, errR + } + return &cnf, nil +} diff --git a/agent/updater/config/const.go b/agent/updater/config/const.go new file mode 100644 index 000000000..5032035e0 --- /dev/null +++ b/agent/updater/config/const.go @@ -0,0 +1,21 @@ +package config + +import ( + "path/filepath" + + "github.com/utmstack/UTMStack/agent/updater/utils" +) + +const ( + SERV_LOG = "utmstack_updater.log" + SERV_AGENT_NAME = "UTMStackAgent" +) + +var ( + DependUrl = "https://%s:%s/private/dependencies/agent/%s" + AgentManagerPort = "9000" + LogAuthProxyPort = "50051" + DependenciesPort = "9001" + + VersionPath = filepath.Join(utils.GetMyPath(), "version.json") +) diff --git a/agent/updater/config/linux_amd64.go b/agent/updater/config/linux_amd64.go new file mode 100644 index 000000000..026f6c3f9 --- /dev/null +++ b/agent/updater/config/linux_amd64.go @@ -0,0 +1,9 @@ +//go:build linux && amd64 +// +build linux,amd64 + +package config + +var ( + ServiceFile = "utmstack_agent_service%s" + DependFiles = []string{"utmstack_agent_dependencies_linux.zip"} +) diff --git a/agent/updater/config/linux_arm64.go b/agent/updater/config/linux_arm64.go new file mode 100644 index 000000000..d77ff9f09 --- /dev/null +++ b/agent/updater/config/linux_arm64.go @@ -0,0 +1,9 @@ +//go:build linux && arm64 +// +build linux,arm64 + +package config + +var ( + ServiceFile = "utmstack_agent_service_arm64%s" + DependFiles = []string{"utmstack_agent_dependencies_linux_arm64.zip"} +) diff --git a/agent/updater/config/macos.go b/agent/updater/config/macos.go new file mode 100644 index 000000000..ecb80457a --- /dev/null +++ b/agent/updater/config/macos.go @@ -0,0 +1,9 @@ +//go:build darwin +// +build darwin + +package config + +var ( + ServiceFile = "utmstack_agent_service%s" + DependFiles = []string{} +) diff --git a/agent/updater/config/windows_amd64.go b/agent/updater/config/windows_amd64.go new file mode 100644 index 000000000..adad86d9f --- /dev/null +++ b/agent/updater/config/windows_amd64.go @@ -0,0 +1,9 @@ +//go:build windows && amd64 +// +build windows,amd64 + +package config + +var ( + ServiceFile = "utmstack_agent_service%s.exe" + DependFiles = []string{"utmstack_agent_dependencies_windows.zip"} +) diff --git a/agent/updater/config/windows_arm64.go b/agent/updater/config/windows_arm64.go new file mode 100644 index 000000000..4705118c1 --- /dev/null +++ b/agent/updater/config/windows_arm64.go @@ -0,0 +1,9 @@ +//go:build windows && arm64 +// +build windows,arm64 + +package config + +var ( + ServiceFile = "utmstack_agent_service_arm64%s.exe" + DependFiles = []string{"utmstack_agent_dependencies_windows_arm64.zip"} +) diff --git a/agent/updater/go.mod b/agent/updater/go.mod new file mode 100644 index 000000000..8b6343295 --- /dev/null +++ b/agent/updater/go.mod @@ -0,0 +1,46 @@ +module github.com/utmstack/UTMStack/agent/updater + +go 1.25.0 + +require ( + github.com/kardianos/service v1.2.2 + github.com/threatwinds/go-sdk v1.0.40 + github.com/threatwinds/logger v1.2.2 + gopkg.in/yaml.v3 v3.0.1 + +) + +require ( + github.com/bytedance/sonic v1.13.3 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/gin-gonic/gin v1.10.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.14 // indirect + golang.org/x/arch v0.18.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/agent/updater/go.sum b/agent/updater/go.sum new file mode 100644 index 000000000..23d1acc42 --- /dev/null +++ b/agent/updater/go.sum @@ -0,0 +1,111 @@ +github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0= +github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= +github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/threatwinds/go-sdk v1.0.40 h1:g0XS8WiGVGD6djucY0ZuckpZljBbXDuqGJ1dKOjce3I= +github.com/threatwinds/go-sdk v1.0.40/go.mod h1:ZLcT5kB0s2xFEUVJoFpwlLucnbQ8VBNU44aoKKC/j/g= +github.com/threatwinds/logger v1.2.2 h1:sVuT8yhbecPqP4tT8EwHfp1czNC6e1wdkE1ihNnuBdA= +github.com/threatwinds/logger v1.2.2/go.mod h1:Amq0QI1y7fkTpnBUgeGVu2Z/C4u4ys2pNLUOuj3UAAU= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.14 h1:yOQvXCBc3Ij46LRkRoh4Yd5qK6LVOgi0bYOXfb7ifjw= +github.com/ugorji/go/codec v1.2.14/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc= +golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/agent/updater/main.go b/agent/updater/main.go new file mode 100644 index 000000000..9aae73b21 --- /dev/null +++ b/agent/updater/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/utmstack/UTMStack/agent/updater/config" + "github.com/utmstack/UTMStack/agent/updater/service" + "github.com/utmstack/UTMStack/agent/updater/utils" +) + +func main() { + path := utils.GetMyPath() + utils.InitLogger(filepath.Join(path, "logs", config.SERV_LOG)) + + if len(os.Args) > 1 { + switch os.Args[1] { + case "install": + fmt.Println("Installing UTMStack Updater service...") + + fmt.Print(("Creating service ... ")) + service.InstallService() + fmt.Println("[OK]") + + fmt.Println("UTMStackUpdater service installed correctly") + return + case "uninstall": + fmt.Println("Uninstalling UTMStack Updater service...") + service.UninstallService() + fmt.Println("Service uninstalled successfully") + return + case "start": + fmt.Println("Starting UTMStack Updater service...") + return + case "stop": + fmt.Println("Stopping UTMStack Updater service...") + // Will be handled by systemd + return + } + } + + service.RunService() +} diff --git a/agent/updater/models/version.go b/agent/updater/models/version.go new file mode 100644 index 000000000..ed01f06e4 --- /dev/null +++ b/agent/updater/models/version.go @@ -0,0 +1,5 @@ +package models + +type Version struct { + Version string `json:"version"` +} diff --git a/agent/updater/rsrc_windows_386.syso b/agent/updater/rsrc_windows_386.syso new file mode 100644 index 0000000000000000000000000000000000000000..2aaa16e001adb2fdf5e602bb8287edcae60fa5d8 GIT binary patch literal 29120 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

2RE?qPlPEHP^SQ!%vv^rOxkWj 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 literal 0 HcmV?d00001 diff --git a/agent/updater/rsrc_windows_arm64.syso b/agent/updater/rsrc_windows_arm64.syso new file mode 100644 index 0000000000000000000000000000000000000000..edf10285e23291a65d9d5ee5acb6be54899da616 GIT binary patch literal 205126 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�F4U7=hY^#{Q|#y{l% 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 BRp0;s literal 0 HcmV?d00001 diff --git a/agent/updater/service/config.go b/agent/updater/service/config.go new file mode 100644 index 000000000..0946f296c --- /dev/null +++ b/agent/updater/service/config.go @@ -0,0 +1,17 @@ +package service + +import ( + "github.com/kardianos/service" +) + +// GetConfigServ creates and returns a pointer to a service configuration structure. +func GetConfigServ() *service.Config { + svcConfig := &service.Config{ + Name: "UTMStackUpdater", + DisplayName: "UTMStack Updater", + Description: "UTMStack Agent Updater Service", + // No arguments needed - service will just run + } + + return svcConfig +} diff --git a/agent/updater/service/install.go b/agent/updater/service/install.go new file mode 100644 index 000000000..f566ea2a7 --- /dev/null +++ b/agent/updater/service/install.go @@ -0,0 +1,52 @@ +package service + +import ( + "fmt" + "os" + + "github.com/kardianos/service" + "github.com/utmstack/UTMStack/agent/updater/utils" +) + +func InstallService() { + svcConfig := GetConfigServ() + prg := new(program) + newService, err := service.New(prg, svcConfig) + if err != nil { + fmt.Println("\nError creating new service: ", err) + os.Exit(1) + } + err = newService.Install() + if err != nil { + fmt.Println("\nError installing new service: ", err) + os.Exit(1) + } + + err = newService.Start() + if err != nil { + fmt.Println("\nError starting new service: ", err) + os.Exit(1) + } + utils.UpdaterLogger.Info("updater service installed succefull") +} + +func UninstallService() { + svcConfig := GetConfigServ() + prg := new(program) + newService, err := service.New(prg, svcConfig) + if err != nil { + fmt.Println("\nError creating new service: ", err) + os.Exit(1) + } + + err = newService.Stop() + if err != nil { + fmt.Println("\nWarning stopping service: ", err) + } + + err = newService.Uninstall() + if err != nil { + fmt.Println("\nError uninstalling service: ", err) + os.Exit(1) + } +} diff --git a/agent/updater/service/service.go b/agent/updater/service/service.go new file mode 100644 index 000000000..837037b09 --- /dev/null +++ b/agent/updater/service/service.go @@ -0,0 +1,43 @@ +package service + +import ( + "github.com/kardianos/service" + "github.com/utmstack/UTMStack/agent/updater/config" + "github.com/utmstack/UTMStack/agent/updater/updates" + "github.com/utmstack/UTMStack/agent/updater/utils" +) + +type program struct{} + +func (p *program) Start(s service.Service) error { + go p.run() + return nil +} + +func (p *program) Stop(s service.Service) error { + return nil +} + +func (p *program) run() { + cnf, err := config.GetCurrentConfig() + if err != nil { + utils.UpdaterLogger.ErrorF("error getting config: %v", err) + return + } + + updates.UpdateDependencies(cnf) +} + +func RunService() { + svcConfig := GetConfigServ() + prg := new(program) + newService, err := service.New(prg, svcConfig) + if err != nil { + utils.UpdaterLogger.Fatal("error creating service: %v", err) + } + + err = newService.Run() + if err != nil { + utils.UpdaterLogger.Fatal("error running service: %v", err) + } +} diff --git a/agent/updater/updates/update.go b/agent/updater/updates/update.go new file mode 100644 index 000000000..80f8779db --- /dev/null +++ b/agent/updater/updates/update.go @@ -0,0 +1,154 @@ +package updates + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "time" + + "github.com/utmstack/UTMStack/agent/updater/config" + "github.com/utmstack/UTMStack/agent/updater/models" + "github.com/utmstack/UTMStack/agent/updater/utils" +) + +const ( + checkEvery = 5 * time.Minute +) + +var currentVersion = models.Version{} + +func UpdateDependencies(cnf *config.Config) { + if utils.CheckIfPathExist(config.VersionPath) { + err := utils.ReadJson(config.VersionPath, ¤tVersion) + if err != nil { + utils.UpdaterLogger.ErrorF("error reading version file: %v", err) + } + } + + for { + time.Sleep(checkEvery) + + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, "version.json"), map[string]string{}, "version_new.json", utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.UpdaterLogger.ErrorF("error downloading version.json: %v", err) + continue + } + newVersion := models.Version{} + err := utils.ReadJson(filepath.Join(utils.GetMyPath(), "version_new.json"), &newVersion) + if err != nil { + utils.UpdaterLogger.ErrorF("error reading version file: %v", err) + continue + } + + if newVersion.Version != currentVersion.Version { + utils.UpdaterLogger.Info("New version of agent found: %s", newVersion.Version) + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.ServiceFile, "")), map[string]string{}, fmt.Sprintf(config.ServiceFile, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.UpdaterLogger.ErrorF("error downloading agent: %v", err) + continue + } + + if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { + if err = utils.Execute("chmod", utils.GetMyPath(), "-R", "755", filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.ServiceFile, "_new"))); err != nil { + utils.UpdaterLogger.ErrorF("error executing chmod: %v", err) + } + } + + utils.UpdaterLogger.Info("Starting update process...") + err = runUpdateProcess() + if err != nil { + utils.UpdaterLogger.ErrorF("error updating service: %v", err) + os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) + os.Remove(filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.ServiceFile, "_new"))) + } else { + utils.UpdaterLogger.Info("Update completed successfully") + if utils.CheckIfPathExist(config.VersionPath) { + err := utils.ReadJson(config.VersionPath, ¤tVersion) + if err != nil { + utils.UpdaterLogger.ErrorF("error reading updated version file: %v", err) + } + } + } + } else { + os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) + } + } +} + +func runUpdateProcess() error { + path := utils.GetMyPath() + + newBin := fmt.Sprintf(config.ServiceFile, "_new") + oldBin := fmt.Sprintf(config.ServiceFile, "") + backupBin := fmt.Sprintf(config.ServiceFile, ".old") + + agentNew := filepath.Join(path, newBin) + if _, err := os.Stat(agentNew); err != nil { + return fmt.Errorf("no _new binary found to update") + } + + if err := utils.StopService(config.SERV_AGENT_NAME); err != nil { + return fmt.Errorf("error stopping agent: %v", err) + } + + time.Sleep(10 * time.Second) + + backupPath := filepath.Join(path, backupBin) + if utils.CheckIfPathExist(backupPath) { + utils.UpdaterLogger.Info("Removing previous backup: %s", backupPath) + if err := os.Remove(backupPath); err != nil { + utils.UpdaterLogger.ErrorF("could not remove old backup: %v", err) + } + } + + if err := os.Rename(filepath.Join(path, oldBin), backupPath); err != nil { + return fmt.Errorf("error backing up old binary: %v", err) + } + + if err := os.Rename(filepath.Join(path, newBin), filepath.Join(path, oldBin)); err != nil { + os.Rename(backupPath, filepath.Join(path, oldBin)) + return fmt.Errorf("error renaming new binary: %v", err) + } + + if err := utils.StartService(config.SERV_AGENT_NAME); err != nil { + rollbackAgent(oldBin, backupBin, path) + return fmt.Errorf("error starting agent: %v", err) + } + + time.Sleep(30 * time.Second) + + isHealthy, err := utils.CheckIfServiceIsActive(config.SERV_AGENT_NAME) + if err != nil || !isHealthy { + utils.UpdaterLogger.Info("New version failed health check, rolling back...") + rollbackAgent(oldBin, backupBin, path) + return fmt.Errorf("rollback completed: new version failed health check") + } + + utils.UpdaterLogger.Info("Health check passed for agent") + + versionNewPath := filepath.Join(path, "version_new.json") + versionPath := filepath.Join(path, "version.json") + if utils.CheckIfPathExist(versionNewPath) { + if err := os.Rename(versionNewPath, versionPath); err != nil { + utils.UpdaterLogger.ErrorF("error updating version file: %v", err) + } else { + utils.UpdaterLogger.Info("Version file updated successfully") + } + } + + return nil +} + +func rollbackAgent(currentBin, backupBin, path string) { + utils.UpdaterLogger.Info("Rolling back agent to previous version...") + + utils.StopService(config.SERV_AGENT_NAME) + time.Sleep(5 * time.Second) + + os.Remove(filepath.Join(path, currentBin)) + os.Rename(filepath.Join(path, backupBin), filepath.Join(path, currentBin)) + + utils.StartService(config.SERV_AGENT_NAME) + os.Remove(filepath.Join(path, "version_new.json")) + + utils.UpdaterLogger.Info("Rollback completed for agent") +} diff --git a/agent/updater/utils/cmd.go b/agent/updater/utils/cmd.go new file mode 100644 index 000000000..eae4140d9 --- /dev/null +++ b/agent/updater/utils/cmd.go @@ -0,0 +1,39 @@ +package utils + +import ( + "errors" + "os/exec" + + twsdk "github.com/threatwinds/go-sdk/entities" +) + +func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { + cmd := exec.Command(c, arg...) + + cmd.Dir = dir + if errors.Is(cmd.Err, exec.ErrDot) { + cmd.Err = nil + } + + out, err := cmd.Output() + if err != nil { + return string(out[:]) + err.Error(), true + } + + if string(out[:]) == "" { + return "Command executed successfully but no output", false + } + validUtf8Out, _, err := twsdk.ValidateString(string(out[:]), false) + if err != nil { + return string(out[:]) + err.Error(), true + } + + return validUtf8Out, false +} + +func Execute(c string, dir string, arg ...string) error { + cmd := exec.Command(c, arg...) + cmd.Dir = dir + + return cmd.Run() +} diff --git a/agent/updater/utils/download.go b/agent/updater/utils/download.go new file mode 100644 index 000000000..055c44881 --- /dev/null +++ b/agent/updater/utils/download.go @@ -0,0 +1,48 @@ +package utils + +import ( + "crypto/tls" + "fmt" + "io" + "net/http" + "os" + "path/filepath" +) + +func DownloadFile(url string, headers map[string]string, fileName string, path string, skipTlsVerification bool) error { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return fmt.Errorf("error creating new request: %v", err) + } + for key, value := range headers { + req.Header.Add(key, value) + } + + client := &http.Client{} + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: skipTlsVerification}, + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("error sending request: %v", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("expected status %d; got %d", http.StatusOK, resp.StatusCode) + } + + out, err := os.Create(filepath.Join(path, fileName)) + if err != nil { + return fmt.Errorf("error creating file: %v", err) + } + defer func() { _ = out.Close() }() + + _, err = io.Copy(out, resp.Body) + if err != nil { + return fmt.Errorf("error copying file: %v", err) + } + + return nil +} diff --git a/agent/updater/utils/files.go b/agent/updater/utils/files.go new file mode 100644 index 000000000..6b0180721 --- /dev/null +++ b/agent/updater/utils/files.go @@ -0,0 +1,92 @@ +package utils + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" +) + +func GetMyPath() string { + ex, err := os.Executable() + if err != nil { + return "" + } + exPath := filepath.Dir(ex) + return exPath +} + +func CreatePathIfNotExist(path string) error { + if _, err := os.Stat(path); os.IsNotExist(err) { + if err := os.MkdirAll(path, 0755); err != nil { + return fmt.Errorf("error creating path: %v", err) + } + } else if err != nil { + return fmt.Errorf("error checking path: %v", err) + } + return nil +} + +func CheckIfPathExist(path string) bool { + if _, err := os.Stat(path); os.IsNotExist(err) { + return false + } + return true +} + +func ReadJson(fileName string, data interface{}) error { + content, err := os.ReadFile(fileName) + if err != nil { + return err + } + + err = json.Unmarshal(content, data) + if err != nil { + return err + } + + return nil +} + +func WriteStringToFile(fileName string, body string) error { + file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) + if err != nil { + return err + } + defer func() { _ = file.Close() }() + + _, err = file.WriteString(body) + return err +} + +func WriteJSON(path string, data interface{}) error { + jsonData, err := json.MarshalIndent(data, "", " ") + if err != nil { + return err + } + + err = WriteStringToFile(path, string(jsonData)) + if err != nil { + return err + } + + return nil +} + +func copyFile(src, dst string) error { + sourceFile, err := os.Open(src) + if err != nil { + return err + } + defer sourceFile.Close() + + destFile, err := os.Create(dst) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + return err +} diff --git a/agent/updater/utils/logger.go b/agent/updater/utils/logger.go new file mode 100644 index 000000000..fc0cbb757 --- /dev/null +++ b/agent/updater/utils/logger.go @@ -0,0 +1,20 @@ +package utils + +import ( + "sync" + + "github.com/threatwinds/logger" +) + +var ( + UpdaterLogger *logger.Logger + loggerOnceInstance sync.Once +) + +func InitLogger(filename string) { + loggerOnceInstance.Do(func() { + UpdaterLogger = logger.NewLogger( + &logger.Config{Format: "text", Level: 100, Output: filename, Retries: 3, Wait: 5}, + ) + }) +} diff --git a/agent/updater/utils/services.go b/agent/updater/utils/services.go new file mode 100644 index 000000000..183980245 --- /dev/null +++ b/agent/updater/utils/services.go @@ -0,0 +1,135 @@ +package utils + +import ( + "fmt" + "runtime" + "strings" +) + +func CheckIfServiceIsActive(serv string) (bool, error) { + var errB bool + var output string + path := GetMyPath() + + switch runtime.GOOS { + case "windows": + output, errB = ExecuteWithResult("sc", path, "query", serv) + case "linux": + output, errB = ExecuteWithResult("systemctl", path, "is-active", serv) + case "darwin": + output, errB = ExecuteWithResult("launchctl", path, "list", serv) + default: + return false, fmt.Errorf("unknown operating system") + } + + if errB { + return false, nil + } + + serviceStatus := strings.ToLower(strings.TrimSpace(output)) + + switch runtime.GOOS { + case "windows": + return strings.Contains(serviceStatus, "running"), nil + case "linux": + return serviceStatus == "active", nil + case "darwin": + // launchctl list returns a JSON-ish block or error.If the service is listed, it's running + return true, nil + default: + return false, fmt.Errorf("unsupported operating system") + } +} + +func RestartService(serv string) error { + path := GetMyPath() + isRunning, err := CheckIfServiceIsActive(serv) + if err != nil { + return fmt.Errorf("error checking if %s service is active: %v", serv, err) + } + + switch runtime.GOOS { + case "windows": + if isRunning { + err := Execute("sc", path, "stop", serv) + if err != nil { + return fmt.Errorf("error stopping service: %v", err) + } + } + err := Execute("sc", path, "start", serv) + if err != nil { + return fmt.Errorf("error starting service: %v", err) + } + + case "linux": + if isRunning { + err := Execute("systemctl", path, "restart", serv) + if err != nil { + return fmt.Errorf("error restarting service: %v", err) + } + } else { + err := Execute("systemctl", path, "start", serv) + if err != nil { + return fmt.Errorf("error starting service: %v", err) + } + } + case "darwin": + plistPath := fmt.Sprintf("/Library/LaunchDaemons/%s.plist", serv) + + if isRunning { + if err := Execute("launchctl", path, "remove", serv); err != nil { + return fmt.Errorf("error stopping macOS service: %v", err) + } + } + + if err := Execute("launchctl", path, "load", plistPath); err != nil { + return fmt.Errorf("error starting macOS service: %v", err) + } + } + return nil +} + +func StopService(name string) error { + path := GetMyPath() + switch runtime.GOOS { + case "windows": + err := Execute("sc", path, "stop", name) + if err != nil { + return fmt.Errorf("error stoping service: %v", err) + } + case "linux": + err := Execute("systemctl", path, "stop", name) + if err != nil { + return fmt.Errorf("error stoping service: %v", err) + } + case "darwin": + err := Execute("launchctl", path, "remove", name) + if err != nil { + return fmt.Errorf("error stopping macOS service: %v", err) + } + } + return nil +} + +func StartService(name string) error { + path := GetMyPath() + switch runtime.GOOS { + case "windows": + err := Execute("sc", path, "start", name) + if err != nil { + return fmt.Errorf("error starting service: %v", err) + } + case "linux": + err := Execute("systemctl", path, "start", name) + if err != nil { + return fmt.Errorf("error starting service: %v", err) + } + case "darwin": + plistPath := fmt.Sprintf("/Library/LaunchDaemons/%s.plist", name) + err := Execute("launchctl", path, "load", plistPath) + if err != nil { + return fmt.Errorf("error starting macOS service: %v", err) + } + } + return nil +} diff --git a/agent/updater/utils/zip.go b/agent/updater/utils/zip.go new file mode 100644 index 000000000..e8c8381b8 --- /dev/null +++ b/agent/updater/utils/zip.go @@ -0,0 +1,42 @@ +package utils + +import ( + "archive/zip" + "io" + "os" + "path" + "path/filepath" +) + +func Unzip(zipFile, destPath string) error { + archive, err := zip.OpenReader(zipFile) + if err != nil { + return err + } + defer archive.Close() + + for _, f := range archive.File { + filePath := path.Join(destPath, f.Name) + if f.FileInfo().IsDir() { + os.MkdirAll(filePath, os.ModePerm) + continue + } + if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { + return err + } + dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + fileInArchive, err := f.Open() + if err != nil { + return err + } + if _, err := io.Copy(dstFile, fileInArchive); err != nil { + return err + } + dstFile.Close() + fileInArchive.Close() + } + return nil +} From 036e3e1ac045d01371e57907ab5c8081606f0983 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Thu, 18 Dec 2025 08:48:51 -0500 Subject: [PATCH 3/4] feat(agent): implement updater service installation and management --- agent/config/const.go | 5 +- agent/config/linux_amd64.go | 2 +- agent/config/linux_arm64.go | 2 +- agent/config/macos.go | 2 +- agent/config/windows_amd64.go | 2 +- agent/config/windows_arm64.go | 2 +- agent/logs/utmstack_agent.log | 1 - agent/models/version.go | 3 +- agent/serv/clean-old.go | 62 +++--------------- agent/serv/service.go | 55 ++++++++++++++++ agent/serv/uninstall.go | 12 ++++ agent/updates/dependencies.go | 17 +++-- agent/updates/update.go | 114 +++++++++++++++++++++++++++++----- agent/utils/services.go | 58 +++++++++++++++++ agent/version.json | 3 +- 15 files changed, 257 insertions(+), 83 deletions(-) delete mode 100644 agent/logs/utmstack_agent.log diff --git a/agent/config/const.go b/agent/config/const.go index 94960361f..f7527d214 100644 --- a/agent/config/const.go +++ b/agent/config/const.go @@ -13,6 +13,10 @@ type ProtoPort struct { TCP string } +const ( + SERVICE_UPDATER_NAME = "UTMStackUpdater" +) + var ( REPLACE_KEY string @@ -41,7 +45,6 @@ var ( IntegrationKeyPath = filepath.Join(utils.GetMyPath(), "certs", "integration.key") IntegrationCAPath = filepath.Join(utils.GetMyPath(), "certs", "integration-ca.crt") - // MaxConnectionTime = 120 * time.Second // SERV_NAME = "UTMStackAgent" // SERV_LOG = "utmstack_agent.log" diff --git a/agent/config/linux_amd64.go b/agent/config/linux_amd64.go index 76c777a2b..dcd1170c4 100644 --- a/agent/config/linux_amd64.go +++ b/agent/config/linux_amd64.go @@ -4,7 +4,7 @@ package config var ( - UpdaterSelf = "utmstack_updater_self%s" ServiceFile = "utmstack_agent_service%s" + UpdaterFile = "utmstack_updater_service%s" DependFiles = []string{"utmstack_agent_dependencies_linux.zip"} ) diff --git a/agent/config/linux_arm64.go b/agent/config/linux_arm64.go index 138c70002..3e0e5e3be 100644 --- a/agent/config/linux_arm64.go +++ b/agent/config/linux_arm64.go @@ -4,7 +4,7 @@ package config var ( - UpdaterSelf = "utmstack_updater_self_arm64%s" ServiceFile = "utmstack_agent_service_arm64%s" + UpdaterFile = "utmstack_updater_service_arm64%s" DependFiles = []string{"utmstack_agent_dependencies_linux_arm64.zip"} ) diff --git a/agent/config/macos.go b/agent/config/macos.go index feef8b2fb..ed03e70d8 100644 --- a/agent/config/macos.go +++ b/agent/config/macos.go @@ -4,7 +4,7 @@ package config var ( - UpdaterSelf = "utmstack_updater_self%s" ServiceFile = "utmstack_agent_service%s" + UpdaterFile = "utmstack_updater_service%s" DependFiles = []string{} ) diff --git a/agent/config/windows_amd64.go b/agent/config/windows_amd64.go index af4490cd0..f055d2dca 100644 --- a/agent/config/windows_amd64.go +++ b/agent/config/windows_amd64.go @@ -4,7 +4,7 @@ package config var ( - UpdaterSelf = "utmstack_updater_self%s.exe" ServiceFile = "utmstack_agent_service%s.exe" + UpdaterFile = "utmstack_updater_service%s.exe" DependFiles = []string{"utmstack_agent_dependencies_windows.zip"} ) diff --git a/agent/config/windows_arm64.go b/agent/config/windows_arm64.go index aa136d400..9bd38ffca 100644 --- a/agent/config/windows_arm64.go +++ b/agent/config/windows_arm64.go @@ -4,7 +4,7 @@ package config var ( - UpdaterSelf = "utmstack_updater_self_arm64%s.exe" ServiceFile = "utmstack_agent_service_arm64%s.exe" + UpdaterFile = "utmstack_updater_service_arm64%s.exe" DependFiles = []string{"utmstack_agent_dependencies_windows_arm64.zip"} ) diff --git a/agent/logs/utmstack_agent.log b/agent/logs/utmstack_agent.log deleted file mode 100644 index 602489253..000000000 --- a/agent/logs/utmstack_agent.log +++ /dev/null @@ -1 +0,0 @@ -2025-04-16T13:37:14.854518Z ERROR f18ed04e-83e4-49d7-b82b-b96385b8b0bd /Users/osmany/Projects/UTMStack/agent/serv/service.go 36 error getting config: error reading config file: open /Users/osmany/Projects/UTMStack/agent/config.yml: no such file or directory diff --git a/agent/models/version.go b/agent/models/version.go index ed01f06e4..1ee6e0648 100644 --- a/agent/models/version.go +++ b/agent/models/version.go @@ -1,5 +1,6 @@ package models type Version struct { - Version string `json:"version"` + Version string `json:"version"` + UpdaterVersion string `json:"updater_version"` } diff --git a/agent/serv/clean-old.go b/agent/serv/clean-old.go index 6369a9ebd..06317deab 100644 --- a/agent/serv/clean-old.go +++ b/agent/serv/clean-old.go @@ -1,76 +1,30 @@ package serv import ( - "fmt" - "os" - "path/filepath" - "runtime" - "github.com/utmstack/UTMStack/agent/config" "github.com/utmstack/UTMStack/agent/utils" ) func CleanOldServices(cnf *config.Config) { - oldVersion := false - - isUpdaterINstalled, err := utils.CheckIfServiceIsInstalled("UTMStackUpdater") - if err != nil { - utils.Logger.LogF(100, "error checking if service is installed: %v", err) - } - - if isUpdaterINstalled { - oldVersion = true - err = utils.StopService("UTMStackUpdater") - if err != nil { - utils.Logger.LogF(100, "error stopping service: %v", err) - } - - err = utils.UninstallService("UTMStackUpdater") - if err != nil { - utils.Logger.LogF(100, "error uninstalling service: %v", err) - } - } - isRedlineInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackRedline") if err != nil { - utils.Logger.LogF(100, "error checking if service is installed: %v", err) + utils.Logger.LogF(100, "error checking if UTMStackRedline service is installed: %v", err) + return } if isRedlineInstalled { - oldVersion = true + utils.Logger.Info("old UTMStackRedline service found, removing...") + err = utils.StopService("UTMStackRedline") if err != nil { - utils.Logger.LogF(100, "error stopping service: %v", err) + utils.Logger.LogF(100, "error stopping UTMStackRedline service: %v", err) } err = utils.UninstallService("UTMStackRedline") if err != nil { - utils.Logger.LogF(100, "error uninstalling service: %v", err) - } - } - - if oldVersion { - utils.Logger.Info("old version of agent found, downloading new version") - if runtime.GOOS != "darwin" { - if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.UpdaterSelf, "")), map[string]string{}, fmt.Sprintf(config.UpdaterSelf, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { - utils.Logger.LogF(100, "error downloading updater: %v", err) - return - } - } - - oldFilePath := filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterSelf, "")) - newFilePath := filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterSelf, "_new")) - - utils.Logger.LogF(100, "renaming %s to %s", newFilePath, oldFilePath) - err := os.Remove(oldFilePath) - if err != nil { - utils.Logger.LogF(100, "error removing old updater: %v", err) - } - err = os.Rename(newFilePath, oldFilePath) - if err != nil { - utils.Logger.LogF(100, "error renaming updater: %v", err) + utils.Logger.LogF(100, "error uninstalling UTMStackRedline service: %v", err) + } else { + utils.Logger.Info("UTMStackRedline service removed successfully") } - } else { - utils.Logger.LogF(100, "no old version of agent found") } } diff --git a/agent/serv/service.go b/agent/serv/service.go index 8206cb220..1016ec933 100644 --- a/agent/serv/service.go +++ b/agent/serv/service.go @@ -2,8 +2,11 @@ package serv import ( "context" + "fmt" "os" "os/signal" + "path/filepath" + "runtime" "strconv" "syscall" @@ -36,6 +39,9 @@ func (p *program) run() { utils.Logger.Fatal("error getting config: %v", err) } + // Ensure updater service is installed + ensureUpdaterServiceInstalled() + CleanOldServices(cnf) ctx, cancel := context.WithCancel(context.Background()) @@ -60,3 +66,52 @@ func (p *program) run() { signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) <-signals } + +func ensureUpdaterServiceInstalled() { + isInstalled, err := utils.CheckIfServiceIsInstalled("UTMStackUpdater") + if err != nil { + utils.Logger.ErrorF("error checking if updater service is installed: %v", err) + return + } + + if isInstalled { + utils.Logger.Info("updater service is already installed") + return + } + + utils.Logger.Info("updater service not found, installing...") + + updaterPath := filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterFile, "")) + + if !utils.CheckIfPathExist(updaterPath) { + + cnf, err := config.GetCurrentConfig() + if err != nil { + utils.Logger.ErrorF("error getting config to download updater: %v", err) + return + } + + updaterBinary := fmt.Sprintf(config.UpdaterFile, "") + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, updaterBinary), map[string]string{}, updaterBinary, utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.Logger.ErrorF("error downloading updater binary: %v", err) + return + } + + if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { + if err := utils.Execute("chmod", utils.GetMyPath(), "755", updaterBinary); err != nil { + utils.Logger.ErrorF("error setting permissions on updater: %v", err) + return + } + } + + utils.Logger.Info("updater binary downloaded successfully") + } + + err = utils.Execute(updaterPath, utils.GetMyPath(), "install") + if err != nil { + utils.Logger.ErrorF("error installing updater service: %v", err) + return + } + + utils.Logger.Info("updater service installed successfully") +} diff --git a/agent/serv/uninstall.go b/agent/serv/uninstall.go index 644bc713a..e789c4ea8 100644 --- a/agent/serv/uninstall.go +++ b/agent/serv/uninstall.go @@ -9,8 +9,20 @@ func UninstallService() { if err != nil { utils.Logger.Fatal("error stopping UTMStackAgent: %v", err) } + err = utils.StopService("UTMStackUpdater") + if err != nil { + utils.Logger.Fatal("error stopping UTMStackUpdater: %v", err) + } + err = utils.UninstallService("UTMStackAgent") + if err != nil { + utils.Logger.Fatal("error uninstalling UTMStackAgent: %v", err) + } err = utils.UninstallService("UTMStackAgent") if err != nil { utils.Logger.Fatal("error uninstalling UTMStackAgent: %v", err) } + err = utils.UninstallService("UTMStackUpdater") + if err != nil { + utils.Logger.Fatal("error uninstalling UTMStackUpdater: %v", err) + } } diff --git a/agent/updates/dependencies.go b/agent/updates/dependencies.go index 5b6e13b5d..914740be4 100644 --- a/agent/updates/dependencies.go +++ b/agent/updates/dependencies.go @@ -16,6 +16,17 @@ func DownloadFirstDependencies(address string, authKey string, insecure bool) er return fmt.Errorf("error downloading version.json : %v", err) } + updaterBinary := fmt.Sprintf(config.UpdaterFile, "") + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, address, config.DependenciesPort, updaterBinary), map[string]string{}, updaterBinary, utils.GetMyPath(), insecure); err != nil { + return fmt.Errorf("error downloading updater binary %s: %v", updaterBinary, err) + } + + if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { + if err := utils.Execute("chmod", utils.GetMyPath(), "755", updaterBinary); err != nil { + return fmt.Errorf("error setting permissions on updater: %v", err) + } + } + dependFiles := config.DependFiles for _, file := range dependFiles { if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, address, config.DependenciesPort, file), map[string]string{}, file, utils.GetMyPath(), insecure); err != nil { @@ -38,12 +49,6 @@ func handleDependenciesPostDownload(dependencies []string) error { return fmt.Errorf("error unzipping dependencies: %v", err) } - if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { - if err := utils.Execute("chmod", utils.GetMyPath(), "-R", "755", fmt.Sprintf(config.UpdaterSelf, "")); err != nil { - return fmt.Errorf("error executing chmod on %s: %v", fmt.Sprintf(config.UpdaterSelf, ""), err) - } - } - if err := os.Remove(filepath.Join(utils.GetMyPath(), file)); err != nil { return fmt.Errorf("error removing file %s: %v", file, err) } diff --git a/agent/updates/update.go b/agent/updates/update.go index 0663ed57f..0d743734d 100644 --- a/agent/updates/update.go +++ b/agent/updates/update.go @@ -40,29 +40,115 @@ func UpdateDependencies(cnf *config.Config) { continue } - if newVersion.Version != currentVersion.Version { - utils.Logger.Info("New version of agent found: %s", newVersion.Version) - if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.ServiceFile, "")), map[string]string{}, fmt.Sprintf(config.ServiceFile, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { - utils.Logger.ErrorF("error downloading agent: %v", err) - continue - } - - currentVersion = newVersion - err = utils.WriteJSON(config.VersionPath, ¤tVersion) - if err != nil { - utils.Logger.ErrorF("error writing version file: %v", err) + if newVersion.UpdaterVersion != currentVersion.UpdaterVersion { + utils.Logger.Info("New version of updater found: %s", newVersion.UpdaterVersion) + if err := utils.DownloadFile(fmt.Sprintf(config.DependUrl, cnf.Server, config.DependenciesPort, fmt.Sprintf(config.UpdaterFile, "")), map[string]string{}, fmt.Sprintf(config.UpdaterFile, "_new"), utils.GetMyPath(), cnf.SkipCertValidation); err != nil { + utils.Logger.ErrorF("error downloading updater: %v", err) continue } if runtime.GOOS == "linux" || runtime.GOOS == "darwin" { - if err = utils.Execute("chmod", utils.GetMyPath(), "-R", "755", filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.ServiceFile, "_new"))); err != nil { + if err = utils.Execute("chmod", utils.GetMyPath(), "-R", "755", filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterFile, "_new"))); err != nil { utils.Logger.ErrorF("error executing chmod: %v", err) } } - utils.Execute(fmt.Sprintf(config.UpdaterSelf, ""), utils.GetMyPath()) + utils.Logger.Info("Starting updater update process...") + err = runUpdateProcess() + if err != nil { + utils.Logger.ErrorF("error updating updater: %v", err) + os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) + os.Remove(filepath.Join(utils.GetMyPath(), fmt.Sprintf(config.UpdaterFile, "_new"))) + } else { + utils.Logger.Info("Updater update completed successfully") + if utils.CheckIfPathExist(config.VersionPath) { + err := utils.ReadJson(config.VersionPath, ¤tVersion) + if err != nil { + utils.Logger.ErrorF("error reading updated version file: %v", err) + } + } + } + } else { + os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) } + } +} + +func runUpdateProcess() error { + path := utils.GetMyPath() + + newBin := fmt.Sprintf(config.UpdaterFile, "_new") + oldBin := fmt.Sprintf(config.UpdaterFile, "") + backupBin := fmt.Sprintf(config.UpdaterFile, ".old") + + updaterNew := filepath.Join(path, newBin) + if _, err := os.Stat(updaterNew); err != nil { + return fmt.Errorf("no _new binary found to update") + } + + if err := utils.StopService(config.SERVICE_UPDATER_NAME); err != nil { + return fmt.Errorf("error stopping updater: %v", err) + } + + time.Sleep(10 * time.Second) + + backupPath := filepath.Join(path, backupBin) + if utils.CheckIfPathExist(backupPath) { + utils.Logger.Info("Removing previous backup: %s", backupPath) + if err := os.Remove(backupPath); err != nil { + utils.Logger.ErrorF("could not remove old backup: %v", err) + } + } - os.Remove(filepath.Join(utils.GetMyPath(), "version_new.json")) + if err := os.Rename(filepath.Join(path, oldBin), backupPath); err != nil { + return fmt.Errorf("error backing up old binary: %v", err) } + + if err := os.Rename(filepath.Join(path, newBin), filepath.Join(path, oldBin)); err != nil { + os.Rename(backupPath, filepath.Join(path, oldBin)) + return fmt.Errorf("error renaming new binary: %v", err) + } + + if err := utils.StartService(config.SERVICE_UPDATER_NAME); err != nil { + rollbackUpdater(oldBin, backupBin, path) + return fmt.Errorf("error starting updater: %v", err) + } + + time.Sleep(30 * time.Second) + + isHealthy, err := utils.CheckIfServiceIsActive(config.SERVICE_UPDATER_NAME) + if err != nil || !isHealthy { + utils.Logger.Info("New version failed health check, rolling back...") + rollbackUpdater(oldBin, backupBin, path) + return fmt.Errorf("rollback completed: new version failed health check") + } + + utils.Logger.Info("Health check passed for updater") + + versionNewPath := filepath.Join(path, "version_new.json") + versionPath := filepath.Join(path, "version.json") + if utils.CheckIfPathExist(versionNewPath) { + if err := os.Rename(versionNewPath, versionPath); err != nil { + utils.Logger.ErrorF("error updating version file: %v", err) + } else { + utils.Logger.Info("Version file updated successfully") + } + } + + return nil +} + +func rollbackUpdater(currentBin, backupBin, path string) { + utils.Logger.Info("Rolling back updater to previous version...") + + utils.StopService(config.SERVICE_UPDATER_NAME) + time.Sleep(5 * time.Second) + + os.Remove(filepath.Join(path, currentBin)) + os.Rename(filepath.Join(path, backupBin), filepath.Join(path, currentBin)) + + utils.StartService(config.SERVICE_UPDATER_NAME) + os.Remove(filepath.Join(path, "version_new.json")) + + utils.Logger.Info("Rollback completed for updater") } diff --git a/agent/utils/services.go b/agent/utils/services.go index 04a9d9401..a0a828d3f 100644 --- a/agent/utils/services.go +++ b/agent/utils/services.go @@ -4,8 +4,66 @@ import ( "fmt" "os" "runtime" + "strings" ) +func CheckIfServiceIsActive(serv string) (bool, error) { + var errB bool + var output string + path := GetMyPath() + + switch runtime.GOOS { + case "windows": + output, errB = ExecuteWithResult("sc", path, "query", serv) + case "linux": + output, errB = ExecuteWithResult("systemctl", path, "is-active", serv) + case "darwin": + output, errB = ExecuteWithResult("launchctl", path, "list", serv) + default: + return false, fmt.Errorf("unknown operating system") + } + + if errB { + return false, nil + } + + serviceStatus := strings.ToLower(strings.TrimSpace(output)) + + switch runtime.GOOS { + case "windows": + return strings.Contains(serviceStatus, "running"), nil + case "linux": + return serviceStatus == "active", nil + case "darwin": + return true, nil + default: + return false, fmt.Errorf("unsupported operating system") + } +} + +func StartService(name string) error { + path := GetMyPath() + switch runtime.GOOS { + case "windows": + err := Execute("sc", path, "start", name) + if err != nil { + return fmt.Errorf("error starting service: %v", err) + } + case "linux": + err := Execute("systemctl", path, "start", name) + if err != nil { + return fmt.Errorf("error starting service: %v", err) + } + case "darwin": + plistPath := fmt.Sprintf("/Library/LaunchDaemons/%s.plist", name) + err := Execute("launchctl", path, "load", plistPath) + if err != nil { + return fmt.Errorf("error starting macOS service: %v", err) + } + } + return nil +} + func StopService(name string) error { path := GetMyPath() switch runtime.GOOS { diff --git a/agent/version.json b/agent/version.json index 2a8d9f74f..219ee83b4 100644 --- a/agent/version.json +++ b/agent/version.json @@ -1,3 +1,4 @@ { - "version": "10.8.1" + "version": "10.9.0", + "updater_version": "1.0.0" } From 850a5460ac0f86c77875baac536025b8a2d123d4 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Thu, 18 Dec 2025 08:50:49 -0500 Subject: [PATCH 4/4] feat(action): update build process to include updater service binaries --- .github/workflows/v10-deployment-pipeline.yml | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/v10-deployment-pipeline.yml b/.github/workflows/v10-deployment-pipeline.yml index 3e6c9c17c..cc3eee7ab 100644 --- a/.github/workflows/v10-deployment-pipeline.yml +++ b/.github/workflows/v10-deployment-pipeline.yml @@ -67,7 +67,7 @@ jobs: - name: Check out code into the right branch uses: actions/checkout@v4 - - name: Build Linux Agent + - name: Build Linux Binaries (Agent & Updater) env: GOOS: linux GOARCH: amd64 @@ -75,7 +75,10 @@ jobs: cd ${{ github.workspace }}/agent go build -o utmstack_agent_service -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . - - name: Build Windows Agent (amd64) + cd ${{ github.workspace }}/agent/updater + go build -o utmstack_updater_service . + + - name: Build Windows Binaries (amd64) env: GOOS: windows GOARCH: amd64 @@ -83,7 +86,10 @@ jobs: cd ${{ github.workspace }}/agent go build -o utmstack_agent_service.exe -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . - - name: Build Windows Agent (arm64) + cd ${{ github.workspace }}/agent/updater + go build -o utmstack_updater_service.exe . + + - name: Build Windows Binaries (arm64) env: GOOS: windows GOARCH: arm64 @@ -91,12 +97,20 @@ jobs: cd ${{ github.workspace }}/agent go build -o utmstack_agent_service_arm64.exe -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . + cd ${{ github.workspace }}/agent/updater + go build -o utmstack_updater_service_arm64.exe . + - name: Sign Windows Agents run: | cd ${{ github.workspace }}/agent signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service.exe" signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_agent_service_arm64.exe" + cd ${{ github.workspace }}/agent/updater + signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_updater_service.exe" + signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f "${{ vars.SIGN_CERT }}" /csp "eToken Base Cryptographic Provider" /k "[{{${{ secrets.SIGN_KEY }}}}]=${{ secrets.SIGN_CONTAINER }}" "utmstack_updater_service_arm64.exe" + + - name: Upload signed binaries as artifacts uses: actions/upload-artifact@v4 with: @@ -105,6 +119,9 @@ jobs: ${{ github.workspace }}/agent/utmstack_agent_service ${{ github.workspace }}/agent/utmstack_agent_service.exe ${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe + ${{ github.workspace }}/agent/updater/utmstack_updater_service + ${{ github.workspace }}/agent/updater/utmstack_updater_service.exe + ${{ github.workspace }}/agent/updater/utmstack_updater_service_arm64.exe retention-days: 1 build_agent_manager: @@ -140,6 +157,10 @@ jobs: cp "${{ github.workspace }}/agent/utmstack_agent_service.exe" ./dependencies/agent/ cp "${{ github.workspace }}/agent/utmstack_agent_service_arm64.exe" ./dependencies/agent/ cp "${{ github.workspace }}/agent/version.json" ./dependencies/agent/ + + cp "${{ github.workspace }}/agent/updater/utmstack_updater_service" ./dependencies/agent/ + cp "${{ github.workspace }}/agent/updater/utmstack_updater_service.exe" ./dependencies/agent/ + cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_arm64.exe" ./dependencies/agent/ - name: Login to GitHub Container Registry uses: docker/login-action@v3