func TestAgentLoadUnloadJob(t *testing.T) { uManager := unit.NewFakeUnitManager() usGenerator := unit.NewUnitStateGenerator(uManager) fReg := registry.NewFakeRegistry() mach := &machine.FakeMachine{machine.MachineState{ID: "XXX"}} a, err := New(uManager, usGenerator, fReg, mach, DefaultTTL) if err != nil { t.Fatalf("Failed creating Agent: %v", err) } j := newTestJobFromUnitContents(t, "foo.service", "") err = a.loadJob(j) if err != nil { t.Fatalf("Failed calling Agent.loadJob: %v", err) } jobs, err := a.jobs() if err != nil { t.Fatalf("Failed calling Agent.jobs: %v", err) } jsLoaded := job.JobStateLoaded expectJobs := map[string]*job.Job{ "foo.service": &job.Job{ Name: "foo.service", UnitState: &unit.UnitState{ LoadState: "loaded", ActiveState: "active", SubState: "running", MachineID: "", }, State: &jsLoaded, Unit: unit.Unit{}, TargetState: job.JobState(""), TargetMachineID: "", }, } if !reflect.DeepEqual(expectJobs, jobs) { t.Fatalf("Received unexpected collection of Jobs: %#v\nExpected: %#v", jobs, expectJobs) } a.unloadJob("foo.service") // This sucks, but we have to do it if Agent.unloadJob is going to spin // off the real work that matters in a goroutine time.Sleep(200) jobs, err = a.jobs() if err != nil { t.Fatalf("Failed calling Agent.jobs: %v", err) } expectJobs = map[string]*job.Job{} if !reflect.DeepEqual(expectJobs, jobs) { t.Fatalf("Received unexpected collection of Jobs: %#v\nExpected: %#v", jobs, expectJobs) } }
func TestAgentLoadStartStopUnit(t *testing.T) { uManager := unit.NewFakeUnitManager() usGenerator := unit.NewUnitStateGenerator(uManager) fReg := registry.NewFakeRegistry() mach := &machine.FakeMachine{MachineState: machine.MachineState{ID: "XXX"}} a := New(uManager, usGenerator, fReg, mach, time.Second) u := newTestUnitFromUnitContents(t, "foo.service", "") err := a.loadUnit(u) if err != nil { t.Fatalf("Failed calling Agent.loadUnit: %v", err) } err = a.startUnit("foo.service") if err != nil { t.Fatalf("Failed starting unit foo.service: %v", err) } units, err := a.units() if err != nil { t.Fatalf("Failed calling Agent.units: %v", err) } jsLaunched := job.JobStateLaunched expectUnits := unitStates{ "foo.service": unitState{ state: jsLaunched, }, } if !reflect.DeepEqual(expectUnits, units) { t.Fatalf("Received unexpected collection of Units: %#v\nExpected: %#v", units, expectUnits) } err = a.stopUnit("foo.service") if err != nil { t.Fatalf("Failed stopping unit foo.service: %v", err) } units, err = a.units() if err != nil { t.Fatalf("Failed calling Agent.units: %v", err) } jsLoaded := job.JobStateLoaded expectUnits = unitStates{ "foo.service": unitState{ state: jsLoaded, }, } if !reflect.DeepEqual(expectUnits, units) { t.Fatalf("Received unexpected collection of Units: %#v\nExpected: %#v", units, expectUnits) } }
func TestAgentLoadUnloadJob(t *testing.T) { uManager := unit.NewFakeUnitManager() usGenerator := unit.NewUnitStateGenerator(uManager) fReg := registry.NewFakeRegistry() mach := &machine.FakeMachine{machine.MachineState{ID: "XXX"}} a := New(uManager, usGenerator, fReg, mach, time.Second) j := newTestJobFromUnitContents(t, "foo.service", "") err := a.loadJob(j) if err != nil { t.Fatalf("Failed calling Agent.loadJob: %v", err) } jobs, err := a.jobs() if err != nil { t.Fatalf("Failed calling Agent.jobs: %v", err) } jsLoaded := job.JobStateLoaded expectJobs := map[string]*job.Job{ "foo.service": &job.Job{ Name: "foo.service", State: &jsLoaded, Unit: unit.UnitFile{}, TargetState: job.JobState(""), TargetMachineID: "", }, } if !reflect.DeepEqual(expectJobs, jobs) { t.Fatalf("Received unexpected collection of Jobs: %#v\nExpected: %#v", jobs, expectJobs) } a.unloadJob("foo.service") jobs, err = a.jobs() if err != nil { t.Fatalf("Failed calling Agent.jobs: %v", err) } expectJobs = map[string]*job.Job{} if !reflect.DeepEqual(expectJobs, jobs) { t.Fatalf("Received unexpected collection of Jobs: %#v\nExpected: %#v", jobs, expectJobs) } }
func New(cfg config.Config) (*Server, error) { agentTTL, err := time.ParseDuration(cfg.AgentTTL) if err != nil { return nil, err } mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eCfg := etcd.Config{ Transport: &http.Transport{TLSClientConfig: tlsConfig}, Endpoints: cfg.EtcdServers, } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } etcdRequestTimeout := time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond kAPI := etcd.NewKeysAPI(eClient) reg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix, etcdRequestTimeout) pub := agent.NewUnitStatePublisher(reg, mach, agentTTL) gen := unit.NewUnitStateGenerator(mgr) a := agent.New(mgr, gen, reg, mach, agentTTL) var rStream pkg.EventStream if !cfg.DisableWatches { rStream = registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix) } lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix, etcdRequestTimeout) ar := agent.NewReconciler(reg, rStream) e := engine.New(reg, lManager, rStream, mach) listeners, err := activation.Listeners(false) if err != nil { return nil, err } hrt := heart.New(reg, mach) mon := heart.NewMonitor(agentTTL) apiServer := api.NewServer(listeners, api.NewServeMux(reg, cfg.TokenLimit)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, stop: nil, engineReconcileInterval: eIval, disableEngine: cfg.DisableEngine, } return &srv, nil }
func New(cfg config.Config) (*Server, error) { mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := etcd.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eTrans := http.Transport{TLSClientConfig: tlsConfig} timeout := time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond eClient, err := etcd.NewClient(cfg.EtcdServers, eTrans, timeout) if err != nil { return nil, err } reg := registry.New(eClient, cfg.EtcdKeyPrefix) pub := agent.NewUnitStatePublisher(mgr, reg, mach) gen := unit.NewUnitStateGenerator(mgr) a, err := newAgentFromConfig(mach, reg, cfg, mgr, gen) if err != nil { return nil, err } ar, err := newAgentReconcilerFromConfig(reg, eClient, cfg) if err != nil { return nil, err } e, err := newEngineFromConfig(reg, eClient, mach, cfg) if err != nil { return nil, err } listeners, err := activation.Listeners(false) if err != nil { return nil, err } hrt, mon, err := newHeartMonitorFromConfig(mach, reg, cfg) if err != nil { return nil, err } apiServer := api.NewServer(listeners, api.NewServeMux(reg)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, stop: nil, engineReconcileInterval: eIval, } return &srv, nil }
func New(cfg config.Config, listeners []net.Listener) (*Server, error) { agentTTL, err := time.ParseDuration(cfg.AgentTTL) if err != nil { return nil, err } mgr, err := systemd.NewSystemdUnitManager(cfg.UnitsDirectory, cfg.SystemdUser) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eCfg := etcd.Config{ Transport: &http.Transport{TLSClientConfig: tlsConfig}, Endpoints: cfg.EtcdServers, HeaderTimeoutPerRequest: (time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond), Username: cfg.EtcdUsername, Password: cfg.EtcdPassword, } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } kAPI := etcd.NewKeysAPI(eClient) var ( reg engine.CompleteRegistry genericReg interface{} ) lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix) if !cfg.EnableGRPC { genericReg = registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix) if obj, ok := genericReg.(engine.CompleteRegistry); ok { reg = obj } } else { etcdReg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix) genericReg = rpc.NewRegistryMux(etcdReg, mach, lManager) if obj, ok := genericReg.(engine.CompleteRegistry); ok { reg = obj } } pub := agent.NewUnitStatePublisher(reg, mach, agentTTL) gen := unit.NewUnitStateGenerator(mgr) a := agent.New(mgr, gen, reg, mach, agentTTL) var rStream pkg.EventStream if !cfg.DisableWatches { rStream = registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix) } ar := agent.NewReconciler(reg, rStream) var e *engine.Engine if !cfg.EnableGRPC { e = engine.New(reg, lManager, rStream, mach, nil) } else { regMux := genericReg.(*rpc.RegistryMux) e = engine.New(reg, lManager, rStream, mach, regMux.EngineChanged) if cfg.DisableEngine { go regMux.ConnectToRegistry(e) } } if len(listeners) == 0 { listeners, err = activation.Listeners(false) if err != nil { return nil, err } } hrt := heart.New(reg, mach) mon := NewMonitor(agentTTL) apiServer := api.NewServer(listeners, api.NewServeMux(reg, cfg.TokenLimit)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, killc: make(chan struct{}), stopc: nil, engineReconcileInterval: eIval, disableEngine: cfg.DisableEngine, reconfigServer: false, restartServer: false, } return &srv, nil }
func New(cfg config.Config) (*Server, error) { agentTTL, err := time.ParseDuration(cfg.AgentTTL) if err != nil { return nil, err } mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } etcdRequestTimeout := time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond // set a per server request timeout that is the global request timeout divided by the number of quorum nodes (i.e. 3 out of 5) // this ensures that the the retry logic in etcd can try at least 3 servers before the global timeout fires and cancels the entire request quorumCount := (len(cfg.EtcdServers) / 2) + 1 etcdRequestPerServerTimeout := etcdRequestTimeout if quorumCount > 1 { etcdRequestPerServerTimeout = time.Duration(int64(etcdRequestTimeout) / int64(quorumCount)) } log.Infof("Etcd endpoints: %v", strings.Join(cfg.EtcdServers, ",")) log.Infof("Setting global request timeout of %v and per server request timeout of %v using a quorum count of %v", etcdRequestTimeout, etcdRequestPerServerTimeout, quorumCount) eCfg := etcd.Config{ Transport: &http.Transport{TLSClientConfig: tlsConfig}, Endpoints: cfg.EtcdServers, HeaderTimeoutPerRequest: etcdRequestPerServerTimeout, } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } kAPI := etcd.NewKeysAPI(eClient) reg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix, etcdRequestTimeout) pub := agent.NewUnitStatePublisher(reg, mach, agentTTL) gen := unit.NewUnitStateGenerator(mgr) a := agent.New(mgr, gen, reg, mach, agentTTL) rStream := registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix) lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix, etcdRequestTimeout) ar := agent.NewReconciler(reg, rStream) e := engine.New(reg, lManager, rStream, mach) listeners, err := activation.Listeners(false) if err != nil { return nil, err } hrt := heart.New(reg, mach) mon := heart.NewMonitor(agentTTL) apiServer := api.NewServer(listeners, api.NewServeMux(reg)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, stop: nil, engineReconcileInterval: eIval, } return &srv, nil }
func TestAgentLoadStartStopJob(t *testing.T) { uManager := unit.NewFakeUnitManager() usGenerator := unit.NewUnitStateGenerator(uManager) fReg := registry.NewFakeRegistry() mach := &machine.FakeMachine{machine.MachineState{ID: "XXX"}} a, err := New(uManager, usGenerator, fReg, mach, DefaultTTL) if err != nil { t.Fatalf("Failed creating Agent: %v", err) } u, err := unit.NewUnit("") if err != nil { t.Fatalf("Failed creating Unit: %v", err) } j := job.NewJob("foo.service", *u) err = a.loadJob(j) if err != nil { t.Fatalf("Failed calling Agent.loadJob: %v", err) } a.startJob("foo.service") jobs, err := a.jobs() if err != nil { t.Fatalf("Failed calling Agent.jobs: %v", err) } jsLaunched := job.JobStateLaunched expectJobs := map[string]*job.Job{ "foo.service": &job.Job{ Name: "foo.service", UnitState: &unit.UnitState{ LoadState: "loaded", ActiveState: "active", SubState: "running", MachineID: "", }, State: &jsLaunched, Unit: unit.Unit{}, TargetState: job.JobState(""), TargetMachineID: "", }, } if !reflect.DeepEqual(expectJobs, jobs) { t.Fatalf("Received unexpected collection of Jobs: %#v\nExpected: %#v", jobs, expectJobs) } a.stopJob("foo.service") jobs, err = a.jobs() if err != nil { t.Fatalf("Failed calling Agent.jobs: %v", err) } jsLoaded := job.JobStateLoaded expectJobs = map[string]*job.Job{ "foo.service": &job.Job{ Name: "foo.service", UnitState: &unit.UnitState{ LoadState: "loaded", ActiveState: "active", SubState: "running", MachineID: "", }, State: &jsLoaded, Unit: unit.Unit{}, TargetState: job.JobState(""), TargetMachineID: "", }, } if !reflect.DeepEqual(expectJobs, jobs) { t.Fatalf("Received unexpected collection of Jobs: %#v\nExpected: %#v", jobs, expectJobs) } }
func New(cfg config.Config) (*Server, error) { etcdRequestTimeout := time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond agentTTL, err := time.ParseDuration(cfg.AgentTTL) if err != nil { return nil, err } mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eTrans := &http.Transport{TLSClientConfig: tlsConfig} eClient, err := etcd.NewClient(cfg.EtcdServers, eTrans, etcdRequestTimeout) if err != nil { return nil, err } reg := registry.NewEtcdRegistry(eClient, cfg.EtcdKeyPrefix) pub := agent.NewUnitStatePublisher(reg, mach, agentTTL) gen := unit.NewUnitStateGenerator(mgr) a := agent.New(mgr, gen, reg, mach, agentTTL) rStream := registry.NewEtcdEventStream(eClient, cfg.EtcdKeyPrefix) ar := agent.NewReconciler(reg, rStream) e := engine.New(reg, rStream, mach) listeners, err := activation.Listeners(false) if err != nil { return nil, err } hrt := heart.New(reg, mach) mon := heart.NewMonitor(agentTTL) apiServer := api.NewServer(listeners, api.NewServeMux(reg)) apiServer.Serve() eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, mach: mach, hrt: hrt, mon: mon, api: apiServer, stop: nil, engineReconcileInterval: eIval, } return &srv, nil }
func New(cfg config.Config) (*Server, error) { mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory) if err != nil { return nil, err } mach, err := newMachineFromConfig(cfg, mgr) if err != nil { return nil, err } tlsConfig, err := etcd.TLSClientConfig(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile) if err != nil { return nil, err } eClient, err := etcd.NewClient(cfg.EtcdServers, http.Transport{TLSClientConfig: tlsConfig}) if err != nil { return nil, err } reg := registry.New(eClient, cfg.EtcdKeyPrefix) pub := agent.NewUnitStatePublisher(mgr, reg, mach) gen := unit.NewUnitStateGenerator(mgr) a, err := newAgentFromConfig(mach, reg, cfg, mgr, gen) if err != nil { return nil, err } ar, err := newAgentReconcilerFromConfig(reg, cfg) if err != nil { return nil, err } e := engine.New(reg, mach) rStream, err := registry.NewEventStream(eClient, reg) if err != nil { return nil, err } eBus := event.NewEventBus() eBus.AddListener(event.JobEvent, ar.Trigger) eBus.AddListener(event.GlobalEvent, e.Trigger) listeners, err := activation.Listeners(false) if err != nil { return nil, err } hrt, mon, err := newHeartMonitorFromConfig(mach, reg, cfg) if err != nil { return nil, err } apiServer := api.NewServer(listeners, api.NewServeMux(reg)) apiServer.Serve() srv := Server{ agent: a, aReconciler: ar, usGen: gen, usPub: pub, engine: e, rStream: rStream, eBus: eBus, mach: mach, hrt: hrt, mon: mon, api: apiServer, stop: nil, } return &srv, nil }