You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/02/21 10:54:45 UTC

[skywalking-infra-e2e] branch main updated: Automatically pull images before loading into KinD (#104)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git


The following commit(s) were added to refs/heads/main by this push:
     new c1558db  Automatically pull images before loading into KinD (#104)
c1558db is described below

commit c1558dba921a36320f9fdc3d774b66592243589d
Author: ethan256 <yu...@163.com>
AuthorDate: Tue Feb 21 18:54:39 2023 +0800

    Automatically pull images before loading into KinD (#104)
---
 internal/components/setup/kind.go | 91 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 2 deletions(-)

diff --git a/internal/components/setup/kind.go b/internal/components/setup/kind.go
index 4fe24a4..a7b7b92 100644
--- a/internal/components/setup/kind.go
+++ b/internal/components/setup/kind.go
@@ -22,13 +22,16 @@ import (
 	"bufio"
 	"bytes"
 	"context"
+	"errors"
 	"fmt"
+	"io"
 	"net/http"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	apiv1 "k8s.io/api/admission/v1"
@@ -45,6 +48,8 @@ import (
 	"k8s.io/kubectl/pkg/scheme"
 	ctlutil "k8s.io/kubectl/pkg/util"
 
+	"github.com/docker/docker/api/types"
+	docker "github.com/docker/docker/client"
 	kind "sigs.k8s.io/kind/cmd/kind/app"
 	kindcmd "sigs.k8s.io/kind/pkg/cmd"
 
@@ -73,8 +78,82 @@ type kindPort struct {
 	waitExpose string // Need to use when expose
 }
 
-//nolint:gocyclo // skip the cyclomatic complexity check here
+func listLocalImages(ctx context.Context, cli *docker.Client) (map[string]struct{}, error) {
+	summary, err := cli.ImageList(ctx, types.ImageListOptions{})
+	if err != nil {
+		return nil, err
+	}
+	res := make(map[string]struct{}, len(summary))
+	for i := 0; i < len(summary); i++ {
+		tags := summary[i].RepoTags
+		for j := 0; j < len(tags); j++ {
+			res[tags[j]] = struct{}{}
+		}
+	}
+	return res, nil
+}
+
+// pullImages pulls docker image from a docker repository
+func pullImages(ctx context.Context, images []string) error {
+	cli, err := docker.NewClientWithOpts(docker.FromEnv)
+	if err != nil {
+		return err
+	}
+	defer cli.Close()
+
+	localImages, err := listLocalImages(ctx, cli)
+	if err != nil {
+		return fmt.Errorf("list local images error: %w", err)
+	}
+
+	// filter local image
+	filter := func(tags []string) []string {
+		res := make([]string, 0)
+		for _, tag := range tags {
+			if _, ok := localImages[tag]; !ok {
+				res = append(res, tag)
+			}
+		}
+		return res
+	}
+
+	filterResult := filter(images)
+	if len(filterResult) == 0 {
+		return nil
+	}
+
+	var count int32
+	var wg sync.WaitGroup
+	for _, image := range filterResult {
+		wg.Add(1)
+		go func(image string) {
+			defer wg.Done()
+			logger.Log.Infof("image %s does not exist, will pull from remote", image)
+			out, err := cli.ImagePull(ctx, image, types.ImagePullOptions{})
+			if err != nil {
+				logger.Log.WithError(err).Errorf("failed pull image: %s", image)
+				return
+			}
+			defer out.Close()
+
+			if _, err := io.ReadAll(out); err != nil {
+				logger.Log.WithError(err).Errorf("failed pull image: %s", image)
+				return
+			}
+			atomic.AddInt32(&count, 1)
+			logger.Log.Infof("success pull image: %s", image)
+		}(image)
+	}
+	wg.Wait()
+	if int(count) != len(filterResult) {
+		return errors.New("can not pull all images")
+	}
+	return nil
+}
+
 // KindSetup sets up environment according to e2e.yaml.
+//
+//nolint:gocyclo // skip the cyclomatic complexity check here
 func KindSetup(e2eConfig *config.E2EConfig) error {
 	kindConfigPath = e2eConfig.Setup.GetFile()
 
@@ -117,8 +196,16 @@ func KindSetup(e2eConfig *config.E2EConfig) error {
 
 	// import images
 	if len(e2eConfig.Setup.Kind.ImportImages) > 0 {
+		images := make([]string, 0, len(e2eConfig.Setup.Kind.ImportImages))
 		for _, image := range e2eConfig.Setup.Kind.ImportImages {
-			image = os.ExpandEnv(image)
+			images = append(images, os.ExpandEnv(image))
+		}
+		// pull images if this image not exist
+		if err := pullImages(context.Background(), images); err != nil {
+			return err
+		}
+
+		for _, image := range images {
 			args := []string{"load", "docker-image", image}
 
 			logger.Log.Infof("import docker images: %s", image)