go.etcd.io/etcd@v3.3.27+incompatible/tests/e2e/etcd_process.go (about)

     1  // Copyright 2017 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package e2e
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    20  	"os"
    21  
    22  	"github.com/coreos/etcd/pkg/expect"
    23  	"github.com/coreos/etcd/pkg/fileutil"
    24  )
    25  
    26  var (
    27  	etcdServerReadyLines = []string{"enabled capabilities for version", "published"}
    28  	binPath              string
    29  	ctlBinPath           string
    30  )
    31  
    32  // etcdProcess is a process that serves etcd requests.
    33  type etcdProcess interface {
    34  	EndpointsV2() []string
    35  	EndpointsV3() []string
    36  	EndpointsMetrics() []string
    37  
    38  	Start() error
    39  	Restart() error
    40  	Stop() error
    41  	Close() error
    42  	WithStopSignal(sig os.Signal) os.Signal
    43  	Config() *etcdServerProcessConfig
    44  }
    45  
    46  type etcdServerProcess struct {
    47  	cfg   *etcdServerProcessConfig
    48  	proc  *expect.ExpectProcess
    49  	donec chan struct{} // closed when Interact() terminates
    50  }
    51  
    52  type etcdServerProcessConfig struct {
    53  	execPath string
    54  	args     []string
    55  	tlsArgs  []string
    56  
    57  	dataDirPath string
    58  	keepDataDir bool
    59  
    60  	name string
    61  
    62  	purl url.URL
    63  
    64  	acurl string
    65  	murl  string
    66  
    67  	initialToken   string
    68  	initialCluster string
    69  }
    70  
    71  func newEtcdServerProcess(cfg *etcdServerProcessConfig) (*etcdServerProcess, error) {
    72  	if !fileutil.Exist(cfg.execPath) {
    73  		return nil, fmt.Errorf("could not find etcd binary")
    74  	}
    75  	if !cfg.keepDataDir {
    76  		if err := os.RemoveAll(cfg.dataDirPath); err != nil {
    77  			return nil, err
    78  		}
    79  	}
    80  	return &etcdServerProcess{cfg: cfg, donec: make(chan struct{})}, nil
    81  }
    82  
    83  func (ep *etcdServerProcess) EndpointsV2() []string      { return []string{ep.cfg.acurl} }
    84  func (ep *etcdServerProcess) EndpointsV3() []string      { return ep.EndpointsV2() }
    85  func (ep *etcdServerProcess) EndpointsMetrics() []string { return []string{ep.cfg.murl} }
    86  
    87  func (ep *etcdServerProcess) Start() error {
    88  	if ep.proc != nil {
    89  		panic("already started")
    90  	}
    91  	proc, err := spawnCmd(append([]string{ep.cfg.execPath}, ep.cfg.args...))
    92  	if err != nil {
    93  		return err
    94  	}
    95  	ep.proc = proc
    96  	return ep.waitReady()
    97  }
    98  
    99  func (ep *etcdServerProcess) Restart() error {
   100  	if err := ep.Stop(); err != nil {
   101  		return err
   102  	}
   103  	ep.donec = make(chan struct{})
   104  	return ep.Start()
   105  }
   106  
   107  func (ep *etcdServerProcess) Stop() (err error) {
   108  	if ep == nil || ep.proc == nil {
   109  		return nil
   110  	}
   111  	err = ep.proc.Stop()
   112  	if err != nil {
   113  		return err
   114  	}
   115  	ep.proc = nil
   116  	<-ep.donec
   117  	ep.donec = make(chan struct{})
   118  	if ep.cfg.purl.Scheme == "unix" || ep.cfg.purl.Scheme == "unixs" {
   119  		err = os.Remove(ep.cfg.purl.Host + ep.cfg.purl.Path)
   120  		if err != nil {
   121  			return err
   122  		}
   123  	}
   124  	return nil
   125  }
   126  
   127  func (ep *etcdServerProcess) Close() error {
   128  	if err := ep.Stop(); err != nil {
   129  		return err
   130  	}
   131  	return os.RemoveAll(ep.cfg.dataDirPath)
   132  }
   133  
   134  func (ep *etcdServerProcess) WithStopSignal(sig os.Signal) os.Signal {
   135  	ret := ep.proc.StopSignal
   136  	ep.proc.StopSignal = sig
   137  	return ret
   138  }
   139  
   140  func (ep *etcdServerProcess) waitReady() error {
   141  	defer close(ep.donec)
   142  	return waitReadyExpectProc(ep.proc, etcdServerReadyLines)
   143  }
   144  
   145  func (ep *etcdServerProcess) Config() *etcdServerProcessConfig { return ep.cfg }