github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/cmd/nodeagent/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "crypto/sha256" 6 "flag" 7 "fmt" 8 "math/rand" 9 "net/http" 10 "os" 11 "os/signal" 12 "runtime" 13 "strings" 14 "syscall" 15 "time" 16 17 "github.com/caos/orbos/internal/operator/nodeagent/networking" 18 19 "github.com/caos/orbos/mntr" 20 "github.com/caos/orbos/pkg/git" 21 22 _ "net/http/pprof" 23 24 "github.com/caos/orbos/internal/operator/nodeagent" 25 "github.com/caos/orbos/internal/operator/nodeagent/dep" 26 "github.com/caos/orbos/internal/operator/nodeagent/dep/conv" 27 "github.com/caos/orbos/internal/operator/nodeagent/firewall" 28 ) 29 30 var ( 31 gitCommit string 32 version string 33 ) 34 35 func main() { 36 37 ctx, cancelCtx := context.WithCancel(context.Background()) 38 39 monitor := mntr.Monitor{ 40 OnInfo: mntr.LogMessage, 41 OnChange: mntr.LogMessage, 42 OnError: mntr.LogError, 43 } 44 45 defer func() { monitor.RecoverPanic(recover()) }() 46 47 verbose := flag.Bool("verbose", false, "Print logs for debugging") 48 printVersion := flag.Bool("version", false, "Print build information") 49 ignorePorts := flag.String("ignore-ports", "", "Comma separated list of firewall ports that are ignored") 50 nodeAgentID := flag.String("id", "", "The managed machines ID") 51 pprof := flag.Bool("pprof", false, "start pprof as port 6060") 52 sentryEnvironment := flag.String("environment", "", "Sentry environment") 53 54 flag.Parse() 55 56 if *printVersion { 57 fmt.Printf("%s %s\n", version, gitCommit) 58 os.Exit(0) 59 } 60 61 if *sentryEnvironment != "" { 62 if err := mntr.Ingest(monitor, "orbos", version, *sentryEnvironment, "node-agent"); err != nil { 63 panic(err) 64 } 65 } 66 67 monitor.WithField("id", nodeAgentID).CaptureMessage("nodeagent invoked") 68 69 if *verbose { 70 monitor = monitor.Verbose() 71 } 72 73 if *nodeAgentID == "" { 74 panic("flag --id is required") 75 } 76 77 monitor.WithFields(map[string]interface{}{ 78 "version": version, 79 "commit": gitCommit, 80 "verbose": *verbose, 81 "nodeAgentID": *nodeAgentID, 82 "sentryEnvironment": *sentryEnvironment, 83 }).Info("Node Agent is starting") 84 85 mutexActionChannel := make(chan interface{}) 86 87 signalChannel := make(chan os.Signal) 88 signal.Notify(signalChannel, 89 syscall.SIGTERM, 90 syscall.SIGINT, 91 syscall.SIGQUIT, 92 ) 93 94 go func() { 95 for sig := range signalChannel { 96 monitor.WithField("signal", sig.String()).Info("Received signal") 97 cancelCtx() 98 mutexActionChannel <- sig 99 } 100 }() 101 102 if *pprof { 103 go func() { 104 monitor.Info(http.ListenAndServe("localhost:6060", nil).Error()) 105 }() 106 } 107 108 runningOnOS, err := dep.GetOperatingSystem() 109 if err != nil { 110 panic(err) 111 } 112 113 repoKey, err := nodeagent.RepoKey() 114 if err != nil { 115 panic(err) 116 } 117 118 pruned := strings.Split(string(repoKey), "-----")[2] 119 hashed := sha256.Sum256([]byte(pruned)) 120 conv := conv.New(ctx, monitor, runningOnOS, fmt.Sprintf("%x", hashed[:])) 121 122 gitClient := git.New(ctx, monitor, fmt.Sprintf("Node Agent %s", *nodeAgentID), "node-agent@caos.ch") 123 124 var portsSlice []string 125 if len(*ignorePorts) > 0 { 126 portsSlice = strings.Split(*ignorePorts, ",") 127 } 128 129 itFunc := nodeagent.Iterator( 130 monitor, 131 gitClient, 132 gitCommit, 133 *nodeAgentID, 134 firewall.Ensurer(monitor, runningOnOS.OperatingSystem, portsSlice), 135 networking.Ensurer(monitor, runningOnOS.OperatingSystem), 136 conv, 137 conv.Init()) 138 139 type updateType struct{} 140 go func() { 141 for range time.Tick(24 * time.Hour) { 142 timer := time.NewTimer(time.Duration(rand.Intn(120)) * time.Minute) 143 <-timer.C 144 mutexActionChannel <- updateType{} 145 timer.Stop() 146 } 147 }() 148 149 type iterateType struct{} 150 //trigger first iteration 151 go func() { mutexActionChannel <- iterateType{} }() 152 153 go func() { 154 for range time.Tick(5 * time.Minute) { 155 if PrintMemUsage(monitor) > 250 { 156 monitor.Info("Shutting down as memory usage exceeded 250 MiB") 157 mutexActionChannel <- syscall.Signal(0) 158 } 159 } 160 }() 161 162 for action := range mutexActionChannel { 163 switch sig := action.(type) { 164 case os.Signal: 165 monitor.WithField("signal", sig.String()).Info("Shutting down") 166 os.Exit(0) 167 case iterateType: 168 monitor.Info("Starting iteration") 169 itFunc() 170 monitor.Info("Iteration done") 171 go func() { 172 //trigger next iteration 173 time.Sleep(10 * time.Second) 174 mutexActionChannel <- iterateType{} 175 }() 176 case updateType: 177 monitor.Info("Starting update") 178 if err := conv.Update(); err != nil { 179 monitor.Error(fmt.Errorf("updating packages failed: %w", err)) 180 } else { 181 monitor.Info("Update done") 182 } 183 } 184 } 185 } 186 187 func PrintMemUsage(monitor mntr.Monitor) uint64 { 188 var m runtime.MemStats 189 runtime.ReadMemStats(&m) 190 mB := m.Sys / 1024 / 1024 191 monitor.WithFields(map[string]interface{}{ 192 "MiB": mB, 193 }).Info("Read current memory usage") 194 return mB 195 }