github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/mdbd/main.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"os"
     7  	"os/signal"
     8  	"syscall"
     9  
    10  	"github.com/Cloud-Foundations/Dominator/lib/constants"
    11  	"github.com/Cloud-Foundations/Dominator/lib/flags/loadflags"
    12  	"github.com/Cloud-Foundations/Dominator/lib/fsutil"
    13  	"github.com/Cloud-Foundations/Dominator/lib/log"
    14  	"github.com/Cloud-Foundations/Dominator/lib/log/serverlogger"
    15  	"github.com/Cloud-Foundations/Dominator/lib/mdb"
    16  	"github.com/Cloud-Foundations/Dominator/lib/srpc/setupserver"
    17  	"github.com/Cloud-Foundations/tricorder/go/tricorder"
    18  )
    19  
    20  var (
    21  	datacentre = flag.String("datacentre", "",
    22  		"Datacentre to limit results to (may not be supported by all drivers)")
    23  	debug         = flag.Bool("debug", false, "If true, show debugging output")
    24  	fetchInterval = flag.Uint("fetchInterval", 59,
    25  		"Interval between fetches from the MDB source, in seconds")
    26  	hostnameRegex = flag.String("hostnameRegex", ".*",
    27  		"A regular expression to match the desired hostnames")
    28  	mdbFile = flag.String("mdbFile", constants.DefaultMdbFile,
    29  		"Name of file to write filtered MDB data to")
    30  	portNum = flag.Uint("portNum", constants.SimpleMdbServerPortNumber,
    31  		"Port number to allocate and listen on for HTTP/RPC")
    32  	sourcesFile = flag.String("sourcesFile", "/var/lib/mdbd/mdb.sources.list",
    33  		"Name of file list of driver url pairs")
    34  	pidfile = flag.String("pidfile", "", "Name of file to write my PID to")
    35  )
    36  
    37  func printUsage() {
    38  	fmt.Fprintln(os.Stderr,
    39  		"Usage: mdbd [flags...]")
    40  	fmt.Fprintln(os.Stderr, "Common flags:")
    41  	flag.PrintDefaults()
    42  	fmt.Fprintln(os.Stderr, "Drivers:")
    43  	fmt.Fprintln(os.Stderr,
    44  		"  aws: region account")
    45  	fmt.Fprintln(os.Stderr,
    46  		"    Query Amazon AWS")
    47  	fmt.Fprintln(os.Stderr,
    48  		"    region: a datacentre like 'us-east-1'")
    49  	fmt.Fprintln(os.Stderr,
    50  		"    account: the profile to use out of ~/.aws/credentials which")
    51  	fmt.Fprintln(os.Stderr,
    52  		"             contains the amazon aws credentials. For additional")
    53  	fmt.Fprintln(os.Stderr,
    54  		"             information see:")
    55  	fmt.Fprintln(os.Stderr,
    56  		"             http://docs.aws.amazon.com/sdk-for-go/latest/v1/developerguide/sdkforgo-dg.pdf")
    57  	fmt.Fprintln(os.Stderr,
    58  		"  aws-filtered: targets filter-tags-file")
    59  	fmt.Fprintln(os.Stderr,
    60  		"    Query Amazon AWS")
    61  	fmt.Fprintln(os.Stderr,
    62  		"    targets: a list of targets, i.e. 'prod,us-east-1;dev,us-east-1'")
    63  	fmt.Fprintln(os.Stderr,
    64  		"    filter-tags-file: a JSON file of tags to filter for")
    65  	fmt.Fprintln(os.Stderr,
    66  		"  aws-local")
    67  	fmt.Fprintln(os.Stderr,
    68  		"    Query Amazon AWS for all acccounts for the local region")
    69  	fmt.Fprintln(os.Stderr,
    70  		"  cis: url")
    71  	fmt.Fprintln(os.Stderr,
    72  		"    url: Cloud Intelligence Service endpoint search query")
    73  	fmt.Fprintln(os.Stderr,
    74  		"  ds.host.fqdn: url")
    75  	fmt.Fprintln(os.Stderr,
    76  		"    url: URL which yields JSON with map of map of hosts with fqdn entries")
    77  	fmt.Fprintln(os.Stderr,
    78  		"  fleet-manager: manager-hostname [location]")
    79  	fmt.Fprintln(os.Stderr,
    80  		"    Query Fleet Manager")
    81  	fmt.Fprintln(os.Stderr,
    82  		"    manager-hostname: hostname of the Fleet Manager")
    83  	fmt.Fprintln(os.Stderr,
    84  		"    location: optional location to limit query to")
    85  	fmt.Fprintln(os.Stderr,
    86  		"  hypervisor")
    87  	fmt.Fprintln(os.Stderr,
    88  		"    Query Hypervisor on this machine")
    89  	fmt.Fprintln(os.Stderr,
    90  		"  text: url")
    91  	fmt.Fprintln(os.Stderr,
    92  		"    url: URL which yields lines. Each line contains:")
    93  	fmt.Fprintln(os.Stderr,
    94  		"         host [required-image [planned-image]]")
    95  }
    96  
    97  type driver struct {
    98  	name      string
    99  	minArgs   int
   100  	maxArgs   int
   101  	setupFunc makeGeneratorFunc
   102  }
   103  
   104  var drivers = []driver{
   105  	{"aws", 2, 2, newAwsGenerator},
   106  	{"aws-filtered", 2, 2, newAwsFilteredGenerator},
   107  	{"aws-local", 0, 0, newAwsLocalGenerator},
   108  	{"cis", 1, 1, newCisGenerator},
   109  	{"ds.host.fqdn", 1, 1, newDsHostFqdnGenerator},
   110  	{"fleet-manager", 1, 2, newFleetManagerGenerator},
   111  	{"hypervisor", 0, 0, newHypervisorGenerator},
   112  	{"text", 1, 1, newTextGenerator},
   113  }
   114  
   115  func gracefulCleanup() {
   116  	os.Remove(*pidfile)
   117  	os.Exit(1)
   118  }
   119  
   120  func writePidfile() {
   121  	file, err := os.Create(*pidfile)
   122  	if err != nil {
   123  		return
   124  	}
   125  	defer file.Close()
   126  	fmt.Fprintln(file, os.Getpid())
   127  }
   128  
   129  func handleSignals(logger log.Logger) {
   130  	if *pidfile == "" {
   131  		return
   132  	}
   133  	sigtermChannel := make(chan os.Signal)
   134  	signal.Notify(sigtermChannel, syscall.SIGTERM, syscall.SIGINT)
   135  	writePidfile()
   136  	go func() {
   137  		for {
   138  			select {
   139  			case <-sigtermChannel:
   140  				gracefulCleanup()
   141  			}
   142  		}
   143  	}()
   144  }
   145  
   146  func showErrorAndDie(err error) {
   147  	fmt.Fprintln(os.Stderr, err)
   148  	os.Exit(2)
   149  }
   150  
   151  func main() {
   152  	if os.Geteuid() == 0 {
   153  		fmt.Fprintln(os.Stderr, "Do not run the MDB daemon as root")
   154  		os.Exit(1)
   155  	}
   156  	if err := loadflags.LoadForDaemon("mdbd"); err != nil {
   157  		fmt.Fprintln(os.Stderr, err)
   158  		os.Exit(1)
   159  	}
   160  	flag.Usage = printUsage
   161  	flag.Parse()
   162  	tricorder.RegisterFlags()
   163  	logger := serverlogger.New("")
   164  	// We have to have inputs.
   165  	if *sourcesFile == "" {
   166  		printUsage()
   167  		os.Exit(2)
   168  	}
   169  	setupserver.SetupTlsClientOnly()
   170  	handleSignals(logger)
   171  	readerChannel := fsutil.WatchFile(*sourcesFile, logger)
   172  	file, err := os.Open(*sourcesFile)
   173  	if err != nil {
   174  		showErrorAndDie(err)
   175  	}
   176  	(<-readerChannel).Close()
   177  	generators, err := setupGenerators(file, drivers, logger)
   178  	file.Close()
   179  	if err != nil {
   180  		showErrorAndDie(err)
   181  	}
   182  	httpSrv, err := startHttpServer(*portNum)
   183  	if err != nil {
   184  		showErrorAndDie(err)
   185  	}
   186  	httpSrv.AddHtmlWriter(logger)
   187  	rpcd := startRpcd(logger)
   188  	go runDaemon(generators, *mdbFile, *hostnameRegex, *datacentre,
   189  		*fetchInterval, func(old, new *mdb.Mdb) {
   190  			rpcd.pushUpdateToAll(old, new)
   191  			httpSrv.UpdateMdb(new)
   192  		},
   193  		logger, *debug)
   194  	<-readerChannel
   195  	fsutil.WatchFileStop()
   196  	if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil {
   197  		logger.Printf("Unable to Exec:%s: %s\n", os.Args[0], err)
   198  	}
   199  }