Skip to content

Commit 01212f3

Browse files
committed
Allow only including / excluding specific extension images
When developing on my Mac, I point origin at locally-built binaries so I can run it directly locally. Now that we have many extension binaries, I would have to override each one to make it work as the payload-extracted images are all Linux executables. This adds environment variables for only specifically including or excluding particular image tags, making it easier to iterate on just one extension. Also migrates docs to the `docs` folder.
1 parent ee7b5a8 commit 01212f3

File tree

3 files changed

+244
-17
lines changed

3 files changed

+244
-17
lines changed
Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
1-
# External Binaries
1+
# OpenShift Test Extensions
22

3-
This package includes the code used for working with external test binaries.
4-
It's intended to house the implementation of the openshift-tests side of the
5-
[openshift-tests extension interface](https://github.com/openshift/enhancements/pull/1676), which is only
6-
partially implemented here for the moment.
3+
`openshift-tests` can be extended using the [openshift-tests extension
4+
interface](https://github.com/openshift/enhancements/pull/1676).
75

8-
There is a registry defined in binary.go, that lists the release image tag, and
9-
path to each external test binary. These binaries should implement the OTE
10-
interface defined in the enhancement, and implemented by the vendorable
11-
[openshift-tests-extension](https://github.com/openshift-eng/openshift-tests-extension).
6+
There is a registry of binaries defined in
7+
`pkg/test/extensions/binary.go`, that lists the release image tag, and
8+
path to each external test binary. These binaries should implement the
9+
OTE interface defined in the enhancement, and implemented by the
10+
vendorable [openshift-tests-extension](https://github.com/openshift-eng/openshift-tests-extension)
11+
framework.
1212

13-
## Requirements
13+
## Local Development
1414

1515
If the architecture of your local system where `openshift-tests` will run
1616
differs from the cluster under test, you should override the release payload
1717
with a payload of the architecture of your own system, as it is where the
18-
binaries will execute. Note, your OS must still be Linux. That means on Apple
19-
Silicon, you'll still need to run this in a Linux environment, such as a
20-
virtual machine, or x86 podman container.
18+
binaries will execute. Note, your OS must still be Linux to run any extracted images
19+
from the payload.
2120

22-
## Overrides
21+
Alternatively, you can point origin to locally-built binaries. An
22+
example workflow for Mac would be to override both the payload and
23+
specific image binaries:
24+
25+
```
26+
export EXTENSIONS_PAYLOAD_OVERRIDE=registry.ci.openshift.org/ocp-arm64/release-arm64:4.18.0-0.nightly-arm64-2024-11-15-135718
27+
export EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS=tests,hyperkube
28+
export EXTENSION_BINARY_OVERRIDE_HYPERKUBE=$HOME/go/src/github.com/kubernetes/kubernetes/_output/bin/k8s-tests-ext"
29+
```
30+
31+
## Environment Variables
2332

2433
A number of environment variables for overriding the behavior of external
2534
binaries are available, but in general this should "just work". A complex set
@@ -28,7 +37,19 @@ credentials to use are found in this code, and extensively documented in code
2837
comments. The following environment variables are available to force certain
2938
behaviors:
3039

31-
### Extension Binary
40+
### Extension Binary Filtering
41+
42+
Filter which extension binaries are extracted by image tag:
43+
44+
```bash
45+
# Exclude specific extensions
46+
export EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS="hyperkube,machine-api-operator"
47+
48+
# Include only specific extensions
49+
export EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS="tests,hyperkube"
50+
```
51+
52+
### Extension Binary Override
3253

3354
When developing locally, you may want to use a locally built extension
3455
binary. You can override the binary from the registry by setting:

pkg/test/extensions/binary.go

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ func ExtractAllTestBinaries(ctx context.Context, parallelism int) (func(), TestB
414414
return nil, nil, errors.New("parallelism must be greater than zero")
415415
}
416416

417+
// Filter extension binaries based on environment variables
418+
filteredBinaries := filterExtensionBinariesByTags(extensionBinaries)
419+
417420
releaseImage, err := DetermineReleasePayloadImage()
418421
if err != nil {
419422
return nil, nil, errors.WithMessage(err, "couldn't determine release image")
@@ -441,14 +444,14 @@ func ExtractAllTestBinaries(ctx context.Context, parallelism int) (func(), TestB
441444
binaries []*TestBinary
442445
mu sync.Mutex
443446
wg sync.WaitGroup
444-
errCh = make(chan error, len(extensionBinaries))
447+
errCh = make(chan error, len(filteredBinaries))
445448
jobCh = make(chan TestBinary)
446449
)
447450

448451
// Producer: sends jobs to the jobCh channel
449452
go func() {
450453
defer close(jobCh)
451-
for _, b := range extensionBinaries {
454+
for _, b := range filteredBinaries {
452455
select {
453456
case <-ctx.Done():
454457
return // Exit if context is cancelled
@@ -747,6 +750,77 @@ func safeComponentPath(c *extension.Component) string {
747750
)
748751
}
749752

753+
// filterExtensionBinariesByTags filters the extension binaries based on environment variables:
754+
// - EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS: comma-separated list of image tags to exclude
755+
// - EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS: comma-separated list of image tags to include (use only these)
756+
func filterExtensionBinariesByTags(binaries []TestBinary) []TestBinary {
757+
excludeTags := os.Getenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS")
758+
includeTags := os.Getenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS")
759+
760+
// If neither environment variable is set, return all binaries
761+
if excludeTags == "" && includeTags == "" {
762+
return binaries
763+
}
764+
765+
var filtered []TestBinary
766+
767+
// Parse exclude tags
768+
var excludeSet sets.Set[string]
769+
if excludeTags != "" {
770+
excludeList := strings.Split(excludeTags, ",")
771+
excludeSet = sets.New[string]()
772+
for _, tag := range excludeList {
773+
tag = strings.TrimSpace(tag)
774+
if tag != "" {
775+
excludeSet.Insert(tag)
776+
}
777+
}
778+
logrus.Infof("Excluding extension binaries with image tags: %v", excludeSet.UnsortedList())
779+
}
780+
781+
// Parse include tags
782+
var includeSet sets.Set[string]
783+
if includeTags != "" {
784+
includeList := strings.Split(includeTags, ",")
785+
includeSet = sets.New[string]()
786+
for _, tag := range includeList {
787+
tag = strings.TrimSpace(tag)
788+
if tag != "" {
789+
includeSet.Insert(tag)
790+
}
791+
}
792+
logrus.Infof("Including only extension binaries with image tags: %v", includeSet.UnsortedList())
793+
}
794+
795+
// Filter binaries
796+
for _, binary := range binaries {
797+
imageTag := binary.imageTag
798+
799+
// If include tags are specified, only include binaries with those tags
800+
if includeSet != nil {
801+
if includeSet.Has(imageTag) {
802+
filtered = append(filtered, binary)
803+
logrus.Infof("Including extension binary with image tag: %s", imageTag)
804+
} else {
805+
logrus.Infof("Excluding extension binary with image tag: %s (not in include list)", imageTag)
806+
}
807+
continue
808+
}
809+
810+
// If exclude tags are specified, exclude binaries with those tags
811+
if excludeSet != nil && excludeSet.Has(imageTag) {
812+
logrus.Infof("Excluding extension binary with image tag: %s", imageTag)
813+
continue
814+
}
815+
816+
// Include the binary
817+
filtered = append(filtered, binary)
818+
}
819+
820+
logrus.Infof("Filtered extension binaries: %d out of %d binaries will be processed", len(filtered), len(binaries))
821+
return filtered
822+
}
823+
750824
// filterToApplicableEnvironmentFlags filters the provided envFlags to only those that are applicable to the
751825
// APIVersion of OTE within the external binary.
752826
func (b *TestBinary) filterToApplicableEnvironmentFlags(envFlags EnvironmentFlags) EnvironmentFlags {
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package extensions
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestFilterExtensionBinariesByTags(t *testing.T) {
11+
// Test data
12+
testBinaries := []TestBinary{
13+
{imageTag: "tests", binaryPath: "/usr/bin/openshift-tests"},
14+
{imageTag: "hyperkube", binaryPath: "/usr/bin/k8s-tests-ext.gz"},
15+
{imageTag: "machine-api-operator", binaryPath: "/machine-api-tests-ext.gz"},
16+
{imageTag: "custom-operator", binaryPath: "/custom-tests-ext.gz"},
17+
}
18+
19+
tests := []struct {
20+
name string
21+
excludeTags string
22+
includeTags string
23+
expectedImageTags []string
24+
expectedCount int
25+
}{
26+
{
27+
name: "no environment variables set",
28+
excludeTags: "",
29+
includeTags: "",
30+
expectedImageTags: []string{"tests", "hyperkube", "machine-api-operator", "custom-operator"},
31+
expectedCount: 4,
32+
},
33+
{
34+
name: "exclude single tag",
35+
excludeTags: "hyperkube",
36+
includeTags: "",
37+
expectedImageTags: []string{"tests", "machine-api-operator", "custom-operator"},
38+
expectedCount: 3,
39+
},
40+
{
41+
name: "exclude multiple tags",
42+
excludeTags: "hyperkube,machine-api-operator",
43+
includeTags: "",
44+
expectedImageTags: []string{"tests", "custom-operator"},
45+
expectedCount: 2,
46+
},
47+
{
48+
name: "exclude with spaces",
49+
excludeTags: " hyperkube , machine-api-operator ",
50+
includeTags: "",
51+
expectedImageTags: []string{"tests", "custom-operator"},
52+
expectedCount: 2,
53+
},
54+
{
55+
name: "include single tag",
56+
excludeTags: "",
57+
includeTags: "tests",
58+
expectedImageTags: []string{"tests"},
59+
expectedCount: 1,
60+
},
61+
{
62+
name: "include multiple tags",
63+
excludeTags: "",
64+
includeTags: "tests,hyperkube",
65+
expectedImageTags: []string{"tests", "hyperkube"},
66+
expectedCount: 2,
67+
},
68+
{
69+
name: "include with spaces",
70+
excludeTags: "",
71+
includeTags: " tests , hyperkube ",
72+
expectedImageTags: []string{"tests", "hyperkube"},
73+
expectedCount: 2,
74+
},
75+
{
76+
name: "include takes precedence over exclude",
77+
excludeTags: "tests,hyperkube",
78+
includeTags: "tests",
79+
expectedImageTags: []string{"tests"},
80+
expectedCount: 1,
81+
},
82+
{
83+
name: "include non-existent tag",
84+
excludeTags: "",
85+
includeTags: "non-existent",
86+
expectedImageTags: []string{},
87+
expectedCount: 0,
88+
},
89+
{
90+
name: "exclude all tags",
91+
excludeTags: "tests,hyperkube,machine-api-operator,custom-operator",
92+
includeTags: "",
93+
expectedImageTags: []string{},
94+
expectedCount: 0,
95+
},
96+
}
97+
98+
for _, tt := range tests {
99+
t.Run(tt.name, func(t *testing.T) {
100+
// Set environment variables
101+
if tt.excludeTags != "" {
102+
os.Setenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS", tt.excludeTags)
103+
} else {
104+
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS")
105+
}
106+
107+
if tt.includeTags != "" {
108+
os.Setenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS", tt.includeTags)
109+
} else {
110+
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS")
111+
}
112+
113+
// Call the function
114+
result := filterExtensionBinariesByTags(testBinaries)
115+
116+
// Verify the count
117+
assert.Equal(t, tt.expectedCount, len(result), "Expected %d binaries, got %d", tt.expectedCount, len(result))
118+
119+
// Verify the image tags
120+
var actualImageTags []string
121+
for _, binary := range result {
122+
actualImageTags = append(actualImageTags, binary.imageTag)
123+
}
124+
125+
assert.ElementsMatch(t, tt.expectedImageTags, actualImageTags, "Expected image tags %v, got %v", tt.expectedImageTags, actualImageTags)
126+
127+
// Clean up environment variables
128+
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_EXCLUDE_TAGS")
129+
os.Unsetenv("EXTENSION_BINARY_OVERRIDE_INCLUDE_TAGS")
130+
})
131+
}
132+
}

0 commit comments

Comments
 (0)