Skip to content

support component-extension for openshift-tests #29909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions pkg/cmd/openshift-tests/images/images_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func NewImagesCommand() *cobra.Command {
if err := imagesetup.VerifyImages(); err != nil {
return err
}
lines, err := createImageMirrorForInternalImages(prefix, ref, !o.Upstream)
lines, err := createImageMirrorForInternalImages(prefix, ref, !o.Upstream, o.ComponentExtensions)
if err != nil {
return err
}
Expand All @@ -95,13 +95,15 @@ func NewImagesCommand() *cobra.Command {
// this is a private flag for debugging only
cmd.Flags().BoolVar(&o.Verify, "verify", o.Verify, "Verify the contents of the image mappings")
cmd.Flags().MarkHidden("verify")
cmd.Flags().Var(extensions.NewStringToMap(&o.ComponentExtensions), "component-extension", "Set extension which is used for the component as <component tag>=<component extension id> pairs (e.g. --component-extension=tag1:id1,tag2=id2 or --component-extension=tag1:id1 --component-extension=tag2=id2)")
return cmd
}

type imagesOptions struct {
Repository string
Upstream bool
Verify bool
Repository string
Upstream bool
Verify bool
ComponentExtensions map[string]string
}

// createImageMirrorForInternalImages returns a list of 'oc image mirror' mappings from source to
Expand All @@ -110,7 +112,7 @@ type imagesOptions struct {
// of the original internal name and the index of the image in the array. Otherwise the mappings will
// be set to mirror the location as defined in the test code into our official mirror, where the target
// TAG is the hash described above.
func createImageMirrorForInternalImages(prefix string, ref reference.DockerImageReference, mirrored bool) ([]string, error) {
func createImageMirrorForInternalImages(prefix string, ref reference.DockerImageReference, mirrored bool, compExts map[string]string) ([]string, error) {
source := ref.Exact()

initialImageSets := []extensions.ImageSet{
Expand All @@ -122,7 +124,7 @@ func createImageMirrorForInternalImages(prefix string, ref reference.DockerImage
// Extract all test binaries
extractionContext, extractionContextCancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer extractionContextCancel()
cleanUpFn, externalBinaries, err := extensions.ExtractAllTestBinaries(extractionContext, 10)
cleanUpFn, externalBinaries, err := extensions.ExtractAllTestBinaries(extractionContext, 10, compExts)
if err != nil {
return nil, err
}
Expand Down
21 changes: 19 additions & 2 deletions pkg/test/extensions/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ type TestBinary struct {
// The binary path to extract from the image
binaryPath string

// the extension from which the openshift-tests selects case of the external binary.
// if it is empty (do not set parameter "--component-extension"), the "default" extension is used.
// if you do not want "default" extension, need to set it with parmater "--component-extension"
extension string

// Cache the info after gathering it
info *ExtensionInfo
}
Expand Down Expand Up @@ -72,6 +77,9 @@ func (b *TestBinary) Info(ctx context.Context) (*ExtensionInfo, error) {

logrus.Infof("Fetching info for %s", binName)
command := exec.Command(b.binaryPath, "info")
if len(b.extension) != 0 {
command.Args = append(command.Args, fmt.Sprintf("--component=%s", b.extension))
}
infoJson, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s info': %w\nOutput: %s", b.binaryPath, err, infoJson)
Expand Down Expand Up @@ -108,6 +116,9 @@ func (b *TestBinary) ListTests(ctx context.Context, envFlags EnvironmentFlags) (
command := exec.Command(b.binaryPath, "list", "-o", "jsonl")
binLogger.Infof("Adding the following applicable flags to the list command: %s", envFlags.String())
command.Args = append(command.Args, envFlags.ArgStrings()...)
if len(b.extension) != 0 {
command.Args = append(command.Args, fmt.Sprintf("--component=%s", b.extension))
}
testList, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s list': %w\nOutput: %s", b.binaryPath, err, testList)
Expand Down Expand Up @@ -158,6 +169,9 @@ func (b *TestBinary) RunTests(ctx context.Context, timeout time.Duration, env []
}
args = append(args, "-o", "jsonl")
command := exec.Command(b.binaryPath, args...)
if len(b.extension) != 0 {
command.Args = append(command.Args, fmt.Sprintf("--component=%s", b.extension))
}
if len(env) == 0 {
env = os.Environ()
}
Expand Down Expand Up @@ -218,6 +232,9 @@ func (b *TestBinary) ListImages(ctx context.Context) (ImageSet, error) {

logrus.Infof("Listing images for %q", binName)
command := exec.Command(b.binaryPath, "images")
if len(b.extension) != 0 {
command.Args = append(command.Args, fmt.Sprintf("--component=%s", b.extension))
}
output, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s list': %w\nOutput: %s", b.binaryPath, err, output)
Expand All @@ -244,7 +261,7 @@ func (b *TestBinary) ListImages(ctx context.Context) (ImageSet, error) {

// 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, parallelism int) (func(), TestBinaries, error) {
func ExtractAllTestBinaries(ctx context.Context, parallelism int, compExts map[string]string) (func(), TestBinaries, error) {
if parallelism < 1 {
return nil, nil, errors.New("parallelism must be greater than zero")
}
Expand Down Expand Up @@ -352,7 +369,7 @@ func ExtractAllTestBinaries(ctx context.Context, parallelism int) (func(), TestB
if !ok {
return // Channel is closed
}
testBinary, err := externalBinaryProvider.ExtractBinaryFromReleaseImage(b.imageTag, b.binaryPath)
testBinary, err := externalBinaryProvider.ExtractBinaryFromReleaseImage(b.imageTag, b.binaryPath, compExts)
if err != nil {
errCh <- err
continue
Expand Down
10 changes: 9 additions & 1 deletion pkg/test/extensions/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,16 @@ func (provider *ExternalBinaryProvider) Cleanup() {
// Note: When developing openshift-tests on a non-Linux non-AMD64 computer (i.e. on Apple Silicon), external
// binaries won't work. You would need to run it in a Linux environment (VM or container), and even then
// override the payload selection with an aarch64 payload unless x86 emulation is enabled.
func (provider *ExternalBinaryProvider) ExtractBinaryFromReleaseImage(tag, binary string) (*TestBinary, error) {
func (provider *ExternalBinaryProvider) ExtractBinaryFromReleaseImage(tag, binary string, compExts map[string]string) (*TestBinary, error) {
if provider.binPath == "" {
return nil, fmt.Errorf("extraction path is not set, cleanup was already run")
}

var ext string
if val, ok := compExts[tag]; ok {
ext = val
}

// Allow overriding image path to an already existing local path, mostly useful
// for development.
if override := binaryPathOverride(tag, binary); override != "" {
Expand All @@ -109,6 +114,7 @@ func (provider *ExternalBinaryProvider) ExtractBinaryFromReleaseImage(tag, binar
return &TestBinary{
imageTag: tag,
binaryPath: override,
extension: ext,
}, nil
}

Expand All @@ -134,6 +140,7 @@ func (provider *ExternalBinaryProvider) ExtractBinaryFromReleaseImage(tag, binar
return &TestBinary{
imageTag: tag,
binaryPath: binPath,
extension: ext,
}, nil
}

Expand Down Expand Up @@ -184,6 +191,7 @@ func (provider *ExternalBinaryProvider) ExtractBinaryFromReleaseImage(tag, binar

return &TestBinary{
binaryPath: extractedBinary,
extension: ext,
}, nil
}

Expand Down
45 changes: 44 additions & 1 deletion pkg/test/extensions/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"debug/elf"
"encoding/json"
"fmt"
"github.com/sirupsen/logrus"
"io"
"os"
"os/exec"
Expand All @@ -18,6 +17,8 @@ import (
"strings"
"time"

"github.com/sirupsen/logrus"

imagev1 "github.com/openshift/api/image/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -260,3 +261,45 @@ func extractReleaseImageStream(extractPath, releaseImage string,

return is, releaseImage, nil
}

type StringToMap struct {
e *map[string]string
}

func NewStringToMap(p *map[string]string) *StringToMap {
if *p == nil {
*p = make(map[string]string)
}
return &StringToMap{e: p}
}

func (s2m *StringToMap) String() string {
var sb strings.Builder
first := true
for k, v := range *s2m.e {
if !first {
sb.WriteString(",")
}
sb.WriteString(fmt.Sprintf("%s=%s", k, v))
first = false
}
return sb.String()
}

func (s2m *StringToMap) Set(s string) error {
items := strings.Split(s, ",")
for _, item := range items {
kv := strings.SplitN(item, "=", 2)
if len(kv) != 2 {
return fmt.Errorf("invalid component-extenstion format, expected key=value: %q", item)
}
k := strings.TrimSpace(kv[0])
v := strings.TrimSpace(kv[1])
(*s2m.e)[k] = v
}
return nil
}

func (s *StringToMap) Type() string {
return "stringToMap"
}
5 changes: 4 additions & 1 deletion pkg/test/ginkgo/cmd_runsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ type GinkgoRunSuiteOptions struct {

IncludeSuccessOutput bool

ComponentExtensions map[string]string

CommandEnv []string

DryRun bool
Expand Down Expand Up @@ -118,6 +120,7 @@ func (o *GinkgoRunSuiteOptions) BindFlags(flags *pflag.FlagSet) {
flags.IntVar(&o.ShardID, "shard-id", o.ShardID, "When tests are sharded across instances, which instance we are")
flags.IntVar(&o.ShardCount, "shard-count", o.ShardCount, "Number of shards used to run tests across multiple instances")
flags.StringVar(&o.ShardStrategy, "shard-strategy", o.ShardStrategy, "Which strategy to use for sharding (hash)")
flags.Var(extensions.NewStringToMap(&o.ComponentExtensions), "component-extension", "Set extension which is used for the component as <component tag>=<component extension id> pairs (e.g. --component-extension=tag1:id1,tag2=id2 or --component-extension=tag1:id1 --component-extension=tag2=id2)")
}

func (o *GinkgoRunSuiteOptions) Validate() error {
Expand Down Expand Up @@ -170,7 +173,7 @@ func (o *GinkgoRunSuiteOptions) Run(suite *TestSuite, junitSuiteName string, mon
// Extract all test binaries
extractionContext, extractionContextCancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer extractionContextCancel()
cleanUpFn, externalBinaries, err := extensions.ExtractAllTestBinaries(extractionContext, 10)
cleanUpFn, externalBinaries, err := extensions.ExtractAllTestBinaries(extractionContext, 10, o.ComponentExtensions)
if err != nil {
return err
}
Expand Down