Skip to content
Merged
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
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ build: fmt vet
build-daemon:
env GOOS=windows GOARCH=amd64 go build -o ${OUTPUT_DIR}/bin/windows-instance-config-daemon.exe ./cmd/daemon

# Build the OTE (OpenShift Tests Extension) binary for Windows Containers tests.
# GO_COMPLIANCE_POLICY=exempt_all is required for test binaries per ART compliance policy.
# The OTE binary lives in the ote/ nested module, isolated from the operator's go.mod.
.PHONY: build-tests-ext
build-tests-ext:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my own education; where/who is invoking make build-tests-ext?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently for local development only — make build-tests-ext lets developers build and test the OTE binary locally. Including it in the final image is planned as a follow-up once this PoC is merged.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently for local development only — make build-tests-ext lets developers build and test the OTE binary locally. Including it in the final image is planned as a follow-up once this PoC is merged.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including it in the final image is planned as a follow-up once this PoC is merged.

I highly recommend also including this in this PR, IMO it must be part of the PoC, given it proves the concept works and we can get a CI signal on it.

Consuming the OTE binary is a key part of the proposal and would be great to have it in this PR.

is there any external blocker on this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jrvaldes Is adding a standalone presubmit that runs wmco-tests-ext list sufficient as CI signal, or do you need the full OTE integration via openshift/origin registration? Happy to do either — just want to confirm scope before implementing.

cd ote && GOFLAGS="" go mod download && GOFLAGS="" GO_COMPLIANCE_POLICY="exempt_all" go build -o ../${OUTPUT_DIR}/bin/wmco-tests-ext ./cmd/wmco-tests-ext

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run cmd/operator/main.go
Expand Down
4 changes: 4 additions & 0 deletions build/Dockerfile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ COPY bundle bundle
COPY hack hack
COPY pkg pkg
COPY test test
COPY ote ote
COPY vendor vendor
COPY version version
COPY go.mod go.mod
Expand All @@ -100,6 +101,7 @@ COPY tools.go tools.go
COPY .gitignore .gitignore
RUN make build
RUN make build-daemon
RUN make build-tests-ext && gzip -9 build/_output/bin/wmco-tests-ext

# Build the operator image with following payload structure
# /payload/
Expand Down Expand Up @@ -208,6 +210,8 @@ COPY --from=build /build/windows-machine-config-operator .

# install operator binary
COPY --from=build /build/windows-machine-config-operator/build/_output/bin/windows-machine-config-operator ${OPERATOR}
# install OTE test extension binary (gzip compressed for openshift-tests extraction)
COPY --from=build /build/windows-machine-config-operator/build/_output/bin/wmco-tests-ext.gz /usr/bin/wmco-tests-ext.gz
COPY --from=build /build/windows-machine-config-operator/build/bin /usr/local/bin
RUN /usr/local/bin/user_setup

Expand Down
2 changes: 2 additions & 0 deletions ote/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
vendor/
bin/
8 changes: 8 additions & 0 deletions ote/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
reviewers:
- rrasouli
- weinliu
- mansikulkarni96
approvers:
- rrasouli
- weinliu
Comment on lines +5 to +7
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add @mansikulkarni96 as backup

- mansikulkarni96
83 changes: 83 additions & 0 deletions ote/cmd/wmco-tests-ext/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// windows-machine-config-operator-tests-ext is the OTE (OpenShift Tests Extension)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider creating a nested OWNERS file so that you and @rrasouli are in the loop for everyting under /ote

see https://docs.ci.openshift.org/how-tos/onboarding-a-new-component/#repositories-under-existing-organizations

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added ote/OWNERS with rrasouli and weinliu as reviewers/approvers.

// binary for Windows Containers tests. Tests are registered as plain Go functions
// using upstream Ginkgo, without the OpenShift Ginkgo fork.
//
// References:
// - OTE Integration Guide: https://github.com/openshift-eng/openshift-tests-extension
package main

import (
"context"
"os"

otecmd "github.com/openshift-eng/openshift-tests-extension/pkg/cmd"
e "github.com/openshift-eng/openshift-tests-extension/pkg/extension"
et "github.com/openshift-eng/openshift-tests-extension/pkg/extension/extensiontests"
"github.com/spf13/cobra"

"github.com/openshift/windows-machine-config-operator/ote/test/extended"
"github.com/openshift/windows-machine-config-operator/ote/test/extended/cli"
)

func main() {
registry := e.NewRegistry()
ext := e.NewExtension("openshift", "payload", "windows-machine-config-operator")

// All WINC tests - used for full runs and informing jobs.
// No qualifier needed: all tests in this binary are WINC tests.
ext.AddSuite(e.Suite{
Name: "windows/all",
})

// Parallel subset: non-Serial, non-Slow, non-Disruptive tests.
ext.AddSuite(e.Suite{
Name: "windows/parallel",
Qualifiers: []string{
`!name.contains("[Serial]") && !name.contains("[Slow]") && !name.contains("[Disruptive]")`,
},
})

// Serial subset: tests that must run in isolation.
ext.AddSuite(e.Suite{
Name: "windows/serial",
Qualifiers: []string{
`name.contains("[Serial]")`,
},
})

// Storage-specific tests.
ext.AddSuite(e.Suite{
Name: "windows/storage",
Qualifiers: []string{
`name.contains("storage")`,
},
})

// Register test specs manually — no OpenShift Ginkgo fork required.
specs := et.ExtensionTestSpecs{
{
Name: "[sig-windows] Windows_Containers Author:rrasouli-Smokerun-Medium-37362-[wmco] wmco using correct golang version [OTP]",
Run: func(ctx context.Context) *et.ExtensionTestResult {
if err := extended.CheckWmcoGolangVersion(ctx, cli.NewCLIWithoutNamespace()); err != nil {
return &et.ExtensionTestResult{Result: et.ResultFailed, Output: err.Error()}
}
return &et.ExtensionTestResult{Result: et.ResultPassed}
},
},
}

ext.AddSpecs(specs)
registry.Register(ext)

root := &cobra.Command{
Use: "windows-machine-config-operator-tests-ext",
Short: "OpenShift Windows Containers test extension (OTE)",
Long: "Runs the WINC test suite as an OpenShift Tests Extension binary.",
}

root.AddCommand(otecmd.DefaultExtensionCommands(registry)...)

if err := root.Execute(); err != nil {
os.Exit(1)
}
}
22 changes: 22 additions & 0 deletions ote/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module github.com/openshift/windows-machine-config-operator/ote

go 1.24.0

require (
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818
github.com/spf13/cobra v1.10.2
)

require (
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/google/cel-go v0.17.8 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/text v0.19.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect
google.golang.org/protobuf v1.35.1 // indirect
)
45 changes: 45 additions & 0 deletions ote/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto=
github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818 h1:jJLE/aCAqDf8U4wc3bE1IEKgIxbb0ICjCNVFA49x/8s=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
77 changes: 77 additions & 0 deletions ote/test/extended/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cli

import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)

// CLI wraps the oc command-line tool for use in OTE Ginkgo tests.
type CLI struct {
namespace string
asAdmin bool
kubeconfig string
}

// NewCLI creates a CLI instance with the given namespace.
func NewCLI(namespace string) *CLI {
return &CLI{
namespace: namespace,
kubeconfig: kubeconfig(),
}
}

// NewCLIWithoutNamespace creates a CLI instance without a namespace (for cluster-scoped resources).
func NewCLIWithoutNamespace() *CLI {
return NewCLI("")
}

// AsAdmin returns a copy of the CLI that runs as cluster-admin.
func (c *CLI) AsAdmin() *CLI {
copy := *c
copy.asAdmin = true
return &copy
}

// Run executes an oc subcommand with the given arguments and returns stdout, stderr, and any error.
func (c *CLI) Run(verb string, args ...string) (string, string, error) {
cmdArgs := []string{verb}
if c.asAdmin {
cmdArgs = append(cmdArgs, "--as=system:admin")
}
if c.namespace != "" {
cmdArgs = append(cmdArgs, "-n", c.namespace)
}
cmdArgs = append(cmdArgs, args...)

cmd := exec.Command("oc", cmdArgs...)
if c.kubeconfig != "" {
cmd.Env = append(os.Environ(), "KUBECONFIG="+c.kubeconfig)
}

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()
return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err
}

// Output is a convenience wrapper that returns stdout or an error combining stderr.
func (c *CLI) Output(verb string, args ...string) (string, error) {
out, errOut, err := c.Run(verb, args...)
if err != nil {
return "", fmt.Errorf("%w\nstderr: %s", err, errOut)
}
return out, nil
}

func kubeconfig() string {
if kc := os.Getenv("KUBECONFIG"); kc != "" {
return kc
}
return filepath.Join(os.Getenv("HOME"), ".kube", "config")
}
53 changes: 53 additions & 0 deletions ote/test/extended/cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package extended

import (
"context"
"encoding/json"
"fmt"
"strings"

"github.com/openshift/windows-machine-config-operator/ote/test/extended/cli"
)

const (
wmcoNamespace = "openshift-windows-machine-config-operator"
)

// CheckWmcoGolangVersion verifies that the golang version reported by the cluster
// matches the version used to build the WMCO binary (OCP-37362).
func CheckWmcoGolangVersion(_ context.Context, oc *cli.CLI) error {
serverVersion, err := oc.AsAdmin().Output("get", "--raw", "/version")
if err != nil {
return fmt.Errorf("failed to get cluster version: %w", err)
}

var versionInfo struct {
GoVersion string `json:"goVersion"`
}
if err := json.Unmarshal([]byte(serverVersion), &versionInfo); err != nil {
return fmt.Errorf("failed to parse /version JSON: %w", err)
}
if versionInfo.GoVersion == "" {
return fmt.Errorf("goVersion not found in /version response")
}

parts := strings.Split(versionInfo.GoVersion, ".")
if len(parts) < 2 {
return fmt.Errorf("unexpected golang version format: %s", versionInfo.GoVersion)
}
truncated := strings.Join(parts[:2], ".")

logs, err := oc.AsAdmin().Output("logs",
"deployment.apps/windows-machine-config-operator",
"-n", wmcoNamespace,
)
if err != nil {
return fmt.Errorf("failed to get WMCO logs: %w", err)
}

if !strings.Contains(logs, truncated) {
return fmt.Errorf("WMCO logs do not contain expected golang version %s (full: %s)",
truncated, versionInfo.GoVersion)
}
return nil
}