func main() { hostname, _ := os.Hostname() externalAddr := flag.String("external", "", "external IP of host") bindAddr := flag.String("bind", "", "bind containers to this IP") configFile := flag.String("config", "", "configuration file") manifestFile := flag.String("manifest", "/etc/flynn-host.json", "manifest file") hostID := flag.String("id", hostname, "host id") force := flag.Bool("force", false, "kill all containers booted by flynn-host before starting") attributes := make(AttributeFlag) flag.Var(&attributes, "attribute", "key=value pair to add as an attribute") flag.Parse() grohl.AddContext("app", "lorne") grohl.Log(grohl.Data{"at": "start"}) g := grohl.NewContext(grohl.Data{"fn": "main"}) dockerc, err := docker.NewClient("unix:///var/run/docker.sock") if err != nil { log.Fatal(err) } if *force { if err := killExistingContainers(dockerc); err != nil { os.Exit(1) } } state := NewState() ports := make(chan int) go allocatePorts(ports, 55000, 65535) go serveHTTP(&Host{state: state, docker: dockerc}, &attachHandler{state: state, docker: dockerc}) go streamEvents(dockerc, state) processor := &jobProcessor{ externalAddr: *externalAddr, bindAddr: *bindAddr, docker: dockerc, state: state, discoverd: os.Getenv("DISCOVERD"), } runner := &manifestRunner{ env: parseEnviron(), externalIP: *externalAddr, ports: ports, processor: processor, docker: dockerc, } var disc *discoverd.Client if *manifestFile != "" { var r io.Reader var f *os.File if *manifestFile == "-" { r = os.Stdin } else { f, err = os.Open(*manifestFile) if err != nil { log.Fatal(err) } r = f } services, err := runner.runManifest(r) if err != nil { log.Fatal(err) } if f != nil { f.Close() } if d, ok := services["discoverd"]; ok { processor.discoverd = fmt.Sprintf("%s:%d", d.InternalIP, d.TCPPorts[0]) var disc *discoverd.Client err = Attempts.Run(func() (err error) { disc, err = discoverd.NewClientWithAddr(processor.discoverd) return }) if err != nil { log.Fatal(err) } } } if processor.discoverd == "" && *externalAddr != "" { processor.discoverd = *externalAddr + ":1111" } // HACK: use env as global for discoverd connection in sampic os.Setenv("DISCOVERD", processor.discoverd) if disc == nil { disc, err = discoverd.NewClientWithAddr(processor.discoverd) if err != nil { log.Fatal(err) } } sampiStandby, err := disc.RegisterAndStandby("flynn-host", *externalAddr+":1113", map[string]string{"id": *hostID}) if err != nil { log.Fatal(err) } // Check if we are the leader so that we can use the cluster functions directly sampiCluster := sampi.NewCluster(sampi.NewState()) select { case <-sampiStandby: g.Log(grohl.Data{"at": "sampi_leader"}) rpc.Register(sampiCluster) case <-time.After(5 * time.Millisecond): go func() { <-sampiStandby g.Log(grohl.Data{"at": "sampi_leader"}) rpc.Register(sampiCluster) }() } cluster, err := cluster.NewClientWithSelf(*hostID, NewLocalClient(*hostID, sampiCluster)) if err != nil { log.Fatal(err) } g.Log(grohl.Data{"at": "sampi_connected"}) events := make(chan host.Event) state.AddListener("all", events) go syncScheduler(cluster, events) h := &host.Host{} if *configFile != "" { h, err = openConfig(*configFile) if err != nil { log.Fatal(err) } } if h.Attributes == nil { h.Attributes = make(map[string]string) } for k, v := range attributes { h.Attributes[k] = v } h.ID = *hostID for { newLeader := cluster.NewLeaderSignal() h.Jobs = state.ClusterJobs() jobs := make(chan *host.Job) hostErr := cluster.RegisterHost(h, jobs) g.Log(grohl.Data{"at": "host_registered"}) processor.Process(ports, jobs) g.Log(grohl.Data{"at": "sampi_disconnected", "err": *hostErr}) <-newLeader } }
func main() { hostname, _ := os.Hostname() externalAddr := flag.String("external", "", "external IP of host") configFile := flag.String("config", "", "configuration file") manifestFile := flag.String("manifest", "", "manifest file") hostID := flag.String("id", hostname, "host id") attributes := make(AttributeFlag) flag.Var(&attributes, "attribute", "key=value pair to add as an attribute") flag.Parse() grohl.AddContext("app", "lorne") grohl.Log(grohl.Data{"at": "start"}) g := grohl.NewContext(grohl.Data{"fn": "main"}) dockerc, err := docker.NewClient("unix:///var/run/docker.sock") if err != nil { log.Fatal(err) } state := NewState() ports := make(chan int) go allocatePorts(ports, 55000, 65535) go serveHTTP(&Host{state: state, docker: dockerc}, &attachHandler{state: state, docker: dockerc}) go streamEvents(dockerc, state) processor := &jobProcessor{ externalAddr: *externalAddr, docker: dockerc, state: state, discoverd: os.Getenv("DISCOVERD"), } runner := &manifestRunner{ env: parseEnviron(), externalIP: *externalAddr, ports: ports, processor: processor, docker: dockerc, } var disc *discoverd.Client if *manifestFile != "" { f, err := os.Open(*manifestFile) if err != nil { log.Fatal(err) } services, err := runner.runManifest(f) if err != nil { log.Fatal(err) } f.Close() if d, ok := services["discoverd"]; ok { processor.discoverd = fmt.Sprintf("%s:%d", d.InternalIP, d.TCPPorts[0]) var disc *discoverd.Client err = Attempts.Run(func() (err error) { disc, err = discoverd.NewClientUsingAddress(processor.discoverd) return }) if err != nil { log.Fatal(err) } } } if processor.discoverd == "" && *externalAddr != "" { processor.discoverd = *externalAddr + ":1111" } // HACK: use env as global for discoverd connection in sampic os.Setenv("DISCOVERD", processor.discoverd) if disc == nil { disc, err = discoverd.NewClientUsingAddress(processor.discoverd) if err != nil { log.Fatal(err) } } sampiStandby, err := disc.RegisterAndStandby("flynn-host", *externalAddr+":1113", map[string]string{"id": *hostID}) if err != nil { log.Fatal(err) } go func() { <-sampiStandby rpc.Register(sampi.NewCluster(sampi.NewState())) }() cluster, err := client.New() if err != nil { log.Fatal(err) } g.Log(grohl.Data{"at": "sampi_connected"}) events := make(chan host.Event) state.AddListener("all", events) go syncScheduler(cluster, events) var h *host.Host if *configFile != "" { h, err = openConfig(*configFile) if err != nil { log.Fatal(err) } } else { h = &host.Host{Resources: make(map[string]host.ResourceValue)} } if _, ok := h.Resources["memory"]; !ok { h.Resources["memory"] = host.ResourceValue{Value: 1024} } h.ID = *hostID h.Jobs = state.ClusterJobs() if h.Attributes == nil { h.Attributes = make(map[string]string) } for k, v := range attributes { h.Attributes[k] = v } jobs := make(chan *host.Job) hostErr := cluster.ConnectHost(h, jobs) g.Log(grohl.Data{"at": "host_registered"}) processor.Process(ports, jobs) log.Fatal(*hostErr) }