github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/daemon_test.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package containerd
    18  
    19  import (
    20  	"context"
    21  	"io"
    22  	"os/exec"
    23  	"sync"
    24  	"syscall"
    25  
    26  	"github.com/pkg/errors"
    27  )
    28  
    29  type daemon struct {
    30  	sync.Mutex
    31  	addr string
    32  	cmd  *exec.Cmd
    33  }
    34  
    35  func (d *daemon) start(name, address string, args []string, stdout, stderr io.Writer) error {
    36  	d.Lock()
    37  	defer d.Unlock()
    38  	if d.cmd != nil {
    39  		return errors.New("daemon is already running")
    40  	}
    41  	args = append(args, []string{"--address", address}...)
    42  	cmd := exec.Command(name, args...)
    43  	cmd.Stdout = stdout
    44  	cmd.Stderr = stderr
    45  	if err := cmd.Start(); err != nil {
    46  		cmd.Wait()
    47  		return errors.Wrap(err, "failed to start daemon")
    48  	}
    49  	d.addr = address
    50  	d.cmd = cmd
    51  	return nil
    52  }
    53  
    54  func (d *daemon) waitForStart(ctx context.Context) (*Client, error) {
    55  	var (
    56  		client  *Client
    57  		serving bool
    58  		err     error
    59  	)
    60  
    61  	client, err = New(d.addr)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	serving, err = client.IsServing(ctx)
    66  	if !serving {
    67  		client.Close()
    68  		if err == nil {
    69  			err = errors.New("connection was successful but service is not available")
    70  		}
    71  		return nil, err
    72  	}
    73  	return client, err
    74  }
    75  
    76  func (d *daemon) Stop() error {
    77  	d.Lock()
    78  	defer d.Unlock()
    79  	if d.cmd == nil {
    80  		return errors.New("daemon is not running")
    81  	}
    82  	return d.cmd.Process.Signal(syscall.SIGTERM)
    83  }
    84  
    85  func (d *daemon) Kill() error {
    86  	d.Lock()
    87  	defer d.Unlock()
    88  	if d.cmd == nil {
    89  		return errors.New("daemon is not running")
    90  	}
    91  	return d.cmd.Process.Kill()
    92  }
    93  
    94  func (d *daemon) Wait() error {
    95  	d.Lock()
    96  	defer d.Unlock()
    97  	if d.cmd == nil {
    98  		return errors.New("daemon is not running")
    99  	}
   100  	err := d.cmd.Wait()
   101  	d.cmd = nil
   102  	return err
   103  }
   104  
   105  func (d *daemon) Restart(stopCb func()) error {
   106  	d.Lock()
   107  	defer d.Unlock()
   108  	if d.cmd == nil {
   109  		return errors.New("daemon is not running")
   110  	}
   111  
   112  	var err error
   113  	if err = d.cmd.Process.Signal(syscall.SIGTERM); err != nil {
   114  		return errors.Wrap(err, "failed to signal daemon")
   115  	}
   116  
   117  	d.cmd.Wait()
   118  
   119  	if stopCb != nil {
   120  		stopCb()
   121  	}
   122  
   123  	cmd := exec.Command(d.cmd.Path, d.cmd.Args[1:]...)
   124  	cmd.Stdout = d.cmd.Stdout
   125  	cmd.Stderr = d.cmd.Stderr
   126  	if err := cmd.Start(); err != nil {
   127  		cmd.Wait()
   128  		return errors.Wrap(err, "failed to start new daemon instance")
   129  	}
   130  	d.cmd = cmd
   131  
   132  	return nil
   133  }