func main() { var bootId string f := flag.NewFlagSet(os.Args[0], 1) f.StringVar(&bootId, "bootid", "", "Provide a user-generated boot ID. This will override the actual boot ID of the machine.") f.Parse(os.Args[1:]) if bootId == "" { bootId = machine.ReadLocalBootId() } m := machine.New(bootId) r := registry.New() a := agent.New(r, m, "") // Push the initial state to the registry a.UpdateJobs() a.UpdateMachine() // Kick off the heartbeating process go a.DoHeartbeat() s := scheduler.New(r, m) s.DoSchedule() }
func TestNewJob(t *testing.T) { mach := machine.New("XXX") js1 := NewJobState("loaded", "inactive", "running", []string{}, mach) jp1 := &JobPayload{"echo.service", "Echo"} j1, _ := NewJob("pong.service", js1, jp1) j2 := Job{"pong.service", "systemd-service", js1, jp1} if *j1 != j2 { t.Error("job.NewJob factory failed to produce appropriate job.Job") } if j1.Name != "pong.service" { t.Fatal("job.Job.Name != 'pong.service'") } if j1.Type != "systemd-service" { t.Fatal("job.Job.Name != 'systemd-service'") } if j1.State != js1 { t.Fatal("job.Job.State does not match expected value") } if j1.Payload != jp1 { t.Fatal("job.Job.Payload does not match expected value") } }
func filterEventJobCreated(resp *etcd.Response) *Event { if resp.Action != "set" || resp.Node.PrevValue != "" { return nil } dir, jobName := path.Split(resp.Node.Key) dir = strings.TrimSuffix(dir, "/") dir, prefix := path.Split(dir) if prefix != strings.Trim(schedulePrefix, "/") { return nil } var jp job.JobPayload err := unmarshal(resp.Node.Value, &jp) if err != nil { log.V(1).Infof("Failed to deserialize JobPayload: %s", err) return nil } j, _ := job.NewJob(jobName, nil, &jp) dir = strings.TrimSuffix(dir, "/") dir, machName := path.Split(dir) m := machine.New(machName) return &Event{"EventJobCreated", *j, m} }
func (self *Server) Configure(cfg *config.Config) { if cfg.BootId != self.machine.BootId { self.machine = machine.New(cfg.BootId) self.agent.Stop() self.agent = agent.New(self.registry, self.events, self.machine, "") go self.agent.Run() } }
func (self *Server) Configure(cfg *config.Config) { if cfg.BootId != self.machine.BootId { self.machine = machine.New(cfg.BootId, cfg.PublicIP, cfg.Metadata()) self.agent.Stop() self.agent = agent.New(self.registry, self.events, self.machine, "", cfg.UnitPrefix) go self.agent.Run() } }
func (r *Registry) GetJobTarget(jobName string) *machine.Machine { // Figure out to which Machine this Job is scheduled key := path.Join(keyPrefix, jobPrefix, jobName, "target") resp, err := r.etcd.Get(key, false, true) if err != nil { return nil } return machine.New(resp.Node.Value, "", make(map[string]string, 0)) }
func New(cfg config.Config) *Server { m := machine.New(cfg.BootId) r := registry.New() es := registry.NewEventStream() a := agent.New(r, es, m, "") e := engine.New(r, es, m) srv := Server{a, e, m, r, es} srv.Configure(&cfg) return &srv }
func filterEventMachineDeleted(resp *etcd.Response) *Event { if base := path.Base(resp.Node.Key); base != "addrs" { return nil } if resp.Action != "expire" && resp.Action != "delete" { return nil } name := path.Base(path.Dir(resp.Node.Key)) m := machine.New(name) return &Event{"EventMachineDeleted", *m, nil} }
func filterEventMachineUpdated(resp *etcd.Response) *Event { if base := path.Base(resp.Node.Key); base != "addrs" { return nil } if resp.Action != "set" || resp.Node.PrevValue == "" { return nil } name := path.Base(path.Dir(resp.Node.Key)) m := machine.New(name) return &Event{"EventMachineUpdated", *m, nil} }
func filterEventJobScheduled(resp *etcd.Response) *Event { if resp.Action != "set" { return nil } dir, baseName := path.Split(resp.Node.Key) if baseName != "target" { return nil } mach := machine.New(resp.Node.Value, "", make(map[string]string, 0)) jobName := path.Base(strings.TrimSuffix(dir, "/")) return &Event{"EventJobScheduled", jobName, mach} }
func New(cfg config.Config) *Server { m := machine.New(cfg.BootId, cfg.PublicIP, cfg.Metadata()) regClient := etcd.NewClient(cfg.EtcdServers) regClient.SetConsistency(etcd.WEAK_CONSISTENCY) r := registry.New(regClient) eventClient := etcd.NewClient(cfg.EtcdServers) eventClient.SetConsistency(etcd.WEAK_CONSISTENCY) es := registry.NewEventStream(eventClient, r) es.Open() a := agent.New(r, es, m, "", cfg.UnitPrefix) e := engine.New(r, es, m) return &Server{a, e, m, r, es} }
func TestNewJob(t *testing.T) { mach := machine.New("XXX", "", make(map[string]string, 0)) js1 := NewJobState("loaded", "inactive", "running", []string{}, mach) jp1, _ := NewJobPayload("echo.service", "Echo", map[string][]string{}) j1 := NewJob("pong.service", js1, jp1) if j1.Name != "pong.service" { t.Fatal("job.Job.Name != 'pong.service'") } if j1.State != js1 { t.Fatal("job.Job.State does not match expected value") } if j1.Payload.Name != jp1.Name { t.Fatal("job.Job.Payload does not match expected value") } }
// Describe all active Machines func (r *Registry) GetActiveMachines() []machine.Machine { key := path.Join(keyPrefix, machinePrefix) resp, err := r.etcd.Get(key, false, true) // Assume the error was KeyNotFound and return an empty data structure if err != nil { return make([]machine.Machine, 0) } machines := make([]machine.Machine, 0) for _, kv := range resp.Node.Nodes { _, bootId := path.Split(kv.Key) machine := machine.New(bootId) // This is a hacky way of telling if a Machine is reporting state addrs := r.getMachineAddrs(machine) if len(addrs) > 0 { machines = append(machines, *machine) } } return machines }
// Describe the list of all known Machines func (r *Registry) GetActiveMachines() map[string]machine.Machine { key := path.Join(keyPrefix, machinePrefix) resp, err := r.Etcd.Get(key, false) // Assume the error was KeyNotFound and return an empty data structure if err != nil { return make(map[string]machine.Machine, 0) } machines := make(map[string]machine.Machine, len(resp.Kvs)) for _, kv := range resp.Kvs { _, bootId := path.Split(kv.Key) machine := machine.New(bootId) // This is a hacky way of telling if a Machine is reporting state addrs := r.GetMachineAddrs(machine) if len(addrs) > 0 { machines[machine.BootId] = *machine } } return machines }
func TestJobState(t *testing.T) { mach := machine.New("XXX", "", make(map[string]string, 0)) js1 := NewJobState("loaded", "inactive", "dead", []string{}, mach) if js1.LoadState != "loaded" { t.Fatal("job.JobState.LoadState != 'loaded'") } if js1.ActiveState != "inactive" { t.Fatal("job.JobState.ActiveState != 'inactive'") } if js1.SubState != "dead" { t.Fatal("job.JobState.SubState != 'dead'") } if len(js1.Sockets) != 0 { t.Fatal("job.JobState.Sockets does not match expected length") } if js1.Machine != mach { t.Fatal("job.JobState.Machine does not match expected value") } }