tools/functional-tester/etcd-agent: add status rpc

This commit is contained in:
Xiang Li 2015-03-12 15:18:11 -07:00
parent f9ee8ecb3a
commit e46beb75c8
4 changed files with 118 additions and 7 deletions

View File

@ -21,9 +21,20 @@ import (
"os/exec" "os/exec"
"path" "path"
"time" "time"
"github.com/coreos/etcd/tools/functional-tester/etcd-agent/client"
)
const (
stateUninitialized = "uninitialized"
stateStarted = "started"
stateStopped = "stopped"
stateTerminated = "terminated"
) )
type Agent struct { type Agent struct {
state string // the state of etcd process
cmd *exec.Cmd cmd *exec.Cmd
logfile *os.File logfile *os.File
l net.Listener l net.Listener
@ -43,7 +54,7 @@ func newAgent(etcd string) (*Agent, error) {
return nil, err return nil, err
} }
return &Agent{cmd: c, logfile: f}, nil return &Agent{state: stateUninitialized, cmd: c, logfile: f}, nil
} }
// start starts a new etcd process with the given args. // start starts a new etcd process with the given args.
@ -51,7 +62,13 @@ func (a *Agent) start(args ...string) error {
a.cmd = exec.Command(a.cmd.Path, args...) a.cmd = exec.Command(a.cmd.Path, args...)
a.cmd.Stdout = a.logfile a.cmd.Stdout = a.logfile
a.cmd.Stderr = a.logfile a.cmd.Stderr = a.logfile
return a.cmd.Start() err := a.cmd.Start()
if err != nil {
return err
}
a.state = stateStarted
return nil
} }
// stop stops the existing etcd process the agent started. // stop stops the existing etcd process the agent started.
@ -61,7 +78,13 @@ func (a *Agent) stop() error {
return err return err
} }
_, err = a.cmd.Process.Wait() _, err = a.cmd.Process.Wait()
return err if err != nil {
return err
}
a.state = stateStopped
return nil
} }
// restart restarts the stopped etcd process. // restart restarts the stopped etcd process.
@ -69,11 +92,22 @@ func (a *Agent) restart() error {
a.cmd = exec.Command(a.cmd.Path, a.cmd.Args[1:]...) a.cmd = exec.Command(a.cmd.Path, a.cmd.Args[1:]...)
a.cmd.Stdout = a.logfile a.cmd.Stdout = a.logfile
a.cmd.Stderr = a.logfile a.cmd.Stderr = a.logfile
return a.cmd.Start() err := a.cmd.Start()
if err != nil {
return err
}
a.state = stateStarted
return nil
} }
func (a *Agent) cleanup() error { func (a *Agent) cleanup() error {
a.stop() err := a.stop()
if err != nil {
return err
}
a.state = stateUninitialized
a.logfile.Close() a.logfile.Close()
if err := archiveLogAndDataDir("etcd.log", a.dataDir()); err != nil { if err := archiveLogAndDataDir("etcd.log", a.dataDir()); err != nil {
return err return err
@ -86,8 +120,20 @@ func (a *Agent) cleanup() error {
// terminate stops the exiting etcd process the agent started // terminate stops the exiting etcd process the agent started
// and removes the data dir. // and removes the data dir.
func (a *Agent) terminate() error { func (a *Agent) terminate() error {
a.stop() err := a.stop()
return os.RemoveAll(a.dataDir()) if err != nil {
return err
}
err = os.RemoveAll(a.dataDir())
if err != nil {
return err
}
a.state = stateTerminated
return nil
}
func (a *Agent) status() client.Status {
return client.Status{State: a.state}
} }
func (a *Agent) dataDir() string { func (a *Agent) dataDir() string {

View File

@ -16,6 +16,12 @@ package client
import "net/rpc" import "net/rpc"
type Status struct {
// TODO: gather more informations
// TODO: memory usage, raft information, etc..
State string
}
type Agent interface { type Agent interface {
ID() uint64 ID() uint64
// Start starts a new etcd with the given args on the agent machine. // Start starts a new etcd with the given args on the agent machine.
@ -30,6 +36,8 @@ type Agent interface {
Terminate() error Terminate() error
// Isoloate isolates the network of etcd // Isoloate isolates the network of etcd
Isolate() error Isolate() error
// Status returns the status of etcd on the agent
Status() (Status, error)
} }
type agent struct { type agent struct {
@ -79,6 +87,15 @@ func (a *agent) Isolate() error {
panic("not implemented") panic("not implemented")
} }
func (a *agent) Status() (Status, error) {
var s Status
err := a.rpcClient.Call("Agent.RPCStatus", struct{}{}, &s)
if err != nil {
return s, err
}
return s, nil
}
func (a *agent) ID() uint64 { func (a *agent) ID() uint64 {
panic("not implemented") panic("not implemented")
} }

View File

@ -19,6 +19,8 @@ import (
"net" "net"
"net/http" "net/http"
"net/rpc" "net/rpc"
"github.com/coreos/etcd/tools/functional-tester/etcd-agent/client"
) )
func (a *Agent) serveRPC() { func (a *Agent) serveRPC() {
@ -69,3 +71,8 @@ func (a *Agent) RPCTerminate(args struct{}, reply *struct{}) error {
func (a *Agent) RPCIsolate(args struct{}, reply *struct{}) error { func (a *Agent) RPCIsolate(args struct{}, reply *struct{}) error {
panic("not implemented") panic("not implemented")
} }
func (a *Agent) RPCStatus(args struct{}, status *client.Status) error {
*status = a.status()
return nil
}

View File

@ -20,6 +20,8 @@ import (
"net/rpc" "net/rpc"
"os" "os"
"testing" "testing"
"github.com/coreos/etcd/tools/functional-tester/etcd-agent/client"
) )
func init() { func init() {
@ -123,3 +125,42 @@ func TestRPCTerminate(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestRPCStatus(t *testing.T) {
c, err := rpc.DialHTTP("tcp", ":9027")
if err != nil {
t.Fatal(err)
}
var s client.Status
err = c.Call("Agent.RPCStatus", struct{}{}, &s)
if err != nil {
t.Fatal(err)
}
if s.State != stateTerminated {
t.Errorf("state = %s, want %s", s.State, stateTerminated)
}
dir, err := ioutil.TempDir(os.TempDir(), "etcd-agent")
if err != nil {
t.Fatal(err)
}
var pid int
err = c.Call("Agent.RPCStart", []string{"-data-dir", dir}, &pid)
if err != nil {
t.Fatal(err)
}
err = c.Call("Agent.RPCStatus", struct{}{}, &s)
if err != nil {
t.Fatal(err)
}
if s.State != stateStarted {
t.Errorf("state = %s, want %s", s.State, stateStarted)
}
err = c.Call("Agent.RPCTerminate", struct{}{}, nil)
if err != nil {
t.Fatal(err)
}
}