func main() { var err error flag.Parse() fmt.Printf("Blacksmith (%s)\n", version) fmt.Printf(" Commit: %s\n", commit) fmt.Printf(" Build Time: %s\n", buildTime) if *versionFlag { os.Exit(0) } // etcd config if etcdFlag == nil || clusterNameFlag == nil { fmt.Fprint(os.Stderr, "\nPlease specify the etcd endpoints\n") os.Exit(1) } // finding interface by interface name var dhcpIF *net.Interface if *listenIFFlag != "" { dhcpIF, err = net.InterfaceByName(*listenIFFlag) if err != nil { fmt.Fprintf(os.Stderr, "\nError while trying to get the interface (%s)\n", *listenIFFlag) os.Exit(1) } } else { fmt.Fprint(os.Stderr, "\nPlease specify an interface\n") os.Exit(1) } serverIP, err := interfaceIP(dhcpIF) if err != nil { fmt.Fprintf(os.Stderr, "\nError while trying to get the ip from the interface (%s)\n", dhcpIF) os.Exit(1) } webAddr := net.TCPAddr{IP: serverIP, Port: 8000} if *httpListenFlag != httpListenFlagDefaultTCPAddress { splitAddress := strings.Split(*httpListenFlag, ":") if len(splitAddress) > 2 { fmt.Printf("Incorrect tcp address provided: %s", httpListenFlag) os.Exit(1) } if len(splitAddress) == 1 { splitAddress = append(splitAddress, "8000") } webAddr.IP = net.ParseIP(splitAddress[0]) port, err := strconv.ParseInt(splitAddress[1], 10, 64) if err != nil { fmt.Printf("Incorrect tcp address provided: %s", httpListenFlag) os.Exit(1) } webAddr.Port = int(port) } // component ports // web api is exposed to requests from `webIP', 0.0.0.0 by default // other services are exposed just through the given interface var httpBooterAddr = net.TCPAddr{IP: serverIP, Port: 70} var tftpAddr = net.UDPAddr{IP: serverIP, Port: 69} var pxeAddr = net.UDPAddr{IP: serverIP, Port: 4011} // 67 -> dhcp // dhcp setting leaseStart := net.ParseIP(*leaseStartFlag) leaseRange := *leaseRangeFlag leaseSubnet := net.ParseIP(*leaseSubnetFlag) leaseRouter := net.ParseIP(*leaseRouterFlag) dnsIPStrings := strings.Split(*dnsAddressesFlag, ",") if len(dnsIPStrings) == 0 { fmt.Fprint(os.Stderr, "\nPlease specify an DNS server\n") os.Exit(1) } for _, ipString := range dnsIPStrings { ip := net.ParseIP(ipString) if ip == nil { fmt.Fprintf(os.Stderr, "\nInvalid dns ip: %s\n", ipString) os.Exit(1) } } if leaseStart == nil { fmt.Fprint(os.Stderr, "\nPlease specify the lease start ip\n") os.Exit(1) } if leaseRange <= 1 { fmt.Fprint(os.Stderr, "\nLease range should be greater that 1\n") os.Exit(1) } if leaseSubnet == nil { fmt.Fprint(os.Stderr, "\nPlease specify the lease subnet\n") os.Exit(1) } if leaseRouter == nil { fmt.Fprint(os.Stderr, "\nNo network router is defined.\n") } fmt.Printf("Interface IP: %s\n", serverIP.String()) fmt.Printf("Interface Name: %s\n", dhcpIF.Name) // datasources etcdClient, err := etcd.New(etcd.Config{ Endpoints: strings.Split(*etcdFlag, ","), HeaderTimeoutPerRequest: 5 * time.Second, }) if err != nil { fmt.Fprintf(os.Stderr, "\nCouldn't create etcd connection: %s\n", err) os.Exit(1) } kapi := etcd.NewKeysAPI(etcdClient) v := datasource.BlacksmithVersion{ Version: version, Commit: commit, BuildTime: buildTime, } etcdDataSource, err := datasource.NewEtcdDataSource(kapi, etcdClient, leaseStart, leaseRange, *clusterNameFlag, *workspacePathFlag, serverIP, dnsIPStrings, v) if err != nil { fmt.Fprintf(os.Stderr, "\nCouldn't create runtime configuration: %s\n", err) os.Exit(1) } go func() { logging.RecordLogs(log.New(os.Stderr, "", log.LstdFlags), *debugFlag) }() // serving api go func() { err := web.ServeWeb(etcdDataSource, webAddr) log.Fatalf("\nError while serving api: %s\n", err) }() c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) go func() { for _ = range c { gracefulShutdown(etcdDataSource) } }() // waiting til we're officially the master instance for !etcdDataSource.IsMaster() { logging.Debug(debugTag, "Not master, waiting to be promoted...") time.Sleep(datasource.StandbyMasterUpdateTime) } logging.Debug(debugTag, "Now we're the master instance. Starting the services...") // serving http booter go func() { err := pxe.ServeHTTPBooter(httpBooterAddr, etcdDataSource, webAddr.Port) log.Fatalf("\nError while serving http booter: %s\n", err) }() // serving tftp go func() { err := pxe.ServeTFTP(tftpAddr) log.Fatalf("\nError while serving tftp: %s\n", err) }() // pxe protocol go func() { err := pxe.ServePXE(pxeAddr, serverIP, httpBooterAddr) log.Fatalf("\nError while serving pxe: %s\n", err) }() // serving dhcp go func() { err := dhcp.ServeDHCP(&dhcp.DHCPSetting{ IFName: dhcpIF.Name, ServerIP: serverIP, RouterAddr: leaseRouter, SubnetMask: leaseSubnet, }, etcdDataSource) log.Fatalf("\nError while serving dhcp: %s\n", err) }() for etcdDataSource.IsMaster() { time.Sleep(datasource.ActiveMasterUpdateTime) } logging.Debug(debugTag, "Now we're NOT the master. Terminating. Hoping to be restarted by the service manager.") gracefulShutdown(etcdDataSource) }
func main() { var err error flag.Parse() fmt.Printf("Blacksmith (%s)\n", version) fmt.Printf(" Commit: %s\n", commit) fmt.Printf(" Build Time: %s\n", buildTime) if *versionFlag { os.Exit(0) } if *debugFlag { log.SetLevel(log.DebugLevel) } else { log.SetLevel(log.InfoLevel) } // etcd config if etcdFlag == nil || clusterNameFlag == nil { fmt.Fprint(os.Stderr, "\nPlease specify the etcd endpoints\n") os.Exit(1) } // finding interface by interface name var dhcpIF *net.Interface if *listenIFFlag != "" { dhcpIF, err = net.InterfaceByName(*listenIFFlag) if err != nil { fmt.Fprintf(os.Stderr, "\nError while trying to get the interface (%s): %s\n", *listenIFFlag, err) os.Exit(1) } } else { fmt.Fprint(os.Stderr, "\nPlease specify an interface\n") os.Exit(1) } serverIP, err := interfaceIP(dhcpIF) if err != nil { fmt.Fprintf(os.Stderr, "\nError while trying to get the ip from the interface (%v)\n", dhcpIF) os.Exit(1) } // web api can be configured to listen on a custom address webAddr := net.TCPAddr{IP: serverIP, Port: 8000} if *httpListenFlag != httpListenFlagDefaultTCPAddress { splitAddress := strings.Split(*httpListenFlag, ":") if len(splitAddress) > 2 { fmt.Printf("Incorrect tcp address provided: %s\n", *httpListenFlag) os.Exit(1) } if len(splitAddress) == 1 { splitAddress = append(splitAddress, "8000") } webAddr.IP = net.ParseIP(splitAddress[0]) port, err := strconv.ParseInt(splitAddress[1], 10, 64) if err != nil { fmt.Printf("Incorrect tcp address provided: %s\n", *httpListenFlag) os.Exit(1) } webAddr.Port = int(port) } // other services are exposed just through the given interface, on hard coded ports var httpBooterAddr = net.TCPAddr{IP: serverIP, Port: 70} var tftpAddr = net.UDPAddr{IP: serverIP, Port: 69} var pxeAddr = net.UDPAddr{IP: serverIP, Port: 4011} // 67 -> dhcp // dhcp setting leaseStart := net.ParseIP(*leaseStartFlag) leaseRange := *leaseRangeFlag dnsIPStrings := strings.Split(*dnsAddressesFlag, ",") if len(dnsIPStrings) == 0 { fmt.Fprint(os.Stderr, "\nPlease specify an DNS server\n") os.Exit(1) } for _, ipString := range dnsIPStrings { ip := net.ParseIP(ipString) if ip == nil { fmt.Fprintf(os.Stderr, "\nInvalid dns ip: %s\n", ipString) os.Exit(1) } } if leaseStart == nil { fmt.Fprint(os.Stderr, "\nPlease specify the lease start ip\n") os.Exit(1) } if leaseRange <= 1 { fmt.Fprint(os.Stderr, "\nLease range should be greater that 1\n") os.Exit(1) } fmt.Printf("Interface IP: %s\n", serverIP.String()) fmt.Printf("Interface Name: %s\n", dhcpIF.Name) // datasources etcdClient, err := etcd.New(etcd.Config{ Endpoints: strings.Split(*etcdFlag, ","), HeaderTimeoutPerRequest: 5 * time.Second, }) if err != nil { fmt.Fprintf(os.Stderr, "\nCouldn't create etcd connection: %s\n", err) os.Exit(1) } kapi := etcd.NewKeysAPI(etcdClient) selfInfo := datasource.InstanceInfo{ IP: serverIP, Nic: dhcpIF.HardwareAddr, WebPort: webAddr.Port, Version: version, Commit: commit, BuildTime: buildTime, ServiceStartTime: time.Now().UTC().Unix(), } etcdDataSource, err := datasource.NewEtcdDataSource(kapi, etcdClient, leaseStart, leaseRange, *clusterNameFlag, *workspacePathFlag, dnsIPStrings, selfInfo) if err != nil { fmt.Fprintf(os.Stderr, "\nCouldn't create runtime configuration: %s\n", err) os.Exit(1) } // serving api go func() { err := web.ServeWeb(etcdDataSource, webAddr) log.Fatalf("\nError while serving api: %s\n", err) }() c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) go func() { for _ = range c { gracefulShutdown(etcdDataSource) } }() // waiting till we're officially the master instance for etcdDataSource.WhileMaster() != nil { log.WithFields(log.Fields{ "where": "blacksmith.main", "action": "debug", }).Debug("Not master, waiting to be promoted...") time.Sleep(datasource.StandbyMasterUpdateTime) } log.WithFields(log.Fields{ "where": "blacksmith.main", "action": "debug", }).Debug("Now we're the master instance. Starting the services...") // serving http booter go func() { err := pxe.ServeHTTPBooter(httpBooterAddr, etcdDataSource, webAddr.Port) log.Fatalf("\nError while serving http booter: %s\n", err) }() // serving tftp go func() { err := pxe.ServeTFTP(tftpAddr) log.Fatalf("\nError while serving tftp: %s\n", err) }() // pxe protocol go func() { err := pxe.ServePXE(pxeAddr, serverIP, httpBooterAddr) log.Fatalf("\nError while serving pxe: %s\n", err) }() // serving dhcp go func() { err := dhcp.StartDHCP(dhcpIF.Name, serverIP, etcdDataSource) log.Fatalf("\nError while serving dhcp: %s\n", err) }() for etcdDataSource.WhileMaster() == nil { time.Sleep(datasource.ActiveMasterUpdateTime) } log.WithFields(log.Fields{ "where": "blacksmith.main", "action": "debug", }).Debug("Now we're NOT the master. Terminating. Hoping to be restarted by the service manager.") gracefulShutdown(etcdDataSource) }