github.com/Cloud-Foundations/Dominator@v0.3.4/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 "time" 11 12 "github.com/Cloud-Foundations/Dominator/hypervisor/dhcpd" 13 "github.com/Cloud-Foundations/Dominator/hypervisor/httpd" 14 "github.com/Cloud-Foundations/Dominator/hypervisor/manager" 15 "github.com/Cloud-Foundations/Dominator/hypervisor/metadatad" 16 "github.com/Cloud-Foundations/Dominator/hypervisor/rpcd" 17 "github.com/Cloud-Foundations/Dominator/hypervisor/tftpbootd" 18 "github.com/Cloud-Foundations/Dominator/lib/constants" 19 "github.com/Cloud-Foundations/Dominator/lib/flags/commands" 20 "github.com/Cloud-Foundations/Dominator/lib/flags/loadflags" 21 "github.com/Cloud-Foundations/Dominator/lib/flagutil" 22 "github.com/Cloud-Foundations/Dominator/lib/log" 23 "github.com/Cloud-Foundations/Dominator/lib/log/serverlogger" 24 "github.com/Cloud-Foundations/Dominator/lib/net" 25 "github.com/Cloud-Foundations/Dominator/lib/srpc" 26 "github.com/Cloud-Foundations/Dominator/lib/srpc/setupserver" 27 "github.com/Cloud-Foundations/tricorder/go/tricorder" 28 ) 29 30 const ( 31 dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP | 32 syscall.S_IROTH | syscall.S_IXOTH 33 ) 34 35 var ( 36 dhcpServerOnBridgesOnly = flag.Bool("dhcpServerOnBridgesOnly", false, 37 "If true, run the DHCP server on bridge interfaces only") 38 imageServerHostname = flag.String("imageServerHostname", "localhost", 39 "Hostname of image server") 40 imageServerPortNum = flag.Uint("imageServerPortNum", 41 constants.ImageServerPortNumber, 42 "Port number of image server") 43 lockCheckInterval = flag.Duration("lockCheckInterval", 2*time.Second, 44 "Interval between checks for lock timeouts") 45 lockLogTimeout = flag.Duration("lockLogTimeout", 5*time.Second, 46 "Timeout before logging that a lock has been held too long") 47 networkBootImage = flag.String("networkBootImage", "pxelinux.0", 48 "Name of boot image passed via DHCP option") 49 objectCacheSize = flagutil.Size(10 << 30) 50 portNum = flag.Uint("portNum", constants.HypervisorPortNumber, 51 "Port number to allocate and listen on for HTTP/RPC") 52 showVGA = flag.Bool("showVGA", false, "If true, show VGA console") 53 stateDir = flag.String("stateDir", "/var/lib/hypervisor", 54 "Name of state directory") 55 testMemoryAvailable = flag.Uint64("testMemoryAvailable", 0, 56 "test if memory is allocatable and exit (units of MiB)") 57 tftpbootImageStream = flag.String("tftpbootImageStream", "", 58 "Name of default image stream for network booting") 59 username = flag.String("username", "nobody", 60 "Name of user to run VMs") 61 volumeDirectories flagutil.StringList 62 ) 63 64 func init() { 65 flag.Var(&objectCacheSize, "objectCacheSize", 66 "maximum size of object cache") 67 flag.Var(&volumeDirectories, "volumeDirectories", 68 "Comma separated list of volume directories. If empty, scan for space") 69 } 70 71 func printUsage() { 72 w := flag.CommandLine.Output() 73 fmt.Fprintln(w, 74 "Usage: hypervisor [flags...] [run|stop|stop-vms-on-next-stop]") 75 fmt.Fprintln(w, "Common flags:") 76 flag.PrintDefaults() 77 fmt.Fprintln(w, "Commands:") 78 commands.PrintCommands(w, subcommands) 79 } 80 81 var subcommands = []commands.Command{ 82 {"check-vms", "", 0, 0, checkVmsSubcommand}, 83 {"repair-vm-volume-allocations", "", 0, 0, 84 repairVmVolumeAllocationsSubcommand}, 85 {"run", "", 0, 0, runSubcommand}, 86 {"stop", "", 0, 0, stopSubcommand}, 87 {"stop-vms-on-next-stop", "", 0, 0, stopVmsOnNextStopSubcommand}, 88 } 89 90 func processCommand(args []string) { 91 if len(args) < 1 { 92 runSubcommand(nil, nil) 93 } 94 os.Exit(commands.RunCommands(subcommands, printUsage, nil)) 95 } 96 97 func main() { 98 if err := loadflags.LoadForDaemon("hypervisor"); err != nil { 99 fmt.Fprintln(os.Stderr, err) 100 os.Exit(1) 101 } 102 flag.Usage = printUsage 103 flag.Parse() 104 processCommand(flag.Args()) 105 } 106 107 func run() { 108 if *testMemoryAvailable > 0 { 109 nBytes := *testMemoryAvailable << 20 110 mem := make([]byte, nBytes) 111 for pos := uint64(0); pos < nBytes; pos += 4096 { 112 mem[pos] = 0 113 } 114 os.Exit(0) 115 } 116 tricorder.RegisterFlags() 117 if os.Geteuid() != 0 { 118 fmt.Fprintln(os.Stderr, "Must run the Hypervisor as root") 119 os.Exit(1) 120 } 121 logger := serverlogger.New("") 122 srpc.SetDefaultLogger(logger) 123 params := setupserver.Params{Logger: logger} 124 if err := setupserver.SetupTlsWithParams(params); err != nil { 125 logger.Fatalln(err) 126 } 127 if err := os.MkdirAll(*stateDir, dirPerms); err != nil { 128 logger.Fatalf("Cannot create state directory: %s\n", err) 129 } 130 bridges, bridgeMap, err := net.ListBroadcastInterfaces( 131 net.InterfaceTypeBridge, logger) 132 if err != nil { 133 logger.Fatalf("Cannot list bridges: %s\n", err) 134 } 135 dhcpInterfaces := make([]string, 0, len(bridges)) 136 vlanIdToBridge := make(map[uint]string) 137 for _, bridge := range bridges { 138 vlanId, err := net.GetBridgeVlanId(bridge.Name) 139 if err != nil { 140 logger.Fatalf("Cannot get VLAN Id for bridge: %s: %s\n", 141 bridge.Name, err) 142 continue 143 } 144 if vlanId < 0 { 145 if len(bridges) > 1 { 146 logger.Printf("Bridge: %s has no EtherNet port, ignoring\n", 147 bridge.Name) 148 continue 149 } 150 logger.Printf( 151 "Bridge: %s has no EtherNet port but is the only bridge, using in hope\n", 152 bridge.Name) 153 vlanId = 0 154 } 155 if *dhcpServerOnBridgesOnly { 156 dhcpInterfaces = append(dhcpInterfaces, bridge.Name) 157 } 158 if !strings.HasPrefix(bridge.Name, "br@") { 159 vlanIdToBridge[uint(vlanId)] = bridge.Name 160 logger.Printf("Bridge: %s, VLAN Id: %d\n", bridge.Name, vlanId) 161 } 162 } 163 dhcpServer, err := dhcpd.New(dhcpInterfaces, 164 filepath.Join(*stateDir, "dynamic-leases.json"), logger) 165 if err != nil { 166 logger.Fatalf("Cannot start DHCP server: %s\n", err) 167 } 168 if err := dhcpServer.SetNetworkBootImage(*networkBootImage); err != nil { 169 logger.Fatalf("Cannot set NetworkBootImage name: %s\n", err) 170 } 171 imageServerAddress := fmt.Sprintf("%s:%d", 172 *imageServerHostname, *imageServerPortNum) 173 tftpbootServer, err := tftpbootd.New(imageServerAddress, 174 *tftpbootImageStream, logger) 175 if err != nil { 176 logger.Fatalf("Cannot start tftpboot server: %s\n", err) 177 } 178 managerObj, err := manager.New(manager.StartOptions{ 179 BridgeMap: bridgeMap, 180 DhcpServer: dhcpServer, 181 ImageServerAddress: imageServerAddress, 182 LockCheckInterval: *lockCheckInterval, 183 LockLogTimeout: *lockLogTimeout, 184 Logger: logger, 185 ObjectCacheBytes: uint64(objectCacheSize), 186 ShowVgaConsole: *showVGA, 187 StateDir: *stateDir, 188 Username: *username, 189 VlanIdToBridge: vlanIdToBridge, 190 VolumeDirectories: volumeDirectories, 191 }) 192 if err != nil { 193 logger.Fatalf("Cannot start hypervisor: %s\n", err) 194 } 195 if err := listenForControl(managerObj, logger); err != nil { 196 logger.Fatalf("Cannot listen for control: %s\n", err) 197 } 198 httpd.AddHtmlWriter(managerObj) 199 if len(bridges) < 1 { 200 logger.Println("No bridges found: entering log-only mode") 201 } else { 202 httpd.AddHtmlWriter(dhcpServer) 203 rpcHtmlWriter, err := rpcd.Setup(managerObj, dhcpServer, tftpbootServer, 204 logger) 205 if err != nil { 206 logger.Fatalf("Cannot start rpcd: %s\n", err) 207 } 208 httpd.AddHtmlWriter(rpcHtmlWriter) 209 } 210 httpd.AddHtmlWriter(logger) 211 err = metadatad.StartServer(*portNum, bridges, managerObj, logger) 212 if err != nil { 213 logger.Fatalf("Cannot start metadata server: %s\n", err) 214 } 215 if err := httpd.StartServer(*portNum, managerObj, false); err != nil { 216 logger.Fatalf("Unable to create http server: %s\n", err) 217 } 218 } 219 220 func runSubcommand(args []string, logger log.DebugLogger) error { 221 run() 222 return fmt.Errorf("unexpected return from run()") 223 }