github.com/demonoid81/containerd@v1.3.4/cmd/containerd-stress/exec_worker.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 main
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"syscall"
    24  	"time"
    25  
    26  	"github.com/containerd/containerd"
    27  	"github.com/containerd/containerd/cio"
    28  	"github.com/containerd/containerd/oci"
    29  	specs "github.com/opencontainers/runtime-spec/specs-go"
    30  	"github.com/sirupsen/logrus"
    31  )
    32  
    33  type execWorker struct {
    34  	worker
    35  }
    36  
    37  func (w *execWorker) exec(ctx, tctx context.Context) {
    38  	defer func() {
    39  		w.wg.Done()
    40  		logrus.Infof("worker %d finished", w.id)
    41  	}()
    42  	id := fmt.Sprintf("exec-container-%d", w.id)
    43  	c, err := w.client.NewContainer(ctx, id,
    44  		containerd.WithNewSnapshot(id, w.image),
    45  		containerd.WithNewSpec(oci.WithImageConfig(w.image), oci.WithUsername("games"), oci.WithProcessArgs("sleep", "30d")),
    46  	)
    47  	if err != nil {
    48  		logrus.WithError(err).Error("create exec container")
    49  		return
    50  	}
    51  	defer c.Delete(ctx, containerd.WithSnapshotCleanup)
    52  
    53  	task, err := c.NewTask(ctx, cio.NullIO)
    54  	if err != nil {
    55  		logrus.WithError(err).Error("create exec container's task")
    56  		return
    57  	}
    58  	defer task.Delete(ctx, containerd.WithProcessKill)
    59  
    60  	statusC, err := task.Wait(ctx)
    61  	if err != nil {
    62  		logrus.WithError(err).Error("wait exec container's task")
    63  		return
    64  	}
    65  	spec, err := c.Spec(ctx)
    66  	if err != nil {
    67  		logrus.WithError(err).Error("failed to get spec")
    68  		return
    69  	}
    70  
    71  	pspec := spec.Process
    72  	pspec.Args = []string{"true"}
    73  
    74  	for {
    75  		select {
    76  		case <-tctx.Done():
    77  			if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
    78  				logrus.WithError(err).Error("kill exec container's task")
    79  			}
    80  			<-statusC
    81  			return
    82  		default:
    83  		}
    84  
    85  		w.count++
    86  		id := w.getID()
    87  		logrus.Debugf("starting exec %s", id)
    88  		start := time.Now()
    89  
    90  		if err := w.runExec(ctx, task, id, pspec); err != nil {
    91  			if err != context.DeadlineExceeded ||
    92  				!strings.Contains(err.Error(), context.DeadlineExceeded.Error()) {
    93  				w.failures++
    94  				logrus.WithError(err).Errorf("running exec %s", id)
    95  				errCounter.WithValues(err.Error()).Inc()
    96  			}
    97  			continue
    98  		}
    99  		// only log times are success so we don't scew the results from failures that go really fast
   100  		execTimer.WithValues(w.commit).UpdateSince(start)
   101  	}
   102  }
   103  
   104  func (w *execWorker) runExec(ctx context.Context, task containerd.Task, id string, spec *specs.Process) (err error) {
   105  	process, err := task.Exec(ctx, id, spec, cio.NullIO)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	defer func() {
   110  		if _, derr := process.Delete(ctx, containerd.WithProcessKill); err == nil {
   111  			err = derr
   112  		}
   113  	}()
   114  	statusC, err := process.Wait(ctx)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	if err := process.Start(ctx); err != nil {
   119  		return err
   120  	}
   121  	status := <-statusC
   122  	_, _, err = status.Result()
   123  	if err != nil {
   124  		if err == context.DeadlineExceeded || err == context.Canceled {
   125  			return nil
   126  		}
   127  		w.failures++
   128  		errCounter.WithValues(err.Error()).Inc()
   129  	}
   130  	return nil
   131  }