Ejemplo n.º 1
0
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)
	}
}
Ejemplo n.º 2
0
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)
	}
}
Ejemplo n.º 3
0
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)
	}
}
Ejemplo n.º 4
0
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
}
Ejemplo n.º 5
0
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
}
Ejemplo n.º 6
0
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
}
Ejemplo n.º 7
0
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
}
Ejemplo n.º 8
0
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)
	}
}
Ejemplo n.º 9
0
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
}
Ejemplo n.º 10
0
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
}