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  }