mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
181 lines
4.5 KiB
Go
181 lines
4.5 KiB
Go
// Copyright 2017 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
|
|
"go.etcd.io/etcd/client/pkg/v3/fileutil"
|
|
"go.etcd.io/etcd/pkg/v3/expect"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var (
|
|
EtcdServerReadyLines = []string{"ready to serve client requests"}
|
|
BinPath string
|
|
CtlBinPath string
|
|
UtlBinPath string
|
|
)
|
|
|
|
// EtcdProcess is a process that serves etcd requests.
|
|
type EtcdProcess interface {
|
|
EndpointsV2() []string
|
|
EndpointsV3() []string
|
|
EndpointsMetrics() []string
|
|
|
|
Start() error
|
|
Restart() error
|
|
Stop() error
|
|
Close() error
|
|
WithStopSignal(sig os.Signal) os.Signal
|
|
Config() *EtcdServerProcessConfig
|
|
Logs() LogsExpect
|
|
}
|
|
|
|
type LogsExpect interface {
|
|
Expect(string) (string, error)
|
|
Lines() []string
|
|
LineCount() int
|
|
}
|
|
|
|
type EtcdServerProcess struct {
|
|
cfg *EtcdServerProcessConfig
|
|
proc *expect.ExpectProcess
|
|
donec chan struct{} // closed when Interact() terminates
|
|
}
|
|
|
|
type EtcdServerProcessConfig struct {
|
|
lg *zap.Logger
|
|
ExecPath string
|
|
Args []string
|
|
TlsArgs []string
|
|
EnvVars map[string]string
|
|
|
|
DataDirPath string
|
|
KeepDataDir bool
|
|
|
|
Name string
|
|
|
|
Purl url.URL
|
|
|
|
Acurl string
|
|
Murl string
|
|
|
|
InitialToken string
|
|
InitialCluster string
|
|
}
|
|
|
|
func NewEtcdServerProcess(cfg *EtcdServerProcessConfig) (*EtcdServerProcess, error) {
|
|
if !fileutil.Exist(cfg.ExecPath) {
|
|
return nil, fmt.Errorf("could not find etcd binary: %s", cfg.ExecPath)
|
|
}
|
|
if !cfg.KeepDataDir {
|
|
if err := os.RemoveAll(cfg.DataDirPath); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &EtcdServerProcess{cfg: cfg, donec: make(chan struct{})}, nil
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) EndpointsV2() []string { return []string{ep.cfg.Acurl} }
|
|
func (ep *EtcdServerProcess) EndpointsV3() []string { return ep.EndpointsV2() }
|
|
func (ep *EtcdServerProcess) EndpointsMetrics() []string { return []string{ep.cfg.Murl} }
|
|
|
|
func (ep *EtcdServerProcess) Start() error {
|
|
if ep.proc != nil {
|
|
panic("already started")
|
|
}
|
|
ep.cfg.lg.Info("starting server...", zap.String("name", ep.cfg.Name))
|
|
proc, err := SpawnCmdWithLogger(ep.cfg.lg, append([]string{ep.cfg.ExecPath}, ep.cfg.Args...), ep.cfg.EnvVars)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ep.proc = proc
|
|
err = ep.waitReady()
|
|
if err == nil {
|
|
ep.cfg.lg.Info("started server.", zap.String("name", ep.cfg.Name))
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) Restart() error {
|
|
ep.cfg.lg.Info("restaring server...", zap.String("name", ep.cfg.Name))
|
|
if err := ep.Stop(); err != nil {
|
|
return err
|
|
}
|
|
ep.donec = make(chan struct{})
|
|
err := ep.Start()
|
|
if err == nil {
|
|
ep.cfg.lg.Info("restared server", zap.String("name", ep.cfg.Name))
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) Stop() (err error) {
|
|
ep.cfg.lg.Info("stoping server...", zap.String("name", ep.cfg.Name))
|
|
if ep == nil || ep.proc == nil {
|
|
return nil
|
|
}
|
|
err = ep.proc.Stop()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ep.proc = nil
|
|
<-ep.donec
|
|
ep.donec = make(chan struct{})
|
|
if ep.cfg.Purl.Scheme == "unix" || ep.cfg.Purl.Scheme == "unixs" {
|
|
err = os.Remove(ep.cfg.Purl.Host + ep.cfg.Purl.Path)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
}
|
|
ep.cfg.lg.Info("stopped server.", zap.String("name", ep.cfg.Name))
|
|
return nil
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) Close() error {
|
|
ep.cfg.lg.Info("closing server...", zap.String("name", ep.cfg.Name))
|
|
if err := ep.Stop(); err != nil {
|
|
return err
|
|
}
|
|
if !ep.cfg.KeepDataDir {
|
|
ep.cfg.lg.Info("removing directory", zap.String("data-dir", ep.cfg.DataDirPath))
|
|
return os.RemoveAll(ep.cfg.DataDirPath)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) WithStopSignal(sig os.Signal) os.Signal {
|
|
ret := ep.proc.StopSignal
|
|
ep.proc.StopSignal = sig
|
|
return ret
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) waitReady() error {
|
|
defer close(ep.donec)
|
|
return WaitReadyExpectProc(ep.proc, EtcdServerReadyLines)
|
|
}
|
|
|
|
func (ep *EtcdServerProcess) Config() *EtcdServerProcessConfig { return ep.cfg }
|
|
|
|
func (ep *EtcdServerProcess) Logs() LogsExpect {
|
|
if ep.proc == nil {
|
|
ep.cfg.lg.Panic("Please grap logs before process is stopped")
|
|
}
|
|
return ep.proc
|
|
}
|