Skip to content

Commit

Permalink
Allow overriding extension binary to local path
Browse files Browse the repository at this point in the history
This makes it easier to do local development.
  • Loading branch information
stbenjam committed Feb 20, 2025
1 parent 2c391f3 commit 8285ecf
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 4 deletions.
18 changes: 18 additions & 0 deletions pkg/test/extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ credentials to use are found in this code, and extensively documented in code
comments. The following environment variables are available to force certain
behaviors:

### Extension Binary

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

```
export EXTENSION_BINARY_OVERRIDE_HYPERKUBE="/home/sally/git/kubernetes/_output/bin/k8s-tests-ext"
```

This overrides all extension binaries registered for that image tag
(i.e. hyperkube). In the uncommon situation where an image tag is
providing multiple test binaries, you can more specifically override one
like this:

```
export EXTENSION_BINARY_OVERRIDE_HYPERKUBE_USR_BIN_K8S_TESTS_EXT_GZ="/home/sally/git/kubernetes/_output/bin/k8s-tests-ext"
```

### Caching

By default, binaries will be cached in `$XDG_CACHE_HOME/openshift-tests`
Expand Down
6 changes: 3 additions & 3 deletions pkg/test/extensions/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (b *TestBinary) Info(ctx context.Context) (*ExtensionInfo, error) {
command := exec.Command(b.binaryPath, "info")
infoJson, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s info': %w", b.binaryPath, err)
return nil, fmt.Errorf("failed running '%s info': %w\nOutput: %s", b.binaryPath, err, infoJson)
}
jsonBegins := bytes.IndexByte(infoJson, '{')
jsonEnds := bytes.LastIndexByte(infoJson, '}')
Expand Down Expand Up @@ -106,7 +106,7 @@ func (b *TestBinary) ListTests(ctx context.Context, envFlags EnvironmentFlags) (
command.Args = append(command.Args, envFlags.ArgStrings()...)
testList, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s list': %w", b.binaryPath, err)
return nil, fmt.Errorf("failed running '%s list': %w\nOutput: %s", b.binaryPath, err, testList)
}
buf := bytes.NewBuffer(testList)
for {
Expand Down Expand Up @@ -212,7 +212,7 @@ func (b *TestBinary) ListImages(ctx context.Context) (ImageSet, error) {
command := exec.Command(b.binaryPath, "images")
output, err := runWithTimeout(ctx, command, 10*time.Minute)
if err != nil {
return nil, fmt.Errorf("failed running '%s list': %w", b.binaryPath, err)
return nil, fmt.Errorf("failed running '%s list': %w\nOutput: %s", b.binaryPath, err, output)
}

var images []Image
Expand Down
35 changes: 34 additions & 1 deletion pkg/test/extensions/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package extensions

import (
"fmt"
"github.com/sirupsen/logrus"
"os"
"path"
"path/filepath"
Expand All @@ -11,6 +10,7 @@ import (

imagev1 "github.com/openshift/api/image/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"

"github.com/openshift/origin/test/extended/util"
)
Expand Down Expand Up @@ -98,6 +98,20 @@ func (provider *ExternalBinaryProvider) ExtractBinaryFromReleaseImage(tag, binar
return nil, fmt.Errorf("extraction path is not set, cleanup was already run")
}

// Allow overriding image path to an already existing local path, mostly useful
// for development.
if override := binaryPathOverride(tag, binary); override != "" {
logrus.WithFields(logrus.Fields{
"tag": tag,
"binary": binary,
"override": override,
}).Info("Found override for this extension")
return &TestBinary{
imageTag: tag,
binaryPath: override,
}, nil
}

// Resolve the image tag from the image stream.
image := ""
for _, t := range provider.imageStream.Spec.Tags {
Expand Down Expand Up @@ -187,3 +201,22 @@ func cleanOldCacheFiles(dir string) {
}
logrus.Infof("Cleaned up old cached data in %v", time.Since(start))
}

func binaryPathOverride(imageTag, binaryPath string) string {
safeEnvVar := strings.NewReplacer("/", "_", "-", "_", ".", "_")

// Check for a specific override for this binary path, less common but allows supporting
// images that have multiple test binaries.
// Example: EXTENSION_BINARY_OVERRIDE_HYPERKUBE_USR_BIN_K8S_TESTS_EXT_GZ
specificOverrideEnvVar := fmt.Sprintf("EXTENSION_BINARY_OVERRIDE_%s_%s",
strings.ToUpper(safeEnvVar.Replace(imageTag)),
strings.ToUpper(safeEnvVar.Replace(strings.TrimPrefix(binaryPath, "/"))),
)
if specificOverride := os.Getenv(specificOverrideEnvVar); specificOverride != "" {
return specificOverride
}

// Check for a global override for all binaries in this image
// Example: EXTENSION_BINARY_OVERRIDE_HYPERKUBE
return os.Getenv(fmt.Sprintf("EXTENSION_BINARY_OVERRIDE_%s", strings.ToUpper(safeEnvVar.Replace(imageTag))))
}
84 changes: 84 additions & 0 deletions pkg/test/extensions/provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package extensions

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestBinaryPathOverride(t *testing.T) {
tests := []struct {
name string
imageTag string
binaryPath string
envVars map[string]string
expectedPath string
}{
{
name: "Global override for image",
imageTag: "hyperkube",
binaryPath: "/usr/bin/k8s-tests-ext",
envVars: map[string]string{
"EXTENSION_BINARY_OVERRIDE_HYPERKUBE": "/custom/global/path",
},
expectedPath: "/custom/global/path",
},
{
name: "Specific override for binary",
imageTag: "hyperkube",
binaryPath: "/usr/bin/k8s-tests-ext",
envVars: map[string]string{
"EXTENSION_BINARY_OVERRIDE_HYPERKUBE_USR_BIN_K8S_TESTS_EXT": "/custom/specific/path",
},
expectedPath: "/custom/specific/path",
},
{
name: "No overrides",
imageTag: "hyperkube",
binaryPath: "/usr/bin/k8s-tests-ext",
envVars: map[string]string{},
expectedPath: "",
},
{
name: "Specific override takes precedence over global",
imageTag: "hyperkube",
binaryPath: "/usr/bin/k8s-tests-ext",
envVars: map[string]string{
"EXTENSION_BINARY_OVERRIDE_HYPERKUBE": "/custom/global/path",
"EXTENSION_BINARY_OVERRIDE_HYPERKUBE_USR_BIN_K8S_TESTS_EXT": "/custom/specific/path",
},
expectedPath: "/custom/specific/path",
},
{
name: "Special characters in image and binary path",
imageTag: "special-image",
binaryPath: "/usr/local/bin/special-tests-1.2.3",
envVars: map[string]string{
"EXTENSION_BINARY_OVERRIDE_SPECIAL_IMAGE_USR_LOCAL_BIN_SPECIAL_TESTS_1_2_3": "/custom/path/for-special",
},
expectedPath: "/custom/path/for-special",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for k, v := range tt.envVars {
err := os.Setenv(k, v)
assert.NoError(t, err)
}

result := binaryPathOverride(tt.imageTag, tt.binaryPath)

if result != tt.expectedPath {
t.Errorf("binaryPathOverride(%q, %q) = %q; want %q",
tt.imageTag, tt.binaryPath, result, tt.expectedPath)
}

for k := range tt.envVars {
err := os.Unsetenv(k)
assert.NoError(t, err)
}
})
}
}

0 comments on commit 8285ecf

Please sign in to comment.