From cb586b5591e7863e3531384571765bfad654887c Mon Sep 17 00:00:00 2001 From: Yorjander Hernandez Vergara <99102374+Kbayero@users.noreply.github.com> Date: Fri, 5 Jan 2024 15:22:31 +0200 Subject: [PATCH] Update agent version and fix agent update based on master version (#227) --- agent/updater/configuration/config.go | 13 ++- agent/updater/configuration/const.go | 70 ++++++++++++++ agent/updater/constants/const.go | 73 -------------- agent/updater/main.go | 34 ++++--- agent/updater/serv/config.go | 4 +- agent/updater/serv/install.go | 9 +- agent/updater/serv/run.go | 7 +- agent/updater/serv/service.go | 8 +- agent/updater/serv/uninstall.go | 13 +-- agent/updater/updates/compare.go | 51 ---------- agent/updater/updates/service.go | 96 ++++++++----------- agent/updater/updates/update.go | 28 +++--- agent/updater/updates/version.go | 20 +++- agent/updater/utils/cmd.go | 35 +++---- agent/updater/utils/delay.go | 1 + agent/updater/utils/files.go | 43 +++++---- agent/updater/utils/lock.go | 2 + agent/updater/utils/req.go | 1 + agent/updater/utils/services.go | 2 + agent/updater/utils/timestamp.go | 1 + agent/updater/utils/tls.go | 1 + .../guide-linux-agent.component.ts | 6 +- 22 files changed, 240 insertions(+), 278 deletions(-) create mode 100644 agent/updater/configuration/const.go delete mode 100644 agent/updater/constants/const.go delete mode 100644 agent/updater/updates/compare.go diff --git a/agent/updater/configuration/config.go b/agent/updater/configuration/config.go index 3cd8adf52..c3e47b1a1 100644 --- a/agent/updater/configuration/config.go +++ b/agent/updater/configuration/config.go @@ -18,22 +18,25 @@ type Environment struct { Branch string `yaml:"branch"` } -func ReadEnv() (*Environment, error) { +// ReadEnv reads the environment file +// If the file does not exist, it returns a default environment with release branch +// If the file exists, it returns the environment +func ReadEnv() (string, error) { var env Environment path, err := utils.GetMyPath() if err != nil { - return nil, err + return "", err } path = filepath.Join(path, "env.yml") if _, err = os.Stat(path); os.IsNotExist(err) { - return &Environment{Branch: "release"}, nil + return "release", nil } else { err = utils.ReadYAML(path, &env) if err != nil { - return nil, err + return "", err } } - return &env, nil + return env.Branch, nil } diff --git a/agent/updater/configuration/const.go b/agent/updater/configuration/const.go new file mode 100644 index 000000000..2e89a5c31 --- /dev/null +++ b/agent/updater/configuration/const.go @@ -0,0 +1,70 @@ +package configuration + +import ( + "path/filepath" + "runtime" + "time" + + "github.com/utmstack/UTMStack/agent/updater/utils" +) + +const ( + SERV_NAME = "UTMStackUpdater" + SERV_LOG = "utmstack_updater.log" + SERV_LOCK = "utmstack_updater.lock" + MASTERVERSIONENDPOINT = "/management/info" + Bucket = "https://cdn.utmstack.com/agent_updates/" + CHECK_EVERY = 5 * time.Minute +) + +type ServiceAttribt struct { + ServName string + ServBin string + ServLock string +} + +// GetServAttr returns a map of ServiceAttribt +func GetServAttr() map[string]ServiceAttribt { + serAttr := map[string]ServiceAttribt{ + "agent": {ServName: "UTMStackAgent", ServBin: "utmstack_agent_service", ServLock: "utmstack_agent.lock"}, + "updater": {ServName: "UTMStackUpdater", ServBin: "utmstack_updater_self", ServLock: "utmstack_updater.lock"}, + "redline": {ServName: "UTMStackRedline", ServBin: "utmstack_redline_service", ServLock: "utmstack_redline.lock"}, + } + + switch runtime.GOOS { + case "windows": + for code, att := range serAttr { + att.ServBin += ".exe" + serAttr[code] = att + } + } + + return serAttr +} + +// GetAgentBin returns the agent binary name +func GetAgentBin() string { + bin := "utmstack_agent_service" + if runtime.GOOS == "windows" { + bin = bin + ".exe" + } + return bin +} + +// GetCertPath returns the path to the certificate +func GetCertPath() string { + path, _ := utils.GetMyPath() + return filepath.Join(path, "certs", "utm.crt") +} + +// GetKeyPath returns the path to the key +func GetKeyPath() string { + path, _ := utils.GetMyPath() + return filepath.Join(path, "certs", "utm.key") +} + +// GetCaPath returns the path to the CA +func GetCaPath() string { + path, _ := utils.GetMyPath() + return filepath.Join(path, "certs", "ca.crt") +} diff --git a/agent/updater/constants/const.go b/agent/updater/constants/const.go deleted file mode 100644 index 9e3de6c17..000000000 --- a/agent/updater/constants/const.go +++ /dev/null @@ -1,73 +0,0 @@ -package constants - -import ( - "path/filepath" - "runtime" - "time" - - "github.com/utmstack/UTMStack/agent/updater/utils" -) - -const ( - SERV_NAME = "UTMStackUpdater" - SERV_LOG = "utmstack_updater.log" - SERV_LOCK = "utmstack_updater.lock" - MASTERVERSIONENDPOINT = "/management/info" - Bucket = "https://cdn.utmstack.com/agent_updates/" -) - -type ServiceAttribt struct { - ServName string - ServBin string - ServLock string -} - -var ( - CheckUpdatesEvery = time.Duration(5 * time.Minute) -) - -func GetServAttr() map[string]ServiceAttribt { - serAttr := map[string]ServiceAttribt{} - - switch runtime.GOOS { - case "windows": - serAttr["agent"] = ServiceAttribt{ServName: "UTMStackAgent", ServBin: "utmstack_agent_service.exe", ServLock: "utmstack_agent.lock"} - serAttr["filebeat"] = ServiceAttribt{ServName: "UTMStackModulesLogsCollector", ServBin: "utmstack_agent_service.exe", ServLock: "utmstack_modules_collector.lock"} - serAttr["winlogbeat"] = ServiceAttribt{ServName: "UTMStackWindowsLogsCollector", ServBin: "utmstack_agent_service.exe", ServLock: "utmstack_windows_collector.lock"} - serAttr["updater"] = ServiceAttribt{ServName: "UTMStackUpdater", ServBin: "utmstack_updater_self.exe", ServLock: "utmstack_updater.lock"} - serAttr["redline"] = ServiceAttribt{ServName: "UTMStackRedline", ServBin: "utmstack_redline_service.exe", ServLock: "utmstack_redline.lock"} - case "linux": - serAttr["agent"] = ServiceAttribt{ServName: "UTMStackAgent", ServBin: "utmstack_agent_service", ServLock: "utmstack_agent.lock"} - serAttr["filebeat"] = ServiceAttribt{ServName: "UTMStackModulesLogsCollector", ServBin: "utmstack_agent_service", ServLock: "utmstack_modules_collector.lock"} - serAttr["winlogbeat"] = ServiceAttribt{ServName: "UTMStackWindowsLogsCollector", ServBin: "utmstack_agent_service", ServLock: "utmstack_windows_collector.lock"} - serAttr["updater"] = ServiceAttribt{ServName: "UTMStackUpdater", ServBin: "utmstack_updater_self", ServLock: "utmstack_updater.lock"} - serAttr["redline"] = ServiceAttribt{ServName: "UTMStackRedline", ServBin: "utmstack_redline_service", ServLock: "utmstack_redline.lock"} - } - return serAttr -} - -func GetAgentBin() string { - var bin string - switch runtime.GOOS { - case "windows": - bin = "utmstack_agent_service.exe" - case "linux": - bin = "utmstack_agent_service" - } - return bin -} - -func GetCertPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "utm.crt") -} - -func GetKeyPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "utm.key") -} - -func GetCaPath() string { - path, _ := utils.GetMyPath() - return filepath.Join(path, "certs", "ca.crt") -} diff --git a/agent/updater/main.go b/agent/updater/main.go index 911cdc919..42ccb6641 100644 --- a/agent/updater/main.go +++ b/agent/updater/main.go @@ -8,23 +8,21 @@ import ( "time" "github.com/quantfall/holmes" - "github.com/utmstack/UTMStack/agent/updater/constants" + "github.com/utmstack/UTMStack/agent/updater/configuration" "github.com/utmstack/UTMStack/agent/updater/serv" "github.com/utmstack/UTMStack/agent/updater/utils" ) -var h = holmes.New("debug", constants.SERV_NAME) +var utmLogger = holmes.New("debug", configuration.SERV_NAME) func main() { - // Get current path path, err := utils.GetMyPath() if err != nil { - fmt.Printf("Failed to get current path: %v", err) - h.FatalError("Failed to get current path: %v", err) + fmt.Printf("failed to get current path: %v", err) + utmLogger.FatalError("failed to get current path: %v", err) } - // Configuring log saving - var logger = utils.CreateLogger(filepath.Join(path, "logs", constants.SERV_LOG)) + var logger = utils.CreateLogger(filepath.Join(path, "logs", configuration.SERV_LOG)) defer logger.Close() log.SetOutput(logger) @@ -32,25 +30,25 @@ func main() { mode := os.Args[1] switch mode { case "run": - serv.RunService(h) + serv.RunService(utmLogger) case "install": - h.Info("Installing UTMStack Updater service...") + utmLogger.Info("Installing UTMStack Updater service...") - if isInstalled, err := utils.CheckIfServiceIsInstalled(constants.SERV_NAME); err != nil { - h.FatalError("error checking %s service: %v", constants.SERV_NAME, err) + if isInstalled, err := utils.CheckIfServiceIsInstalled(configuration.SERV_NAME); err != nil { + utmLogger.FatalError("error checking %s service: %v", configuration.SERV_NAME, err) } else if isInstalled { - h.FatalError("%s is already installed", constants.SERV_NAME) + utmLogger.FatalError("%s is already installed", configuration.SERV_NAME) } - serv.InstallService(h) - h.Info("UTMStack Updater service installed correctly.") + serv.InstallService(utmLogger) + utmLogger.Info("UTMStack Updater service installed correctly.") time.Sleep(5 * time.Second) os.Exit(0) case "uninstall": - h.Info("Uninstalling UTMStack Updater service...") - serv.UninstallService(h) - h.Info("UTMStack Updater service uninstalled correctly.") + utmLogger.Info("Uninstalling UTMStack Updater service...") + serv.UninstallService(utmLogger) + utmLogger.Info("UTMStack Updater service uninstalled correctly.") time.Sleep(5 * time.Second) os.Exit(0) @@ -58,6 +56,6 @@ func main() { fmt.Println("unknown option") } } else { - serv.RunService(h) + serv.RunService(utmLogger) } } diff --git a/agent/updater/serv/config.go b/agent/updater/serv/config.go index 3971abf47..05c68ddf9 100644 --- a/agent/updater/serv/config.go +++ b/agent/updater/serv/config.go @@ -2,13 +2,13 @@ package serv import ( "github.com/kardianos/service" - "github.com/utmstack/UTMStack/agent/updater/constants" + "github.com/utmstack/UTMStack/agent/updater/configuration" ) // GetConfigServ creates and returns a pointer to a service configuration structure. func GetConfigServ() *service.Config { svcConfig := &service.Config{ - Name: constants.SERV_NAME, + Name: configuration.SERV_NAME, DisplayName: "UTMStack Updater", Description: "UTMStack Updater Service", } diff --git a/agent/updater/serv/install.go b/agent/updater/serv/install.go index 8bed64710..463b01432 100644 --- a/agent/updater/serv/install.go +++ b/agent/updater/serv/install.go @@ -7,24 +7,25 @@ import ( "github.com/quantfall/holmes" ) -func InstallService(h *holmes.Logger) { +// InstallService installs the service in the system and starts it +func InstallService(utmLogger *holmes.Logger) { svcConfig := GetConfigServ() prg := new(program) newService, err := service.New(prg, svcConfig) if err != nil { fmt.Printf("error creating new service: %v", err) - h.FatalError("error creating new service: %v", err) + utmLogger.FatalError("error creating new service: %v", err) } err = newService.Install() if err != nil { fmt.Printf("error installing new service: %v", err) - h.FatalError("error installing new service: %v", err) + utmLogger.FatalError("error installing new service: %v", err) } // Start the service after installing it err = newService.Start() if err != nil { fmt.Printf("error starting new service: %v", err) - h.FatalError("error starting new service: %v", err) + utmLogger.FatalError("error starting new service: %v", err) } } diff --git a/agent/updater/serv/run.go b/agent/updater/serv/run.go index e5bdecb56..c737c044e 100644 --- a/agent/updater/serv/run.go +++ b/agent/updater/serv/run.go @@ -5,15 +5,16 @@ import ( "github.com/quantfall/holmes" ) -func RunService(h *holmes.Logger) { +// RunService runs the service in the system +func RunService(utmLogger *holmes.Logger) { svcConfig := GetConfigServ() prg := new(program) newService, err := service.New(prg, svcConfig) if err != nil { - h.FatalError("error creating new service: %v", err) + utmLogger.FatalError("error creating new service: %v", err) } err = newService.Run() if err != nil { - h.FatalError("error running new service: %v", err) + utmLogger.FatalError("error running new service: %v", err) } } diff --git a/agent/updater/serv/service.go b/agent/updater/serv/service.go index 8dd2e5d77..319c5dbb0 100644 --- a/agent/updater/serv/service.go +++ b/agent/updater/serv/service.go @@ -10,12 +10,11 @@ import ( "github.com/kardianos/service" "github.com/quantfall/holmes" "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/constants" "github.com/utmstack/UTMStack/agent/updater/updates" "github.com/utmstack/UTMStack/agent/updater/utils" ) -var h = holmes.New("debug", constants.SERV_NAME) +var h = holmes.New("debug", configuration.SERV_NAME) type program struct{} @@ -30,10 +29,10 @@ func (p *program) Stop(s service.Service) error { func (p *program) run() { for { - isActive, err := utils.CheckIfServiceIsActive(constants.GetServAttr()["agent"].ServName) + isActive, err := utils.CheckIfServiceIsActive(configuration.GetServAttr()["agent"].ServName) if err != nil { time.Sleep(time.Second * 5) - h.Error("error checking if %s service is active: %v", constants.GetServAttr()["agent"].ServName, err) + h.Error("error checking if %s service is active: %v", configuration.GetServAttr()["agent"].ServName, err) continue } else if !isActive { time.Sleep(time.Second * 5) @@ -47,7 +46,6 @@ func (p *program) run() { h.FatalError("failed to get current path: %v", err) } - // Read config.yml var cnf configuration.Config err = utils.ReadYAML(filepath.Join(path, "config.yml"), &cnf) if err != nil { diff --git a/agent/updater/serv/uninstall.go b/agent/updater/serv/uninstall.go index 7c9f5c1cd..a375ba1e5 100644 --- a/agent/updater/serv/uninstall.go +++ b/agent/updater/serv/uninstall.go @@ -2,18 +2,19 @@ package serv import ( "github.com/quantfall/holmes" - "github.com/utmstack/UTMStack/agent/updater/constants" + "github.com/utmstack/UTMStack/agent/updater/configuration" "github.com/utmstack/UTMStack/agent/updater/utils" ) -func UninstallService(h *holmes.Logger) { +// UninstallService uninstalls the service in the system +func UninstallService(utmLogger *holmes.Logger) { // Uninstall service - err := utils.StopService(constants.SERV_NAME) + err := utils.StopService(configuration.SERV_NAME) if err != nil { - h.FatalError("error stopping %s: %v", constants.SERV_NAME, err) + utmLogger.FatalError("error stopping %s: %v", configuration.SERV_NAME, err) } - err = utils.UninstallService(constants.SERV_NAME) + err = utils.UninstallService(configuration.SERV_NAME) if err != nil { - h.FatalError("error uninstalling %s: %v", constants.SERV_NAME, err) + utmLogger.FatalError("error uninstalling %s: %v", configuration.SERV_NAME, err) } } diff --git a/agent/updater/updates/compare.go b/agent/updater/updates/compare.go deleted file mode 100644 index 13236fa35..000000000 --- a/agent/updater/updates/compare.go +++ /dev/null @@ -1,51 +0,0 @@ -package updates - -import ( - "sort" - "strconv" - "strings" -) - -func GetLatestVersion(versions DataVersions, masterVersions string) Version { - latestVersions := Version{} - - sort.Slice(versions.Versions, func(i, j int) bool { - s1 := strings.Split(versions.Versions[i].MasterVersion, ".") - s2 := strings.Split(versions.Versions[j].MasterVersion, ".") - for k := 0; k < 3; k++ { - if s1[k] > s2[k] { - return true - } else if s1[k] < s2[k] { - return false - } - } - return true - }) - - for _, vers := range versions.Versions { - if isVersionGreaterOrEqual(vers.MasterVersion, masterVersions) { - latestVersions = vers - break - } - } - - return latestVersions -} - -func isVersionGreaterOrEqual(version1 string, version2 string) bool { - v1Parts := strings.Split(version1, ".") - v2Parts := strings.Split(version2, ".") - - for i := 0; i < len(v1Parts) && i < len(v2Parts); i++ { - v1, _ := strconv.Atoi(v1Parts[i]) - v2, _ := strconv.Atoi(v2Parts[i]) - - if v1 > v2 { - return true - } else if v1 < v2 { - return false - } - } - - return true -} diff --git a/agent/updater/updates/service.go b/agent/updater/updates/service.go index 7b2864be8..49324c5e0 100644 --- a/agent/updater/updates/service.go +++ b/agent/updater/updates/service.go @@ -8,14 +8,23 @@ import ( "github.com/quantfall/holmes" "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/constants" "github.com/utmstack/UTMStack/agent/updater/utils" ) type UTMServices struct { + MasterVersion string CurrentVersions Version LatestVersions Version - ServAttr map[string]constants.ServiceAttribt + ServAttr map[string]configuration.ServiceAttribt +} + +func (u *UTMServices) UpdateCurrentMasterVersion(cnf configuration.Config) error { + masterVersion, err := getMasterVersion(cnf.Server, cnf.SkipCertValidation) + if err != nil { + return fmt.Errorf("error getting master version: %v", err) + } + u.MasterVersion = masterVersion + return nil } func (u *UTMServices) UpdateCurrentVersions() error { @@ -24,7 +33,6 @@ func (u *UTMServices) UpdateCurrentVersions() error { return fmt.Errorf("failed to get current path: %v", err) } - // Save data from versions.json err = utils.ReadJson(filepath.Join(path, "versions.json"), &u.CurrentVersions) if err != nil { return fmt.Errorf("error reading current versions.json: %v", err) @@ -33,32 +41,24 @@ func (u *UTMServices) UpdateCurrentVersions() error { return nil } -func (u *UTMServices) UpdateLatestVersions() error { - // Select environment - env, err := configuration.ReadEnv() - if err != nil { - return fmt.Errorf("error reading environment configuration: %v", err) - } - +func (u *UTMServices) UpdateLatestVersions(env string) error { path, err := utils.GetMyPath() if err != nil { return fmt.Errorf("failed to get current path: %v", err) } - err = utils.DownloadFile(constants.Bucket+env.Branch+"/versions.json?time="+utils.GetCurrentTime(), filepath.Join(path, "versions.json")) + err = utils.DownloadFile(configuration.Bucket+env+"/versions.json", filepath.Join(path, "versions.json")) if err != nil { return fmt.Errorf("error downloading latest versions.json: %v", err) } - // Save data from versions.json newData := DataVersions{} err = utils.ReadJson(filepath.Join(path, "versions.json"), &newData) if err != nil { return fmt.Errorf("error reading latest versions.json: %v", err) } - // Save master versions - u.LatestVersions = GetLatestVersion(newData, u.CurrentVersions.MasterVersion) + u.LatestVersions = getLatestVersion(newData, u.MasterVersion) err = utils.WriteJSON(filepath.Join(path, "versions.json"), &u.LatestVersions) if err != nil { return fmt.Errorf("error writing versions.json: %v", err) @@ -67,48 +67,40 @@ func (u *UTMServices) UpdateLatestVersions() error { return nil } -func (u *UTMServices) CheckUpdates(masterVersion string, h *holmes.Logger) error { - if isNewOrEqualVersion(u.LatestVersions.MasterVersion, masterVersion) { - path, err := utils.GetMyPath() - if err != nil { - return fmt.Errorf("failed to get current path: %v", err) - } +func (u *UTMServices) CheckUpdates(env string, utmLogger *holmes.Logger) error { + path, err := utils.GetMyPath() + if err != nil { + return fmt.Errorf("failed to get current path: %v", err) + } - // Select environment - env, err := configuration.ReadEnv() + if isVersionGreater(u.CurrentVersions.RedlineVersion, u.LatestVersions.RedlineVersion) { + err := u.UpdateService(path, env, "redline", u.LatestVersions.RedlineVersion) if err != nil { - return fmt.Errorf("error reading environment configuration: %v", err) - } - - if isVersionGreater(u.CurrentVersions.RedlineVersion, u.LatestVersions.RedlineVersion) { - err := u.UpdateService(path, env.Branch, "redline") - if err != nil { - return fmt.Errorf("error updating UTMStackRedline service: %v", err) - } - h.Info("UTMStackRedline service updated correctly") + return fmt.Errorf("error updating UTMStackRedline service: %v", err) } + utmLogger.Info("UTMStackRedline service updated correctly") + } - if isVersionGreater(u.CurrentVersions.AgentVersion, u.LatestVersions.AgentVersion) { - err := u.UpdateService(path, env.Branch, "agent") - if err != nil { - return fmt.Errorf("error updating UTMStackAgent service: %v", err) - } - h.Info("UTMStackAgent service updated correctly") + if isVersionGreater(u.CurrentVersions.AgentVersion, u.LatestVersions.AgentVersion) { + err := u.UpdateService(path, env, "agent", u.LatestVersions.AgentVersion) + if err != nil { + return fmt.Errorf("error updating UTMStackAgent service: %v", err) } + utmLogger.Info("UTMStackAgent service updated correctly") + } - if isVersionGreater(u.CurrentVersions.UpdaterVersion, u.LatestVersions.UpdaterVersion) { - err := u.UpdateService(path, env.Branch, "updater") - if err != nil { - return fmt.Errorf("error updating UTMStackUpdater service: %v", err) - } - h.Info("UTMStackUpdater service updated correctly") + if isVersionGreater(u.CurrentVersions.UpdaterVersion, u.LatestVersions.UpdaterVersion) { + err := u.UpdateService(path, env, "updater", u.LatestVersions.UpdaterVersion) + if err != nil { + return fmt.Errorf("error updating UTMStackUpdater service: %v", err) } + utmLogger.Info("UTMStackUpdater service updated correctly") } return nil } -func (u *UTMServices) UpdateService(path string, env string, servCode string) error { +func (u *UTMServices) UpdateService(path string, env string, servCode string, newVers string) error { attr := u.ServAttr[servCode] err := utils.CreatePathIfNotExist(filepath.Join(path, "locks")) if err != nil { @@ -123,22 +115,12 @@ func (u *UTMServices) UpdateService(path string, env string, servCode string) er if servCode == "updater" { utils.Execute(filepath.Join(path, attr.ServBin), path) } else { - // Stop service err = utils.StopService(attr.ServName) if err != nil { return fmt.Errorf("error stoping %s service: %v", attr.ServName, err) } - // Download new version - vers := "" - switch servCode { - case "agent": - vers = u.LatestVersions.AgentVersion - case "redline": - vers = u.LatestVersions.RedlineVersion - } - - url := constants.Bucket + env + "/" + servCode + "_service/v" + vers + "/" + attr.ServBin + "?time=" + utils.GetCurrentTime() + url := configuration.Bucket + env + "/" + servCode + "_service/v" + newVers + "/" + attr.ServBin + "?time=" + utils.GetCurrentTime() err = utils.DownloadFile(url, filepath.Join(path, attr.ServBin)) if err != nil { return fmt.Errorf("error downloading new %s: %v", attr.ServBin, err) @@ -150,7 +132,6 @@ func (u *UTMServices) UpdateService(path string, env string, servCode string) er } } - // Restart service err = utils.RestartService(attr.ServName) if err != nil { return fmt.Errorf("error restarting %s service: %v", attr.ServName, err) @@ -173,9 +154,10 @@ var ( func GetUTMServicesInstance() UTMServices { utmServOnce.Do(func() { utmServ = UTMServices{ + MasterVersion: "", CurrentVersions: Version{}, LatestVersions: Version{}, - ServAttr: constants.GetServAttr(), + ServAttr: configuration.GetServAttr(), } }) return utmServ diff --git a/agent/updater/updates/update.go b/agent/updater/updates/update.go index 988849294..8819f56b7 100644 --- a/agent/updater/updates/update.go +++ b/agent/updater/updates/update.go @@ -5,38 +5,42 @@ import ( "github.com/quantfall/holmes" "github.com/utmstack/UTMStack/agent/updater/configuration" - "github.com/utmstack/UTMStack/agent/updater/constants" ) -func UpdateServices(cnf configuration.Config, h *holmes.Logger) { +func UpdateServices(cnf configuration.Config, utmLogger *holmes.Logger) { utmServices := GetUTMServicesInstance() + env, err := configuration.ReadEnv() + if err != nil { + utmLogger.FatalError("error reading environment configuration: %v", err) + } + + utmLogger.Info("enviroment: %v", env) + for { - time.Sleep(constants.CheckUpdatesEvery) + time.Sleep(configuration.CHECK_EVERY) - masterVersion, err := getMasterVersion(cnf.Server, cnf.SkipCertValidation) + err = utmServices.UpdateCurrentMasterVersion(cnf) if err != nil { - h.Error("error getting master version: %v", err) + utmLogger.Error("error updating current master version: %v", err) continue } - // save current versions err = utmServices.UpdateCurrentVersions() if err != nil { - h.Error("error updating current versions: %v", err) + utmLogger.Error("error updating current versions: %v", err) continue } - // download new versions and save - err = utmServices.UpdateLatestVersions() + err = utmServices.UpdateLatestVersions(env) if err != nil { - h.Error("error updating latest versions: %v", err) + utmLogger.Error("error updating latest versions: %v", err) continue } - err = utmServices.CheckUpdates(masterVersion, h) + err = utmServices.CheckUpdates(env, utmLogger) if err != nil { - h.Error("error updating services: %v", err) + utmLogger.Error("error updating services: %v", err) continue } diff --git a/agent/updater/updates/version.go b/agent/updater/updates/version.go index 98ec3d138..5f1f6c078 100644 --- a/agent/updater/updates/version.go +++ b/agent/updater/updates/version.go @@ -7,20 +7,31 @@ import ( "strconv" "strings" - "github.com/utmstack/UTMStack/agent/updater/constants" + "github.com/utmstack/UTMStack/agent/updater/configuration" "github.com/utmstack/UTMStack/agent/updater/utils" ) +// getLatestVersion returns the latest version of the service +func getLatestVersion(versions DataVersions, masterVersions string) Version { + for _, vers := range versions.Versions { + if vers.MasterVersion == masterVersions { + return vers + } + } + return Version{} +} + +// getMasterVersion returns the master version of the service func getMasterVersion(ip string, skip bool) (string, error) { config := &tls.Config{InsecureSkipVerify: skip} if !skip { var err error - config, err = utils.LoadTLSCredentials(constants.GetCertPath()) + config, err = utils.LoadTLSCredentials(configuration.GetCertPath()) if err != nil { return "", fmt.Errorf("error loading tls credentials: %v", err) } } - resp, status, err := utils.DoReq[InfoResponse]("https://"+ip+constants.MASTERVERSIONENDPOINT, nil, http.MethodGet, map[string]string{}, config) + resp, status, err := utils.DoReq[InfoResponse]("https://"+ip+configuration.MASTERVERSIONENDPOINT, nil, http.MethodGet, map[string]string{}, config) if err != nil { return "", err } else if status != http.StatusOK { @@ -29,6 +40,7 @@ func getMasterVersion(ip string, skip bool) (string, error) { return resp.Build.Version, nil } +// isVersionGreater returns true if newVersion is greater than oldVersion func isVersionGreater(oldVersion, newVersion string) bool { oldParts := strings.Split(oldVersion, ".") newParts := strings.Split(newVersion, ".") @@ -47,6 +59,7 @@ func isVersionGreater(oldVersion, newVersion string) bool { return false } +/* func isNewOrEqualVersion(oldVersion, newVersion string) bool { oldParts := strings.Split(oldVersion, ".") newParts := strings.Split(newVersion, ".") @@ -69,3 +82,4 @@ func isNewOrEqualVersion(oldVersion, newVersion string) bool { return len(newParts) >= len(oldParts) } +*/ diff --git a/agent/updater/utils/cmd.go b/agent/updater/utils/cmd.go index b1881855f..686c93f95 100644 --- a/agent/updater/utils/cmd.go +++ b/agent/updater/utils/cmd.go @@ -6,21 +6,7 @@ import ( "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) -} - +// ExecuteWithResult executes a command and returns the output func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { cmd := exec.Command(c, arg...) @@ -34,14 +20,31 @@ func ExecuteWithResult(c string, dir string, arg ...string) (string, bool) { return string(out[:]) + err.Error(), true } - validUtf8Out := CleanString(string(out[:])) + validUtf8Out := cleanString(string(out[:])) return validUtf8Out, false } +// Execute executes a command without returning the output func Execute(c string, dir string, arg ...string) error { cmd := exec.Command(c, arg...) cmd.Dir = dir return cmd.Run() } + +// cleanString cleans a string from invalid utf8 characters +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) +} diff --git a/agent/updater/utils/delay.go b/agent/updater/utils/delay.go index e3000ea71..61193d39b 100644 --- a/agent/updater/utils/delay.go +++ b/agent/updater/utils/delay.go @@ -2,6 +2,7 @@ package utils import "time" +// IncrementReconnectDelay increments the delay for reconnecting to the server func IncrementReconnectDelay(delay time.Duration, maxReconnectDelay time.Duration) time.Duration { delay *= 2 if delay > maxReconnectDelay { diff --git a/agent/updater/utils/files.go b/agent/updater/utils/files.go index 101231197..1006b2c0f 100644 --- a/agent/updater/utils/files.go +++ b/agent/updater/utils/files.go @@ -20,13 +20,6 @@ func GetMyPath() (string, error) { return exPath, nil } -func CheckIfPathExist(path string) bool { - if _, err := os.Stat(path); os.IsNotExist(err) { - return false - } - return true -} - // ReadYAML reads the YAML data from the specified file URL and deserializes it into the provided result interface{}. // Returns an error if any error occurs during the process. func ReadYAML(path string, result interface{}) error { @@ -56,19 +49,7 @@ func ReadJson(fileName string, data interface{}) error { return nil } -func writeToFile(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 file.Close() - - _, err = file.WriteString(body) - return err -} - +// WriteJSON writes the provided data interface{} to the specified file URL in JSON format. func WriteJSON(path string, data interface{}) error { jsonData, err := json.MarshalIndent(data, "", " ") if err != nil { @@ -94,3 +75,25 @@ func CreatePathIfNotExist(path string) error { } return nil } + +// CheckIfPathExist checks if a specific path exists +func CheckIfPathExist(path string) bool { + if _, err := os.Stat(path); os.IsNotExist(err) { + return false + } + return true +} + +// writeToFile writes the provided body string to the specified file URL. +func writeToFile(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 file.Close() + + _, err = file.WriteString(body) + return err +} diff --git a/agent/updater/utils/lock.go b/agent/updater/utils/lock.go index 1f7e8ce54..261ee0415 100644 --- a/agent/updater/utils/lock.go +++ b/agent/updater/utils/lock.go @@ -5,6 +5,7 @@ import ( "os" ) +// SetLock creates a lock file func SetLock(lockdir string) error { if !CheckIfPathExist(lockdir) { file, err := os.OpenFile(lockdir, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) @@ -16,6 +17,7 @@ func SetLock(lockdir string) error { return nil } +// RemoveLock removes a lock file func RemoveLock(lockdir string) error { if CheckIfPathExist(lockdir) { err := os.Remove(lockdir) diff --git a/agent/updater/utils/req.go b/agent/updater/utils/req.go index 7b3a88ca6..5e8a639af 100644 --- a/agent/updater/utils/req.go +++ b/agent/updater/utils/req.go @@ -8,6 +8,7 @@ import ( "net/http" ) +// DoReq makes a request to the specified URL with the specified data, method and headers. func DoReq[response any](url string, data []byte, method string, headers map[string]string, config *tls.Config) (response, int, error) { req, err := http.NewRequest(method, url, bytes.NewBuffer(data)) if err != nil { diff --git a/agent/updater/utils/services.go b/agent/updater/utils/services.go index d6404f52b..96d9b18f4 100644 --- a/agent/updater/utils/services.go +++ b/agent/updater/utils/services.go @@ -81,6 +81,7 @@ func RestartService(serv string) error { return nil } +// StopService stops a service func StopService(name string) error { path, err := GetMyPath() if err != nil { @@ -101,6 +102,7 @@ func StopService(name string) error { return nil } +// UninstallService uninstalls a service func UninstallService(name string) error { path, err := GetMyPath() if err != nil { diff --git a/agent/updater/utils/timestamp.go b/agent/updater/utils/timestamp.go index e33aa0f2a..7fbb24f2e 100644 --- a/agent/updater/utils/timestamp.go +++ b/agent/updater/utils/timestamp.go @@ -2,6 +2,7 @@ package utils import "time" +// GetCurrentTime returns the current time in the format YYYYMMDDHHMMSS func GetCurrentTime() string { t := time.Now() return t.Format("20060102150405") diff --git a/agent/updater/utils/tls.go b/agent/updater/utils/tls.go index 77fc7470e..d0a1bb693 100644 --- a/agent/updater/utils/tls.go +++ b/agent/updater/utils/tls.go @@ -7,6 +7,7 @@ import ( "os" ) +// LoadTLSCredentials loads the TLS credentials from the specified certificate file. func LoadTLSCredentials(crtName string) (*tls.Config, error) { // Load the server's certificate serverCert, err := os.ReadFile(crtName) diff --git a/frontend/src/app/app-module/guides/guide-linux-agent/guide-linux-agent.component.ts b/frontend/src/app/app-module/guides/guide-linux-agent/guide-linux-agent.component.ts index 91c73584b..a7fea8cfc 100644 --- a/frontend/src/app/app-module/guides/guide-linux-agent/guide-linux-agent.component.ts +++ b/frontend/src/app/app-module/guides/guide-linux-agent/guide-linux-agent.component.ts @@ -33,19 +33,19 @@ export class GuideLinuxAgentComponent implements OnInit { getCommandUbuntu(): string { const ip = window.location.host.includes(':') ? window.location.host.split(':')[0] : window.location.host; return `sudo apt update -y && sudo apt install wget -y && mkdir -p /opt/utmstack-linux-agent && wget -P /opt/utmstack-linux-agent ` + - `https://cdn.utmstack.com/agent_updates/release/installer/v10.1.2/utmstack_agent_installer && chmod -R 777 ` + + `https://cdn.utmstack.com/agent_updates/release/installer/v10.2.0/utmstack_agent_installer && chmod -R 777 ` + `/opt/utmstack-linux-agent/utmstack_agent_installer && sudo /opt/utmstack-linux-agent/utmstack_agent_installer install ` + ip + ` ` + this.token + ` yes`; } getCommandCentos7RedHat(): string { const ip = window.location.host.includes(':') ? window.location.host.split(':')[0] : window.location.host; return `sudo yum install wget -y && mkdir /opt/utmstack-linux-agent && wget -P /opt/utmstack-linux-agent ` + - `https://cdn.utmstack.com/agent_updates/release/installer/v10.1.2/utmstack_agent_installer && chmod -R 777 ` + + `https://cdn.utmstack.com/agent_updates/release/installer/v10.2.0/utmstack_agent_installer && chmod -R 777 ` + `/opt/utmstack-linux-agent/utmstack_agent_installer && sudo /opt/utmstack-linux-agent/utmstack_agent_installer install ` + ip + ` ` + this.token + ` yes`; } getCommandCentos8Almalinux(): string { const ip = window.location.host.includes(':') ? window.location.host.split(':')[0] : window.location.host; return `sudo dnf install wget -y && mkdir /opt/utmstack-linux-agent && wget -P /opt/utmstack-linux-agent ` + - `https://cdn.utmstack.com/agent_updates/release/installer/v10.1.2/utmstack_agent_installer && chmod -R 777 ` + + `https://cdn.utmstack.com/agent_updates/release/installer/v10.2.0/utmstack_agent_installer && chmod -R 777 ` + `/opt/utmstack-linux-agent/utmstack_agent_installer && sudo /opt/utmstack-linux-agent/utmstack_agent_installer install ` + ip + ` ` + this.token + ` yes`; } getUninstallCommand(): string {