github.com/containerd/Containerd@v1.4.13/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 }