github.com/containerd/Containerd@v1.4.13/cmd/containerd-stress/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  	"sync"
    24  	"time"
    25  
    26  	"github.com/containerd/containerd"
    27  	"github.com/containerd/containerd/cio"
    28  	"github.com/containerd/containerd/oci"
    29  	"github.com/sirupsen/logrus"
    30  )
    31  
    32  type worker struct {
    33  	id       int
    34  	wg       *sync.WaitGroup
    35  	count    int
    36  	failures int
    37  
    38  	client *containerd.Client
    39  	image  containerd.Image
    40  	commit string
    41  }
    42  
    43  func (w *worker) run(ctx, tctx context.Context) {
    44  	defer func() {
    45  		w.wg.Done()
    46  		logrus.Infof("worker %d finished", w.id)
    47  	}()
    48  	for {
    49  		select {
    50  		case <-tctx.Done():
    51  			return
    52  		default:
    53  		}
    54  
    55  		w.count++
    56  		id := w.getID()
    57  		logrus.Debugf("starting container %s", id)
    58  		start := time.Now()
    59  		if err := w.runContainer(ctx, id); err != nil {
    60  			if err != context.DeadlineExceeded ||
    61  				!strings.Contains(err.Error(), context.DeadlineExceeded.Error()) {
    62  				w.failures++
    63  				logrus.WithError(err).Errorf("running container %s", id)
    64  				errCounter.WithValues(err.Error()).Inc()
    65  
    66  			}
    67  			continue
    68  		}
    69  		// only log times are success so we don't scew the results from failures that go really fast
    70  		ct.WithValues(w.commit).UpdateSince(start)
    71  	}
    72  }
    73  
    74  func (w *worker) runContainer(ctx context.Context, id string) (err error) {
    75  	// fix up cgroups path for a default config
    76  	c, err := w.client.NewContainer(ctx, id,
    77  		containerd.WithNewSnapshot(id, w.image),
    78  		containerd.WithNewSpec(oci.WithImageConfig(w.image), oci.WithUsername("games"), oci.WithProcessArgs("true")),
    79  	)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	defer func() {
    84  		if derr := c.Delete(ctx, containerd.WithSnapshotCleanup); err == nil {
    85  			err = derr
    86  		}
    87  	}()
    88  	task, err := c.NewTask(ctx, cio.NullIO)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	defer func() {
    93  		if _, derr := task.Delete(ctx, containerd.WithProcessKill); err == nil {
    94  			err = derr
    95  		}
    96  	}()
    97  	statusC, err := task.Wait(ctx)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if err := task.Start(ctx); err != nil {
   102  		return err
   103  	}
   104  	status := <-statusC
   105  	_, _, err = status.Result()
   106  	if err != nil {
   107  		if err == context.DeadlineExceeded || err == context.Canceled {
   108  			return nil
   109  		}
   110  		w.failures++
   111  		errCounter.WithValues(err.Error()).Inc()
   112  	}
   113  	return nil
   114  }
   115  
   116  func (w *worker) getID() string {
   117  	return fmt.Sprintf("%d-%d", w.id, w.count)
   118  }