github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/hypervisor/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 "syscall" 10 11 "github.com/Cloud-Foundations/Dominator/hypervisor/dhcpd" 12 "github.com/Cloud-Foundations/Dominator/hypervisor/httpd" 13 "github.com/Cloud-Foundations/Dominator/hypervisor/manager" 14 "github.com/Cloud-Foundations/Dominator/hypervisor/metadatad" 15 "github.com/Cloud-Foundations/Dominator/hypervisor/rpcd" 16 "github.com/Cloud-Foundations/Dominator/hypervisor/tftpbootd" 17 "github.com/Cloud-Foundations/Dominator/lib/constants" 18 "github.com/Cloud-Foundations/Dominator/lib/flags/loadflags" 19 "github.com/Cloud-Foundations/Dominator/lib/flagutil" 20 "github.com/Cloud-Foundations/Dominator/lib/log/serverlogger" 21 "github.com/Cloud-Foundations/Dominator/lib/net" 22 "github.com/Cloud-Foundations/Dominator/lib/srpc/setupserver" 23 "github.com/Cloud-Foundations/tricorder/go/tricorder" 24 ) 25 26 const ( 27 dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP | 28 syscall.S_IROTH | syscall.S_IXOTH 29 ) 30 31 var ( 32 dhcpServerOnBridgesOnly = flag.Bool("dhcpServerOnBridgesOnly", false, 33 "If true, run the DHCP server on bridge interfaces only") 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 networkBootImage = flag.String("networkBootImage", "pxelinux.0", 40 "Name of boot image passed via DHCP option") 41 objectCacheSize = flagutil.Size(10 << 30) 42 portNum = flag.Uint("portNum", constants.HypervisorPortNumber, 43 "Port number to allocate and listen on for HTTP/RPC") 44 showVGA = flag.Bool("showVGA", false, "If true, show VGA console") 45 stateDir = flag.String("stateDir", "/var/lib/hypervisor", 46 "Name of state directory") 47 testMemoryAvailable = flag.Uint64("testMemoryAvailable", 0, 48 "test if memory is allocatable and exit (units of MiB)") 49 tftpbootImageStream = flag.String("tftpbootImageStream", "", 50 "Name of default image stream for network booting") 51 username = flag.String("username", "nobody", 52 "Name of user to run VMs") 53 volumeDirectories flagutil.StringList 54 ) 55 56 func init() { 57 flag.Var(&objectCacheSize, "objectCacheSize", 58 "maximum size of object cache") 59 flag.Var(&volumeDirectories, "volumeDirectories", 60 "Comma separated list of volume directories. If empty, scan for space") 61 } 62 63 func printUsage() { 64 fmt.Fprintln(os.Stderr, 65 "Usage: hypervisor [flags...] [run|stop|stop-vms-on-next-stop]") 66 fmt.Fprintln(os.Stderr, "Common flags:") 67 flag.PrintDefaults() 68 } 69 70 func processCommand(args []string) { 71 if len(args) < 1 { 72 return 73 } else if len(args) > 1 { 74 printUsage() 75 os.Exit(2) 76 } 77 switch args[0] { 78 case "run": 79 return 80 case "stop": 81 requestStop() 82 case "stop-vms-on-next-stop": 83 configureVMsToStopOnNextStop() 84 default: 85 printUsage() 86 os.Exit(2) 87 } 88 } 89 90 func main() { 91 if err := loadflags.LoadForDaemon("hypervisor"); err != nil { 92 fmt.Fprintln(os.Stderr, err) 93 os.Exit(1) 94 } 95 flag.Usage = printUsage 96 flag.Parse() 97 processCommand(flag.Args()) 98 if *testMemoryAvailable > 0 { 99 nBytes := *testMemoryAvailable << 20 100 mem := make([]byte, nBytes) 101 for pos := uint64(0); pos < nBytes; pos += 4096 { 102 mem[pos] = 0 103 } 104 os.Exit(0) 105 } 106 tricorder.RegisterFlags() 107 if os.Geteuid() != 0 { 108 fmt.Fprintln(os.Stderr, "Must run the Hypervisor as root") 109 os.Exit(1) 110 } 111 logger := serverlogger.New("") 112 if err := setupserver.SetupTls(); err != nil { 113 logger.Fatalln(err) 114 } 115 if err := os.MkdirAll(*stateDir, dirPerms); err != nil { 116 logger.Fatalf("Cannot create state directory: %s\n", err) 117 } 118 bridges, bridgeMap, err := net.ListBroadcastInterfaces( 119 net.InterfaceTypeBridge, logger) 120 if err != nil { 121 logger.Fatalf("Cannot list bridges: %s\n", err) 122 } 123 dhcpInterfaces := make([]string, 0, len(bridges)) 124 vlanIdToBridge := make(map[uint]string) 125 for _, bridge := range bridges { 126 if vlanId, err := net.GetBridgeVlanId(bridge.Name); err != nil { 127 logger.Fatalf("Cannot get VLAN Id for bridge: %s: %s\n", 128 bridge.Name, err) 129 } else if vlanId < 0 { 130 logger.Printf("Bridge: %s has no EtherNet port, ignoring\n", 131 bridge.Name) 132 } else { 133 if *dhcpServerOnBridgesOnly { 134 dhcpInterfaces = append(dhcpInterfaces, bridge.Name) 135 } 136 if !strings.HasPrefix(bridge.Name, "br@") { 137 vlanIdToBridge[uint(vlanId)] = bridge.Name 138 logger.Printf("Bridge: %s, VLAN Id: %d\n", bridge.Name, vlanId) 139 } 140 } 141 } 142 dhcpServer, err := dhcpd.New(dhcpInterfaces, 143 filepath.Join(*stateDir, "dynamic-leases.json"), logger) 144 if err != nil { 145 logger.Fatalf("Cannot start DHCP server: %s\n", err) 146 } 147 if err := dhcpServer.SetNetworkBootImage(*networkBootImage); err != nil { 148 logger.Fatalf("Cannot set NetworkBootImage name: %s\n", err) 149 } 150 imageServerAddress := fmt.Sprintf("%s:%d", 151 *imageServerHostname, *imageServerPortNum) 152 tftpbootServer, err := tftpbootd.New(imageServerAddress, 153 *tftpbootImageStream, logger) 154 if err != nil { 155 logger.Fatalf("Cannot start tftpboot server: %s\n", err) 156 } 157 managerObj, err := manager.New(manager.StartOptions{ 158 BridgeMap: bridgeMap, 159 DhcpServer: dhcpServer, 160 ImageServerAddress: imageServerAddress, 161 Logger: logger, 162 ObjectCacheBytes: uint64(objectCacheSize), 163 ShowVgaConsole: *showVGA, 164 StateDir: *stateDir, 165 Username: *username, 166 VlanIdToBridge: vlanIdToBridge, 167 VolumeDirectories: volumeDirectories, 168 }) 169 if err != nil { 170 logger.Fatalf("Cannot start hypervisor: %s\n", err) 171 } 172 if err := listenForControl(managerObj, logger); err != nil { 173 logger.Fatalf("Cannot listen for control: %s\n", err) 174 } 175 httpd.AddHtmlWriter(managerObj) 176 if len(bridges) < 1 { 177 logger.Println("No bridges found: entering log-only mode") 178 } else { 179 rpcHtmlWriter, err := rpcd.Setup(managerObj, dhcpServer, tftpbootServer, 180 logger) 181 if err != nil { 182 logger.Fatalf("Cannot start rpcd: %s\n", err) 183 } 184 httpd.AddHtmlWriter(rpcHtmlWriter) 185 } 186 httpd.AddHtmlWriter(logger) 187 err = metadatad.StartServer(*portNum, bridges, managerObj, logger) 188 if err != nil { 189 logger.Fatalf("Cannot start metadata server: %s\n", err) 190 } 191 if err := httpd.StartServer(*portNum, managerObj, false); err != nil { 192 logger.Fatalf("Unable to create http server: %s\n", err) 193 } 194 }