github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/functional/agent/handler.go (about)

     1  // Copyright 2018 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 agent
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"net/url"
    21  	"os"
    22  	"os/exec"
    23  	"path/filepath"
    24  	"syscall"
    25  	"time"
    26  
    27  	"github.com/lfch/etcd-io/client/pkg/v3/fileutil"
    28  	"github.com/lfch/etcd-io/pkg/v3/proxy"
    29  	"github.com/lfch/etcd-io/tests/v3/functional/rpcpb"
    30  
    31  	"go.uber.org/zap"
    32  )
    33  
    34  // return error for system errors (e.g. fail to create files)
    35  // return status error in response for wrong configuration/operation (e.g. start etcd twice)
    36  func (srv *Server) handleTesterRequest(req *rpcpb.Request) (resp *rpcpb.Response, err error) {
    37  	defer func() {
    38  		if err == nil && req != nil {
    39  			srv.last = req.Operation
    40  			srv.lg.Info("handler success", zap.String("operation", req.Operation.String()))
    41  		}
    42  	}()
    43  	if req != nil {
    44  		srv.Member = req.Member
    45  		srv.Tester = req.Tester
    46  	}
    47  
    48  	switch req.Operation {
    49  	case rpcpb.Operation_INITIAL_START_ETCD:
    50  		return srv.handle_INITIAL_START_ETCD(req)
    51  	case rpcpb.Operation_RESTART_ETCD:
    52  		return srv.handle_RESTART_ETCD(req)
    53  
    54  	case rpcpb.Operation_SIGTERM_ETCD:
    55  		return srv.handle_SIGTERM_ETCD()
    56  	case rpcpb.Operation_SIGQUIT_ETCD_AND_REMOVE_DATA:
    57  		return srv.handle_SIGQUIT_ETCD_AND_REMOVE_DATA()
    58  
    59  	case rpcpb.Operation_SAVE_SNAPSHOT:
    60  		return srv.handle_SAVE_SNAPSHOT()
    61  	case rpcpb.Operation_RESTORE_RESTART_FROM_SNAPSHOT:
    62  		return srv.handle_RESTORE_RESTART_FROM_SNAPSHOT(req)
    63  	case rpcpb.Operation_RESTART_FROM_SNAPSHOT:
    64  		return srv.handle_RESTART_FROM_SNAPSHOT(req)
    65  
    66  	case rpcpb.Operation_SIGQUIT_ETCD_AND_ARCHIVE_DATA:
    67  		return srv.handle_SIGQUIT_ETCD_AND_ARCHIVE_DATA()
    68  	case rpcpb.Operation_SIGQUIT_ETCD_AND_REMOVE_DATA_AND_STOP_AGENT:
    69  		return srv.handle_SIGQUIT_ETCD_AND_REMOVE_DATA_AND_STOP_AGENT()
    70  
    71  	case rpcpb.Operation_BLACKHOLE_PEER_PORT_TX_RX:
    72  		return srv.handle_BLACKHOLE_PEER_PORT_TX_RX(), nil
    73  	case rpcpb.Operation_UNBLACKHOLE_PEER_PORT_TX_RX:
    74  		return srv.handle_UNBLACKHOLE_PEER_PORT_TX_RX(), nil
    75  	case rpcpb.Operation_DELAY_PEER_PORT_TX_RX:
    76  		return srv.handle_DELAY_PEER_PORT_TX_RX(), nil
    77  	case rpcpb.Operation_UNDELAY_PEER_PORT_TX_RX:
    78  		return srv.handle_UNDELAY_PEER_PORT_TX_RX(), nil
    79  
    80  	default:
    81  		msg := fmt.Sprintf("operation not found (%v)", req.Operation)
    82  		return &rpcpb.Response{Success: false, Status: msg}, errors.New(msg)
    83  	}
    84  }
    85  
    86  // just archive the first file
    87  func (srv *Server) createEtcdLogFile() error {
    88  	var err error
    89  	if srv.etcdLogFile, err = os.Create(srv.Member.Etcd.LogOutputs[0]); err != nil {
    90  		return err
    91  	}
    92  	srv.lg.Info("created etcd log file", zap.String("path", srv.Member.Etcd.LogOutputs[0]))
    93  	return nil
    94  }
    95  
    96  func (srv *Server) createEtcd(fromSnapshot bool, failpoints string) error {
    97  	if !fileutil.Exist(srv.Member.EtcdExec) {
    98  		return fmt.Errorf("unknown etcd exec path %q does not exist", srv.Member.EtcdExec)
    99  	}
   100  
   101  	etcdPath, etcdFlags := srv.Member.EtcdExec, srv.Member.Etcd.Flags()
   102  	if fromSnapshot {
   103  		etcdFlags = srv.Member.EtcdOnSnapshotRestore.Flags()
   104  	}
   105  	u, _ := url.Parse(srv.Member.FailpointHTTPAddr)
   106  	srv.lg.Info(
   107  		"creating etcd command",
   108  		zap.String("etcd-exec", etcdPath),
   109  		zap.Strings("etcd-flags", etcdFlags),
   110  		zap.String("GOFAIL_FAILPOINTS", failpoints),
   111  		zap.String("failpoint-http-addr", srv.Member.FailpointHTTPAddr),
   112  		zap.String("failpoint-addr", u.Host),
   113  	)
   114  	srv.etcdCmd = exec.Command(etcdPath, etcdFlags...)
   115  	srv.etcdCmd.Env = []string{"GOFAIL_HTTP=" + u.Host}
   116  	if failpoints != "" {
   117  		srv.etcdCmd.Env = append(srv.etcdCmd.Env, "GOFAIL_FAILPOINTS="+failpoints)
   118  	}
   119  	srv.etcdCmd.Stdout = srv.etcdLogFile
   120  	srv.etcdCmd.Stderr = srv.etcdLogFile
   121  	return nil
   122  }
   123  
   124  // start but do not wait for it to complete
   125  func (srv *Server) runEtcd() error {
   126  	errc := make(chan error)
   127  	go func() {
   128  		time.Sleep(1 * time.Second)
   129  		// server advertise client/peer listener had to start first
   130  		// before setting up proxy listener
   131  		errc <- srv.startProxy()
   132  	}()
   133  
   134  	if srv.etcdCmd != nil {
   135  		srv.lg.Info(
   136  			"starting etcd command",
   137  			zap.String("command-path", srv.etcdCmd.Path),
   138  		)
   139  		err := srv.etcdCmd.Start()
   140  
   141  		srv.lg.Info(
   142  			"started etcd command",
   143  			zap.String("command-path", srv.etcdCmd.Path),
   144  			zap.Strings("command-args", srv.etcdCmd.Args),
   145  			zap.Strings("envs", srv.etcdCmd.Env),
   146  			zap.Error(err),
   147  		)
   148  		if err != nil {
   149  			return err
   150  		}
   151  
   152  		return <-errc
   153  	}
   154  
   155  	select {
   156  	case <-srv.etcdServer.Server.ReadyNotify():
   157  		srv.lg.Info("embedded etcd is ready")
   158  	case <-time.After(time.Minute):
   159  		srv.etcdServer.Close()
   160  		return fmt.Errorf("took too long to start %v", <-srv.etcdServer.Err())
   161  	}
   162  	return <-errc
   163  }
   164  
   165  // SIGQUIT to exit with stackstrace
   166  func (srv *Server) stopEtcd(sig os.Signal) error {
   167  	srv.stopProxy()
   168  
   169  	if srv.etcdCmd != nil {
   170  		srv.lg.Info(
   171  			"stopping etcd command",
   172  			zap.String("command-path", srv.etcdCmd.Path),
   173  			zap.String("signal", sig.String()),
   174  		)
   175  
   176  		if err := srv.etcdCmd.Process.Signal(sig); err != nil {
   177  			return err
   178  		}
   179  
   180  		errc := make(chan error)
   181  		go func() {
   182  			_, ew := srv.etcdCmd.Process.Wait()
   183  			errc <- ew
   184  			close(errc)
   185  		}()
   186  
   187  		select {
   188  		case <-time.After(5 * time.Second):
   189  			srv.etcdCmd.Process.Kill()
   190  		case e := <-errc:
   191  			return e
   192  		}
   193  
   194  		err := <-errc
   195  
   196  		srv.lg.Info(
   197  			"stopped etcd command",
   198  			zap.String("command-path", srv.etcdCmd.Path),
   199  			zap.String("signal", sig.String()),
   200  			zap.Error(err),
   201  		)
   202  		return err
   203  	}
   204  
   205  	srv.lg.Info("stopping embedded etcd")
   206  	srv.etcdServer.Server.HardStop()
   207  	srv.etcdServer.Close()
   208  	srv.lg.Info("stopped embedded etcd")
   209  	return nil
   210  }
   211  
   212  func (srv *Server) startProxy() error {
   213  	if srv.Member.EtcdClientProxy {
   214  		advertiseClientURL, advertiseClientURLPort, err := getURLAndPort(srv.Member.Etcd.AdvertiseClientURLs[0])
   215  		if err != nil {
   216  			return err
   217  		}
   218  		listenClientURL, _, err := getURLAndPort(srv.Member.Etcd.ListenClientURLs[0])
   219  		if err != nil {
   220  			return err
   221  		}
   222  
   223  		srv.lg.Info("Checking client target's connectivity", zap.String("target", listenClientURL.Host))
   224  		if err := checkTCPConnect(srv.lg, listenClientURL.Host); err != nil {
   225  			return fmt.Errorf("check client target failed, %w", err)
   226  		}
   227  
   228  		srv.lg.Info("starting proxy on client traffic", zap.String("url", advertiseClientURL.String()))
   229  		srv.advertiseClientPortToProxy[advertiseClientURLPort] = proxy.NewServer(proxy.ServerConfig{
   230  			Logger: srv.lg,
   231  			From:   *advertiseClientURL,
   232  			To:     *listenClientURL,
   233  		})
   234  		select {
   235  		case err = <-srv.advertiseClientPortToProxy[advertiseClientURLPort].Error():
   236  			srv.lg.Info("starting client proxy failed", zap.Error(err))
   237  			return err
   238  		case <-time.After(2 * time.Second):
   239  			srv.lg.Info("started proxy on client traffic", zap.String("url", advertiseClientURL.String()))
   240  		}
   241  	}
   242  
   243  	if srv.Member.EtcdPeerProxy {
   244  		advertisePeerURL, advertisePeerURLPort, err := getURLAndPort(srv.Member.Etcd.AdvertisePeerURLs[0])
   245  		if err != nil {
   246  			return err
   247  		}
   248  		listenPeerURL, _, err := getURLAndPort(srv.Member.Etcd.ListenPeerURLs[0])
   249  		if err != nil {
   250  			return err
   251  		}
   252  
   253  		srv.lg.Info("Checking peer target's connectivity", zap.String("target", listenPeerURL.Host))
   254  		if err := checkTCPConnect(srv.lg, listenPeerURL.Host); err != nil {
   255  			return fmt.Errorf("check peer target failed, %w", err)
   256  		}
   257  
   258  		srv.lg.Info("starting proxy on peer traffic", zap.String("url", advertisePeerURL.String()))
   259  		srv.advertisePeerPortToProxy[advertisePeerURLPort] = proxy.NewServer(proxy.ServerConfig{
   260  			Logger: srv.lg,
   261  			From:   *advertisePeerURL,
   262  			To:     *listenPeerURL,
   263  		})
   264  		select {
   265  		case err = <-srv.advertisePeerPortToProxy[advertisePeerURLPort].Error():
   266  			srv.lg.Info("starting peer proxy failed", zap.Error(err))
   267  			return err
   268  		case <-time.After(2 * time.Second):
   269  			srv.lg.Info("started proxy on peer traffic", zap.String("url", advertisePeerURL.String()))
   270  		}
   271  	}
   272  	return nil
   273  }
   274  
   275  func (srv *Server) stopProxy() {
   276  	if srv.Member.EtcdClientProxy && len(srv.advertiseClientPortToProxy) > 0 {
   277  		for port, px := range srv.advertiseClientPortToProxy {
   278  			if err := px.Close(); err != nil {
   279  				srv.lg.Warn("failed to close proxy", zap.Int("port", port))
   280  				continue
   281  			}
   282  			select {
   283  			case <-px.Done():
   284  				// enough time to release port
   285  				time.Sleep(time.Second)
   286  			case <-time.After(time.Second):
   287  			}
   288  			srv.lg.Info("closed proxy",
   289  				zap.Int("port", port),
   290  				zap.String("from", px.From()),
   291  				zap.String("to", px.To()),
   292  			)
   293  		}
   294  		srv.advertiseClientPortToProxy = make(map[int]proxy.Server)
   295  	}
   296  	if srv.Member.EtcdPeerProxy && len(srv.advertisePeerPortToProxy) > 0 {
   297  		for port, px := range srv.advertisePeerPortToProxy {
   298  			if err := px.Close(); err != nil {
   299  				srv.lg.Warn("failed to close proxy", zap.Int("port", port))
   300  				continue
   301  			}
   302  			select {
   303  			case <-px.Done():
   304  				// enough time to release port
   305  				time.Sleep(time.Second)
   306  			case <-time.After(time.Second):
   307  			}
   308  			srv.lg.Info("closed proxy",
   309  				zap.Int("port", port),
   310  				zap.String("from", px.From()),
   311  				zap.String("to", px.To()),
   312  			)
   313  		}
   314  		srv.advertisePeerPortToProxy = make(map[int]proxy.Server)
   315  	}
   316  }
   317  
   318  // if started with manual TLS, stores TLS assets
   319  // from tester/client to disk before starting etcd process
   320  func (srv *Server) saveTLSAssets() error {
   321  	const defaultFileMode os.FileMode = 0644
   322  
   323  	if err := safeDataToFile(srv.Member.PeerCertPath, []byte(srv.Member.PeerCertData), defaultFileMode); err != nil {
   324  		return err
   325  	}
   326  	if err := safeDataToFile(srv.Member.PeerKeyPath, []byte(srv.Member.PeerKeyData), defaultFileMode); err != nil {
   327  		return err
   328  	}
   329  	if err := safeDataToFile(srv.Member.PeerTrustedCAPath, []byte(srv.Member.PeerTrustedCAData), defaultFileMode); err != nil {
   330  		return err
   331  	}
   332  	if srv.Member.PeerCertPath != "" &&
   333  		srv.Member.PeerKeyPath != "" &&
   334  		srv.Member.PeerTrustedCAPath != "" {
   335  		srv.lg.Info(
   336  			"wrote",
   337  			zap.String("peer-cert", srv.Member.PeerCertPath),
   338  			zap.String("peer-key", srv.Member.PeerKeyPath),
   339  			zap.String("peer-trusted-ca", srv.Member.PeerTrustedCAPath),
   340  		)
   341  	}
   342  
   343  	if err := safeDataToFile(srv.Member.ClientCertPath, []byte(srv.Member.ClientCertData), defaultFileMode); err != nil {
   344  		return err
   345  	}
   346  	if err := safeDataToFile(srv.Member.ClientKeyPath, []byte(srv.Member.ClientKeyData), defaultFileMode); err != nil {
   347  		return err
   348  	}
   349  	if err := safeDataToFile(srv.Member.ClientTrustedCAPath, []byte(srv.Member.ClientTrustedCAData), defaultFileMode); err != nil {
   350  		return err
   351  	}
   352  	if srv.Member.ClientCertPath != "" &&
   353  		srv.Member.ClientKeyPath != "" &&
   354  		srv.Member.ClientTrustedCAPath != "" {
   355  		srv.lg.Info(
   356  			"wrote",
   357  			zap.String("client-cert", srv.Member.ClientCertPath),
   358  			zap.String("client-key", srv.Member.ClientKeyPath),
   359  			zap.String("client-trusted-ca", srv.Member.ClientTrustedCAPath),
   360  		)
   361  	}
   362  	return nil
   363  }
   364  
   365  func (srv *Server) loadAutoTLSAssets() error {
   366  	if srv.Member.Etcd.PeerAutoTLS {
   367  		// in case of slow disk
   368  		time.Sleep(time.Second)
   369  
   370  		fdir := filepath.Join(srv.Member.Etcd.DataDir, "fixtures", "peer")
   371  
   372  		srv.lg.Info(
   373  			"loading peer auto TLS assets",
   374  			zap.String("dir", fdir),
   375  			zap.String("endpoint", srv.EtcdClientEndpoint),
   376  		)
   377  		// load peer cert.pem
   378  		certPath := filepath.Join(fdir, "cert.pem")
   379  		certData, err := loadFileData(certPath)
   380  		if err != nil {
   381  			return err
   382  		}
   383  		srv.Member.PeerCertData = string(certData)
   384  		// load peer key.pem
   385  		keyPath := filepath.Join(fdir, "key.pem")
   386  		keyData, err := loadFileData(keyPath)
   387  		if err != nil {
   388  			return err
   389  		}
   390  		srv.Member.PeerKeyData = string(keyData)
   391  
   392  		srv.lg.Info(
   393  			"loaded peer auto TLS assets",
   394  			zap.String("peer-cert-path", certPath),
   395  			zap.Int("peer-cert-length", len(certData)),
   396  			zap.String("peer-key-path", keyPath),
   397  			zap.Int("peer-key-length", len(keyData)),
   398  		)
   399  	}
   400  
   401  	if srv.Member.Etcd.ClientAutoTLS {
   402  		// in case of slow disk
   403  		time.Sleep(time.Second)
   404  
   405  		fdir := filepath.Join(srv.Member.Etcd.DataDir, "fixtures", "client")
   406  
   407  		srv.lg.Info(
   408  			"loading client TLS assets",
   409  			zap.String("dir", fdir),
   410  			zap.String("endpoint", srv.EtcdClientEndpoint),
   411  		)
   412  		// load client cert.pem
   413  		certPath := filepath.Join(fdir, "cert.pem")
   414  		certData, err := loadFileData(certPath)
   415  		if err != nil {
   416  			return err
   417  		}
   418  		srv.Member.ClientCertData = string(certData)
   419  		// load client key.pem
   420  		keyPath := filepath.Join(fdir, "key.pem")
   421  		keyData, err := loadFileData(keyPath)
   422  		if err != nil {
   423  			return err
   424  		}
   425  		srv.Member.ClientKeyData = string(keyData)
   426  
   427  		srv.lg.Info(
   428  			"loaded client TLS assets",
   429  			zap.String("client-cert-path", certPath),
   430  			zap.Int("client-cert-length", len(certData)),
   431  			zap.String("client-key-path", keyPath),
   432  			zap.Int("client-key-length", len(keyData)),
   433  		)
   434  	}
   435  
   436  	return nil
   437  }
   438  
   439  func (srv *Server) handle_INITIAL_START_ETCD(req *rpcpb.Request) (*rpcpb.Response, error) {
   440  	if srv.last != rpcpb.Operation_NOT_STARTED {
   441  		return &rpcpb.Response{
   442  			Success: false,
   443  			Status:  fmt.Sprintf("%q is not valid; last server operation was %q", rpcpb.Operation_INITIAL_START_ETCD.String(), srv.last.String()),
   444  			Member:  req.Member,
   445  		}, nil
   446  	}
   447  
   448  	if err := fileutil.TouchDirAll(srv.lg, srv.Member.BaseDir); err != nil {
   449  		return nil, err
   450  	}
   451  	srv.lg.Info("created base directory", zap.String("path", srv.Member.BaseDir))
   452  
   453  	if srv.etcdServer == nil {
   454  		if err := srv.createEtcdLogFile(); err != nil {
   455  			return nil, err
   456  		}
   457  	}
   458  
   459  	if err := srv.saveTLSAssets(); err != nil {
   460  		return nil, err
   461  	}
   462  	if err := srv.createEtcd(false, req.Member.Failpoints); err != nil {
   463  		return nil, err
   464  	}
   465  	if err := srv.runEtcd(); err != nil {
   466  		return nil, err
   467  	}
   468  	if err := srv.loadAutoTLSAssets(); err != nil {
   469  		return nil, err
   470  	}
   471  
   472  	return &rpcpb.Response{
   473  		Success: true,
   474  		Status:  "start etcd PASS",
   475  		Member:  srv.Member,
   476  	}, nil
   477  }
   478  
   479  func (srv *Server) handle_RESTART_ETCD(req *rpcpb.Request) (*rpcpb.Response, error) {
   480  	var err error
   481  	if !fileutil.Exist(srv.Member.BaseDir) {
   482  		if err = fileutil.TouchDirAll(srv.lg, srv.Member.BaseDir); err != nil {
   483  			return nil, err
   484  		}
   485  	}
   486  
   487  	if err = srv.saveTLSAssets(); err != nil {
   488  		return nil, err
   489  	}
   490  	if err = srv.createEtcd(false, req.Member.Failpoints); err != nil {
   491  		return nil, err
   492  	}
   493  	if err = srv.runEtcd(); err != nil {
   494  		return nil, err
   495  	}
   496  	if err = srv.loadAutoTLSAssets(); err != nil {
   497  		return nil, err
   498  	}
   499  
   500  	return &rpcpb.Response{
   501  		Success: true,
   502  		Status:  "restart etcd PASS",
   503  		Member:  srv.Member,
   504  	}, nil
   505  }
   506  
   507  func (srv *Server) handle_SIGTERM_ETCD() (*rpcpb.Response, error) {
   508  	if err := srv.stopEtcd(syscall.SIGTERM); err != nil {
   509  		return nil, err
   510  	}
   511  
   512  	if srv.etcdServer != nil {
   513  		srv.etcdServer.GetLogger().Sync()
   514  	} else {
   515  		srv.etcdLogFile.Sync()
   516  	}
   517  
   518  	return &rpcpb.Response{
   519  		Success: true,
   520  		Status:  "killed etcd",
   521  	}, nil
   522  }
   523  
   524  func (srv *Server) handle_SIGQUIT_ETCD_AND_REMOVE_DATA() (*rpcpb.Response, error) {
   525  	if err := srv.stopEtcd(syscall.SIGQUIT); err != nil {
   526  		return nil, err
   527  	}
   528  
   529  	if srv.etcdServer != nil {
   530  		srv.etcdServer.GetLogger().Sync()
   531  	} else {
   532  		srv.etcdLogFile.Sync()
   533  		srv.etcdLogFile.Close()
   534  	}
   535  
   536  	// for debugging purposes, rename instead of removing
   537  	if err := os.RemoveAll(srv.Member.BaseDir + ".backup"); err != nil {
   538  		return nil, err
   539  	}
   540  	if err := os.Rename(srv.Member.BaseDir, srv.Member.BaseDir+".backup"); err != nil {
   541  		return nil, err
   542  	}
   543  	srv.lg.Info(
   544  		"renamed",
   545  		zap.String("base-dir", srv.Member.BaseDir),
   546  		zap.String("new-dir", srv.Member.BaseDir+".backup"),
   547  	)
   548  
   549  	// create a new log file for next new member restart
   550  	if !fileutil.Exist(srv.Member.BaseDir) {
   551  		if err := fileutil.TouchDirAll(srv.lg, srv.Member.BaseDir); err != nil {
   552  			return nil, err
   553  		}
   554  	}
   555  
   556  	return &rpcpb.Response{
   557  		Success: true,
   558  		Status:  "killed etcd and removed base directory",
   559  	}, nil
   560  }
   561  
   562  func (srv *Server) handle_SAVE_SNAPSHOT() (*rpcpb.Response, error) {
   563  	if err := srv.Member.SaveSnapshot(srv.lg); err != nil {
   564  		return nil, err
   565  	}
   566  	return &rpcpb.Response{
   567  		Success:      true,
   568  		Status:       "saved snapshot",
   569  		SnapshotInfo: srv.Member.SnapshotInfo,
   570  	}, nil
   571  }
   572  
   573  func (srv *Server) handle_RESTORE_RESTART_FROM_SNAPSHOT(req *rpcpb.Request) (resp *rpcpb.Response, err error) {
   574  	if err = srv.Member.RestoreSnapshot(srv.lg); err != nil {
   575  		return nil, err
   576  	}
   577  	resp, err = srv.handle_RESTART_FROM_SNAPSHOT(req)
   578  	if resp != nil && err == nil {
   579  		resp.Status = "restored snapshot and " + resp.Status
   580  	}
   581  	return resp, err
   582  }
   583  
   584  func (srv *Server) handle_RESTART_FROM_SNAPSHOT(req *rpcpb.Request) (resp *rpcpb.Response, err error) {
   585  	if err = srv.saveTLSAssets(); err != nil {
   586  		return nil, err
   587  	}
   588  	if err = srv.createEtcd(true, req.Member.Failpoints); err != nil {
   589  		return nil, err
   590  	}
   591  	if err = srv.runEtcd(); err != nil {
   592  		return nil, err
   593  	}
   594  	if err = srv.loadAutoTLSAssets(); err != nil {
   595  		return nil, err
   596  	}
   597  
   598  	return &rpcpb.Response{
   599  		Success:      true,
   600  		Status:       "restarted etcd from snapshot",
   601  		SnapshotInfo: srv.Member.SnapshotInfo,
   602  	}, nil
   603  }
   604  
   605  func (srv *Server) handle_SIGQUIT_ETCD_AND_ARCHIVE_DATA() (*rpcpb.Response, error) {
   606  	if err := srv.stopEtcd(syscall.SIGQUIT); err != nil {
   607  		return nil, err
   608  	}
   609  
   610  	if srv.etcdServer != nil {
   611  		srv.etcdServer.GetLogger().Sync()
   612  	} else {
   613  		srv.etcdLogFile.Sync()
   614  		srv.etcdLogFile.Close()
   615  	}
   616  
   617  	// TODO: support separate WAL directory
   618  	if err := archive(srv.lg, srv.Member.BaseDir, srv.Member.Etcd.LogOutputs[0], srv.Member.Etcd.DataDir); err != nil {
   619  		return nil, err
   620  	}
   621  	srv.lg.Info("archived data", zap.String("base-dir", srv.Member.BaseDir))
   622  
   623  	if srv.etcdServer == nil {
   624  		if err := srv.createEtcdLogFile(); err != nil {
   625  			return nil, err
   626  		}
   627  	}
   628  
   629  	// TODO: Verify whether this cleaning of 'cache pages' is needed.
   630  	srv.lg.Info("cleaning up page cache")
   631  	if err := cleanPageCache(); err != nil {
   632  		srv.lg.Warn("failed to clean up page cache", zap.String("error", err.Error()))
   633  	}
   634  	srv.lg.Info("cleaned up page cache")
   635  
   636  	return &rpcpb.Response{
   637  		Success: true,
   638  		Status:  "cleaned up etcd",
   639  	}, nil
   640  }
   641  
   642  // stop proxy, etcd, delete data directory
   643  func (srv *Server) handle_SIGQUIT_ETCD_AND_REMOVE_DATA_AND_STOP_AGENT() (*rpcpb.Response, error) {
   644  	if err := srv.stopEtcd(syscall.SIGQUIT); err != nil {
   645  		return nil, err
   646  	}
   647  
   648  	if srv.etcdServer != nil {
   649  		srv.etcdServer.GetLogger().Sync()
   650  	} else {
   651  		srv.etcdLogFile.Sync()
   652  		srv.etcdLogFile.Close()
   653  	}
   654  
   655  	if err := os.RemoveAll(srv.Member.BaseDir); err != nil {
   656  		return nil, err
   657  	}
   658  	srv.lg.Info("removed base directory", zap.String("dir", srv.Member.BaseDir))
   659  
   660  	// stop agent server
   661  	srv.Stop()
   662  
   663  	return &rpcpb.Response{
   664  		Success: true,
   665  		Status:  "destroyed etcd and agent",
   666  	}, nil
   667  }
   668  
   669  func (srv *Server) handle_BLACKHOLE_PEER_PORT_TX_RX() *rpcpb.Response {
   670  	for port, px := range srv.advertisePeerPortToProxy {
   671  		srv.lg.Info("blackholing", zap.Int("peer-port", port))
   672  		px.BlackholeTx()
   673  		px.BlackholeRx()
   674  		srv.lg.Info("blackholed", zap.Int("peer-port", port))
   675  	}
   676  	return &rpcpb.Response{
   677  		Success: true,
   678  		Status:  "blackholed peer port tx/rx",
   679  	}
   680  }
   681  
   682  func (srv *Server) handle_UNBLACKHOLE_PEER_PORT_TX_RX() *rpcpb.Response {
   683  	for port, px := range srv.advertisePeerPortToProxy {
   684  		srv.lg.Info("unblackholing", zap.Int("peer-port", port))
   685  		px.UnblackholeTx()
   686  		px.UnblackholeRx()
   687  		srv.lg.Info("unblackholed", zap.Int("peer-port", port))
   688  	}
   689  	return &rpcpb.Response{
   690  		Success: true,
   691  		Status:  "unblackholed peer port tx/rx",
   692  	}
   693  }
   694  
   695  func (srv *Server) handle_DELAY_PEER_PORT_TX_RX() *rpcpb.Response {
   696  	lat := time.Duration(srv.Tester.UpdatedDelayLatencyMs) * time.Millisecond
   697  	rv := time.Duration(srv.Tester.DelayLatencyMsRv) * time.Millisecond
   698  
   699  	for port, px := range srv.advertisePeerPortToProxy {
   700  		srv.lg.Info("delaying",
   701  			zap.Int("peer-port", port),
   702  			zap.Duration("latency", lat),
   703  			zap.Duration("random-variable", rv),
   704  		)
   705  		px.DelayTx(lat, rv)
   706  		px.DelayRx(lat, rv)
   707  		srv.lg.Info("delayed",
   708  			zap.Int("peer-port", port),
   709  			zap.Duration("latency", lat),
   710  			zap.Duration("random-variable", rv),
   711  		)
   712  	}
   713  
   714  	return &rpcpb.Response{
   715  		Success: true,
   716  		Status:  "delayed peer port tx/rx",
   717  	}
   718  }
   719  
   720  func (srv *Server) handle_UNDELAY_PEER_PORT_TX_RX() *rpcpb.Response {
   721  	for port, px := range srv.advertisePeerPortToProxy {
   722  		srv.lg.Info("undelaying", zap.Int("peer-port", port))
   723  		px.UndelayTx()
   724  		px.UndelayRx()
   725  		srv.lg.Info("undelayed", zap.Int("peer-port", port))
   726  	}
   727  	return &rpcpb.Response{
   728  		Success: true,
   729  		Status:  "undelayed peer port tx/rx",
   730  	}
   731  }