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) }
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) } // etcd config if etcdFlag == nil || etcdDirFlag == nil { fmt.Fprint(os.Stderr, "please specify the etcd endpoints\n") os.Exit(1) } // listen ip address for http, tftp var listenIP = net.IP{0, 0, 0, 0} // finding interface by interface name var dhcpIF *net.Interface if *listenIFFlag != "" { dhcpIF, err = net.InterfaceByName(*listenIFFlag) } else { fmt.Fprint(os.Stderr, "please specify an interface\n") os.Exit(1) } if err != nil { log.Fatalln(err) } dhcpIP, err := interfaceIP(dhcpIF) if err != nil { log.Fatalln(err) } // used for replying in dhcp and pxe var serverIP = net.IPv4zero if serverIP.Equal(net.IPv4zero) { serverIP = dhcpIP } var httpAddr = net.TCPAddr{IP: listenIP, Port: 70} var tftpAddr = net.UDPAddr{IP: listenIP, Port: 69} var webAddr = net.TCPAddr{IP: listenIP, Port: 8000} var cloudConfigHTTPAddr = net.TCPAddr{IP: listenIP, Port: 8001} var pxeAddr = net.UDPAddr{IP: dhcpIP, Port: 4011} // dhcp setting leaseStart := net.ParseIP(*leaseStartFlag) leaseRange := *leaseRangeFlag leaseSubnet := net.ParseIP(*leaseSubnetFlag) leaseRouter := net.ParseIP(*leaseRouterFlag) leaseDNS := net.ParseIP(*leaseDNSFlag) leaseDuration := 1 * time.Hour if leaseStart == nil { fmt.Fprint(os.Stderr, "please specify the lease start ip\n") os.Exit(1) } if leaseRange <= 1 { fmt.Fprint(os.Stderr, "lease range should be greater that 1\n") os.Exit(1) } if leaseSubnet == nil { fmt.Fprint(os.Stderr, "please specify the lease subnet\n") os.Exit(1) } if leaseRouter == nil { fmt.Fprint(os.Stderr, "please specify the IP address of network router\n") os.Exit(1) } if leaseDNS == nil { fmt.Fprint(os.Stderr, "please specify an DNS server\n") os.Exit(1) } fmt.Printf("Server IP: %s\n", serverIP.String()) fmt.Printf("Interface IP: %s\n", dhcpIP.String()) fmt.Printf("Interface Name: %s\n", dhcpIF.Name) // datasources etcdClient, err := etcd.New(etcd.Config{ Endpoints: strings.Split(*etcdFlag, ","), HeaderTimeoutPerRequest: time.Second, }) if err != nil { fmt.Fprintf(os.Stderr, "couldn't create etcd connection: %s\n", err) os.Exit(1) } kapi := etcd.NewKeysAPI(etcdClient) runtimeConfig, err := datasource.NewRuntimeConfiguration(kapi, etcdClient, *etcdDirFlag, *workspacePathFlag) if err != nil { fmt.Fprintf(os.Stderr, "couldn't create runtime configuration: %s\n", err) os.Exit(1) } flagsDataSource, err := datasource.NewFlags(kapi, path.Join(*etcdDirFlag, "flags")) if err != nil { fmt.Fprintf(os.Stderr, "couldn't create runtime configuration: %s\n", err) os.Exit(1) } datasources := map[string]cloudconfig.DataSource{ "default": runtimeConfig, "flags": flagsDataSource, } // serving cloudconfig go func() { log.Fatalln(cloudconfig.ServeCloudConfig(cloudConfigHTTPAddr, *workspacePathFlag, datasources)) }() // serving http booter go func() { repo, err := cloudconfig.FromPath(datasources, path.Join(*workspacePathFlag, "config/bootparams")) if err != nil { log.Fatalln(err) } log.Fatalln(pxe.ServeHTTPBooter(httpAddr, runtimeConfig, repo)) }() // serving tftp go func() { log.Fatalln(pxe.ServeTFTP(tftpAddr)) }() // pxe protocol go func() { log.Fatalln(pxe.ServePXE(pxeAddr, serverIP, net.TCPAddr{IP: serverIP, Port: httpAddr.Port})) }() // serving dhcp leasePool, err := dhcp.NewLeasePool(kapi, *etcdDirFlag, leaseStart, leaseRange, leaseDuration) if err != nil { log.Fatalln(err) } // serving web go func() { restServer := web.NewRest(leasePool, runtimeConfig) log.Fatalln(web.ServeWeb(restServer, webAddr)) }() go func() { log.Fatalln(dhcp.ServeDHCP(&dhcp.DHCPSetting{ IFName: dhcpIF.Name, LeaseDuration: leaseDuration, ServerIP: serverIP, RouterAddr: leaseRouter, SubnetMask: leaseSubnet, DNSAddr: leaseDNS, }, leasePool)) }() logging.RecordLogs(log.New(os.Stderr, "", log.LstdFlags), *debugFlag) }