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