github.com/demonoid81/containerd@v1.3.4/runtime/v2/binary.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 v2
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"io"
    23  	"os"
    24  	gruntime "runtime"
    25  	"strings"
    26  
    27  	"github.com/containerd/containerd/events/exchange"
    28  	"github.com/containerd/containerd/log"
    29  	"github.com/containerd/containerd/runtime"
    30  	client "github.com/containerd/containerd/runtime/v2/shim"
    31  	"github.com/containerd/containerd/runtime/v2/task"
    32  	"github.com/containerd/ttrpc"
    33  	"github.com/gogo/protobuf/types"
    34  	"github.com/pkg/errors"
    35  	"github.com/sirupsen/logrus"
    36  )
    37  
    38  func shimBinary(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, containerdTTRPCAddress string, events *exchange.Exchange, rt *runtime.TaskList) *binary {
    39  	return &binary{
    40  		bundle:                 bundle,
    41  		runtime:                runtime,
    42  		containerdAddress:      containerdAddress,
    43  		containerdTTRPCAddress: containerdTTRPCAddress,
    44  		events:                 events,
    45  		rtTasks:                rt,
    46  	}
    47  }
    48  
    49  type binary struct {
    50  	runtime                string
    51  	containerdAddress      string
    52  	containerdTTRPCAddress string
    53  	bundle                 *Bundle
    54  	events                 *exchange.Exchange
    55  	rtTasks                *runtime.TaskList
    56  }
    57  
    58  func (b *binary) Start(ctx context.Context, opts *types.Any, onClose func()) (_ *shim, err error) {
    59  	args := []string{"-id", b.bundle.ID}
    60  	if logrus.GetLevel() == logrus.DebugLevel {
    61  		args = append(args, "-debug")
    62  	}
    63  	args = append(args, "start")
    64  
    65  	cmd, err := client.Command(
    66  		ctx,
    67  		b.runtime,
    68  		b.containerdAddress,
    69  		b.containerdTTRPCAddress,
    70  		b.bundle.Path,
    71  		opts,
    72  		args...,
    73  	)
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	f, err := openShimLog(ctx, b.bundle, client.AnonDialer)
    78  	if err != nil {
    79  		return nil, errors.Wrap(err, "open shim log pipe")
    80  	}
    81  	defer func() {
    82  		if err != nil {
    83  			f.Close()
    84  		}
    85  	}()
    86  	// open the log pipe and block until the writer is ready
    87  	// this helps with synchronization of the shim
    88  	// copy the shim's logs to containerd's output
    89  	go func() {
    90  		defer f.Close()
    91  		_, err := io.Copy(os.Stderr, f)
    92  		err = checkCopyShimLogError(ctx, err)
    93  		if err != nil {
    94  			log.G(ctx).WithError(err).Error("copy shim log")
    95  		}
    96  	}()
    97  	out, err := cmd.CombinedOutput()
    98  	if err != nil {
    99  		return nil, errors.Wrapf(err, "%s", out)
   100  	}
   101  	address := strings.TrimSpace(string(out))
   102  	conn, err := client.Connect(address, client.AnonDialer)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	client := ttrpc.NewClient(conn, ttrpc.WithOnClose(onClose))
   107  	return &shim{
   108  		bundle:  b.bundle,
   109  		client:  client,
   110  		task:    task.NewTaskClient(client),
   111  		events:  b.events,
   112  		rtTasks: b.rtTasks,
   113  	}, nil
   114  }
   115  
   116  func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) {
   117  	log.G(ctx).Info("cleaning up dead shim")
   118  
   119  	// Windows cannot delete the current working directory while an
   120  	// executable is in use with it. For the cleanup case we invoke with the
   121  	// default work dir and forward the bundle path on the cmdline.
   122  	var bundlePath string
   123  	if gruntime.GOOS != "windows" {
   124  		bundlePath = b.bundle.Path
   125  	}
   126  
   127  	cmd, err := client.Command(ctx,
   128  		b.runtime,
   129  		b.containerdAddress,
   130  		b.containerdTTRPCAddress,
   131  		bundlePath,
   132  		nil,
   133  		"-id", b.bundle.ID,
   134  		"-bundle", b.bundle.Path,
   135  		"delete")
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	var (
   140  		out  = bytes.NewBuffer(nil)
   141  		errb = bytes.NewBuffer(nil)
   142  	)
   143  	cmd.Stdout = out
   144  	cmd.Stderr = errb
   145  	if err := cmd.Run(); err != nil {
   146  		return nil, errors.Wrapf(err, "%s", errb.String())
   147  	}
   148  	s := errb.String()
   149  	if s != "" {
   150  		log.G(ctx).Warnf("cleanup warnings %s", s)
   151  	}
   152  	var response task.DeleteResponse
   153  	if err := response.Unmarshal(out.Bytes()); err != nil {
   154  		return nil, err
   155  	}
   156  	if err := b.bundle.Delete(); err != nil {
   157  		return nil, err
   158  	}
   159  	return &runtime.Exit{
   160  		Status:    response.ExitStatus,
   161  		Timestamp: response.ExitedAt,
   162  		Pid:       response.Pid,
   163  	}, nil
   164  }