Skip to content

Commit 05eeb94

Browse files
Merge pull request #29980 from stbenjam/limit-extensions
NO-JIRA: Allow only including / excluding specific extension images
2 parents 2b2313a + 01212f3 commit 05eeb94

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)