Example #1
0
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)
}
Example #2
0
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)
}
Example #3
0
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)
}