github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/dominator/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 _ "net/http/pprof" 7 "os" 8 "path" 9 "syscall" 10 "time" 11 12 "github.com/Cloud-Foundations/Dominator/dom/herd" 13 "github.com/Cloud-Foundations/Dominator/dom/rpcd" 14 "github.com/Cloud-Foundations/Dominator/lib/constants" 15 "github.com/Cloud-Foundations/Dominator/lib/flags/loadflags" 16 "github.com/Cloud-Foundations/Dominator/lib/log" 17 "github.com/Cloud-Foundations/Dominator/lib/log/serverlogger" 18 "github.com/Cloud-Foundations/Dominator/lib/mdb" 19 "github.com/Cloud-Foundations/Dominator/lib/mdb/mdbd" 20 objectserver "github.com/Cloud-Foundations/Dominator/lib/objectserver/filesystem" 21 "github.com/Cloud-Foundations/Dominator/lib/srpc/setupserver" 22 "github.com/Cloud-Foundations/tricorder/go/tricorder" 23 ) 24 25 const dirPerms = syscall.S_IRWXU 26 27 var ( 28 debug = flag.Bool("debug", false, 29 "If true, show debugging output") 30 fdLimit = flag.Uint64("fdLimit", getFdLimit(), 31 "Maximum number of open file descriptors (this limits concurrent connection attempts)") 32 imageServerHostname = flag.String("imageServerHostname", "localhost", 33 "Hostname of image server") 34 imageServerPortNum = flag.Uint("imageServerPortNum", 35 constants.ImageServerPortNumber, 36 "Port number of image server") 37 mdbFile = flag.String("mdbFile", constants.DefaultMdbFile, 38 "File to read MDB data from") 39 minInterval = flag.Uint("minInterval", 1, 40 "Minimum interval between loops (in seconds)") 41 objectsDir = flag.String("objectsDir", "objects", 42 "Directory containing computed objects, relative to stateDir") 43 permitInsecureMode = flag.Bool("permitInsecureMode", false, 44 "If true, run in insecure mode. This gives remote access to all") 45 portNum = flag.Uint("portNum", constants.DominatorPortNumber, 46 "Port number to allocate and listen on for HTTP/RPC") 47 stateDir = flag.String("stateDir", "/var/lib/Dominator", 48 "Name of dominator state directory.") 49 ) 50 51 func showMdb(mdb *mdb.Mdb) { 52 fmt.Println() 53 mdb.DebugWrite(os.Stdout) 54 fmt.Println() 55 } 56 57 func getFdLimit() uint64 { 58 var rlim syscall.Rlimit 59 if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil { 60 panic(err) 61 } 62 return rlim.Max 63 } 64 65 func pathJoin(first, second string) string { 66 if path.IsAbs(second) { 67 return path.Clean(second) 68 } 69 return path.Join(first, second) 70 } 71 72 func newObjectServer(objectsDir string, logger log.DebugLogger) ( 73 *objectserver.ObjectServer, error) { 74 fi, err := os.Stat(objectsDir) 75 if err != nil { 76 if err := os.Mkdir(objectsDir, dirPerms); err != nil { 77 return nil, err 78 } 79 } else if !fi.IsDir() { 80 return nil, fmt.Errorf("%s is not a directory", objectsDir) 81 } 82 return objectserver.NewObjectServer(objectsDir, logger) 83 } 84 85 func main() { 86 if os.Geteuid() == 0 { 87 fmt.Fprintln(os.Stderr, "Do not run the Dominator as root") 88 os.Exit(1) 89 } 90 if err := loadflags.LoadForDaemon("dominator"); err != nil { 91 fmt.Fprintln(os.Stderr, err) 92 os.Exit(1) 93 } 94 flag.Parse() 95 tricorder.RegisterFlags() 96 logger := serverlogger.New("") 97 if err := setupserver.SetupTls(); err != nil { 98 if *permitInsecureMode { 99 logger.Println(err) 100 } else { 101 logger.Fatalln(err) 102 } 103 } 104 rlim := syscall.Rlimit{Cur: *fdLimit, Max: *fdLimit} 105 if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil { 106 fmt.Fprintf(os.Stderr, "Cannot set FD limit: %s\n", err) 107 os.Exit(1) 108 } 109 fi, err := os.Lstat(*stateDir) 110 if err != nil { 111 fmt.Fprintf(os.Stderr, "Cannot stat: %s: %s\n", *stateDir, err) 112 os.Exit(1) 113 } 114 if !fi.IsDir() { 115 fmt.Fprintf(os.Stderr, "%s is not a directory\n", *stateDir) 116 os.Exit(1) 117 } 118 interval := time.Duration(*minInterval) * time.Second 119 mdbChannel := mdbd.StartMdbDaemon(*mdbFile, logger) 120 objectServer, err := newObjectServer(path.Join(*stateDir, *objectsDir), 121 logger) 122 if err != nil { 123 fmt.Fprintf(os.Stderr, "Cannot load objectcache: %s\n", err) 124 os.Exit(1) 125 } 126 metricsDir, err := tricorder.RegisterDirectory("/dominator/herd") 127 if err != nil { 128 fmt.Fprintf(os.Stderr, "Cannot create metrics directory: %s\n", err) 129 os.Exit(1) 130 } 131 herd := herd.NewHerd(fmt.Sprintf("%s:%d", *imageServerHostname, 132 *imageServerPortNum), objectServer, metricsDir, logger) 133 herd.AddHtmlWriter(logger) 134 rpcd.Setup(herd, logger) 135 if err = herd.StartServer(*portNum, true); err != nil { 136 fmt.Fprintf(os.Stderr, "Unable to create http server: %s\n", err) 137 os.Exit(1) 138 } 139 scanTokenChannel := make(chan bool, 1) 140 scanTokenChannel <- true 141 nextCycleStopTime := time.Now().Add(interval) 142 for { 143 select { 144 case mdb := <-mdbChannel: 145 herd.MdbUpdate(mdb) 146 if *debug { 147 showMdb(mdb) 148 } 149 case <-scanTokenChannel: 150 // Scan one sub. 151 if herd.PollNextSub() { // We've reached the end of a scan cycle. 152 if *debug { 153 fmt.Print(".") 154 } 155 go func(sleepDuration time.Duration) { 156 time.Sleep(sleepDuration) 157 nextCycleStopTime = time.Now().Add(interval) 158 scanTokenChannel <- true 159 }(nextCycleStopTime.Sub(time.Now())) 160 } else { 161 scanTokenChannel <- true 162 } 163 } 164 } 165 }