Skip to content

Commit

Permalink
List images from external binary
Browse files Browse the repository at this point in the history
  • Loading branch information
bertinatto committed Jan 18, 2025
1 parent b573a5b commit 4394648
Showing 2 changed files with 117 additions and 0 deletions.
33 changes: 33 additions & 0 deletions pkg/cmd/openshift-tests/images/images_command.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package images

import (
"context"
"fmt"
"log"
"os"
"sort"
"strings"
"time"

k8simage "k8s.io/kubernetes/test/utils/image"

"github.com/openshift/library-go/pkg/image/reference"
"github.com/openshift/origin/pkg/clioptions/imagesetup"
"github.com/openshift/origin/pkg/cmd"
"github.com/openshift/origin/pkg/test/externalbinary"
"github.com/openshift/origin/test/extended/util/image"
"github.com/spf13/cobra"
"k8s.io/kube-openapi/pkg/util/sets"
@@ -151,7 +155,36 @@ type imagesOptions struct {
func createImageMirrorForInternalImages(prefix string, ref reference.DockerImageReference, mirrored bool) ([]string, error) {
source := ref.Exact()

// This is coming from the vendored directory
initialDefaults := k8simage.GetOriginalImageConfigs()

// If ENV is set, this should come from external binary
if len(os.Getenv("OPENSHIFT_SKIP_EXTERNAL_TESTS")) == 0 {
// Extract all test binaries
extractLogger := log.New(os.Stdout, "", log.LstdFlags|log.Lmicroseconds)
extractionContext, extractionContextCancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer extractionContextCancel()
cleanUpFn, externalBinaries, err := externalbinary.ExtractAllTestBinaries(extractionContext, extractLogger, 10)
if err != nil {
return nil, err
}
defer cleanUpFn()

// List test images from all available binaries and convert them to origin's testCase format
listContext, listContextCancel := context.WithTimeout(context.Background(), time.Minute)
defer listContextCancel()

imagesFromExternalBinaries, err := externalBinaries.ListImages(listContext, 10)
if err != nil {
return nil, err
}

if len(imagesFromExternalBinaries) > 0 {
// FIXME: only 1 for now
initialDefaults = imagesFromExternalBinaries[0]
}
}

exceptions := image.Exceptions.List()
defaults := map[k8simage.ImageID]k8simage.Config{}

84 changes: 84 additions & 0 deletions pkg/test/externalbinary/binary.go
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ import (
"github.com/pkg/errors"
kapierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8simage "k8s.io/kubernetes/test/utils/image"

"github.com/openshift/origin/test/extended/util"
)
@@ -80,6 +81,27 @@ func (b *TestBinary) ListTests(ctx context.Context) (ExtensionTestSpecs, error)
return tests, nil
}

func (b *TestBinary) ListImages(ctx context.Context) (map[k8simage.ImageID]k8simage.Config, error) {
start := time.Now()
binName := filepath.Base(b.path)

b.logger.Printf("Listing images for %q", binName)
command := exec.Command(b.path, "images")
output, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s list': %w", b.path, err)
}

images := make(map[k8simage.ImageID]k8simage.Config)
err = json.Unmarshal(output, &images)
if err != nil {
return nil, err
}

b.logger.Printf("Listed %d test images for %q in %v", len(images), binName, time.Since(start))
return images, nil
}

// ExtractAllTestBinaries determines the optimal release payload to use, and extracts all the external
// test binaries from it, and returns a slice of them.
func ExtractAllTestBinaries(ctx context.Context, logger *log.Logger, parallelism int) (func(), TestBinaries, error) {
@@ -223,6 +245,68 @@ func ExtractAllTestBinaries(ctx context.Context, logger *log.Logger, parallelism

type TestBinaries []*TestBinary

func (binaries TestBinaries) ListImages(ctx context.Context, parallelism int) ([]map[k8simage.ImageID]k8simage.Config, error) {
var (
allImages []map[k8simage.ImageID]k8simage.Config
mu sync.Mutex
wg sync.WaitGroup
errCh = make(chan error, len(binaries))
jobCh = make(chan *TestBinary)
)

// Producer: sends jobs to the jobCh channel
go func() {
defer close(jobCh)
for _, binary := range binaries {
select {
case <-ctx.Done():
return // Exit when context is cancelled
case jobCh <- binary:
}
}
}()

// Consumer workers: extract tests concurrently
for i := 0; i < parallelism; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return // Exit when context is cancelled
case binary, ok := <-jobCh:
if !ok {
return // Channel was closed
}
images, err := binary.ListImages(ctx)
if err != nil {
errCh <- err
}
mu.Lock()
allImages = append(allImages, images)
mu.Unlock()
}
}
}()
}

// Wait for all workers to finish
wg.Wait()
close(errCh)

// Check if any errors were reported
var errs []string
for err := range errCh {
errs = append(errs, err.Error())
}
if len(errs) > 0 {
return nil, fmt.Errorf("encountered errors while listing tests: %s", strings.Join(errs, ";"))
}

return allImages, nil
}

// ListTests extracts the tests from all TestBinaries using the specified parallelism.
func (binaries TestBinaries) ListTests(ctx context.Context, parallelism int) (ExtensionTestSpecs, error) {
var (

0 comments on commit 4394648

Please sign in to comment.