OCPCLOUD-3319: Create installer controller - #494
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@mdbooth: This pull request references OCPCLOUD-3319 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Skipping CI for Draft Pull Request. |
|
Important Review skippedAuto reviews are limited based on label configuration. 🚫 Review skipped — only excluded labels are configured. (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughReplaced the legacy capiinstaller implementation with a new installer controller and revision-based engine (boxcutter); removed capiinstaller sources and tests; added installer probes, relatedObjects handling, extensive installer tests and helpers; updated main wiring and multiple go.mod files; added a ClusterAPI manifest. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
| - group: apiextensions.openshift.io | ||
| resource: compatibilityrequirements | ||
|
|
||
| # the installer controller dynamically adds entries for CAPI providers it installs No newline at end of file |
There was a problem hiding this comment.
Nit, missing final new line character
| // CRDAsYAML marshals a CRD object to YAML. Use with GenerateCRD or | ||
| // GenerateSchemalessSpecStatusCRD from crdbuilder.go to create CRD fixtures | ||
| // for use with WithManifests. | ||
| func CRDAsYAML(crd *apiextensionsv1.CustomResourceDefinition) string { |
There was a problem hiding this comment.
Took me a moment to realise this is CRD As YAML instead of CRDAs YAML, what is a CRDA 😂
| Profile: profileName, | ||
| ManifestsPath: writeManifestFile(t, manifestContent), | ||
| } | ||
| return test.NewTestProvider(t, name, |
There was a problem hiding this comment.
Why is this NewTestProvider and not NewTestProviderImageManifests? A Provider feels different to me
| // reconcileCh allows tests to explicitly trigger reconciliation, | ||
| // even when no ClusterAPI object exists. | ||
| reconcileCh chan event.TypedGenericEvent[client.Object] |
There was a problem hiding this comment.
Why not just always have a ClusterAPI object?
There was a problem hiding this comment.
There's a wait test for if CVO creates us before the ClusterAPI object.
| type revisionHandler func(context.Context, []operatorv1alpha1.ClusterAPIInstallerRevision) (bool, []string, []error) | ||
|
|
||
| // mergeWithTail merges the results of the head revision with the results of calling the tail handler on the tail revisions. | ||
| func mergeWithTail(ctx context.Context, tailHandler revisionHandler, tailRevisions []operatorv1alpha1.ClusterAPIInstallerRevision) func(bool, string, error) (bool, []string, []error) { |
There was a problem hiding this comment.
The head and tail semantics here are not immediately obvious, might be worth some further comments to explain what's going on in these various flows
| DiscoveryClient: discoveryClient, | ||
| RestMapper: mgr.GetRESTMapper(), | ||
| Writer: mgr.GetClient(), | ||
| Reader: trackingCache, |
There was a problem hiding this comment.
This is interesting, why do they have their own tracking cache? Why not read from the informers like a normal controller would?
There was a problem hiding this comment.
The tracking cache dynamically adds and removes informers as required according to whatever's in the manifests.
| return gvk.String() | ||
| }), ", ")) | ||
|
|
||
| err := c.trackingCache.Watch(ctx, clusterAPI, allGVKs) |
There was a problem hiding this comment.
How do you stop watching a GVK if it is no longer relevant?
There was a problem hiding this comment.
The tracking cache automatically prunes them when allGVKs passed here no longer contains the GVK.
7cae2d6 to
04780de
Compare
|
/test e2e-aws-capi-techpreview |
|
/pipeline required |
|
Scheduling tests matching the |
| /* | ||
| * The entry point to this file is the revisionReconciler.reconcile() function. | ||
| * revisionReconciler.reconcile() reconciles a list of revisions. | ||
| * | ||
| * Revisions are created by the revision controller. They represent all the | ||
| * manifests from the current release which are relevant to the current cluster. | ||
| * The revision controller will add a new revision with a higher revision number | ||
| * whenever there is any change in the manifests to be applied. | ||
| * | ||
| * The goal of the installer controller is to ensure all manifests specified by | ||
| * the most recent revision are applied to the cluster, and that objects which | ||
| * are no longer required are removed. | ||
| * | ||
| * The installer controller manages objects with Boxcutter. Boxcutter defines 2 | ||
| * operations on a revision: | ||
| * * reconcile (create) | ||
| * * teardown (remove) | ||
| * We want to 'reconcile' the newest revision, and 'teardown' any older | ||
| * revisions. Note that a newer revision will typically be similar to an older | ||
| * revision, so an object will usually be in multiple revisions. Boxcutter | ||
| * stores metadata on objects it installs to track the most recent revision | ||
| * which was successfully applied the object. During teardown, it won't remove | ||
| * an object if it's managed by a newer revision. Therefore it's crtically | ||
| * important that we successfully reconcile the new revision before tearing down | ||
| * any older revisions. | ||
| * | ||
| * An additional goal is that if the newest revision can't be applied for any | ||
| * reason, for example because its CRD Requirements are not compatible with the | ||
| * cluster, we should continue to reconcile the next most recently applied | ||
| * revision. | ||
| * | ||
| * The algorithm here is to try to reconcile the newest revision. If it succeeds | ||
| * we teardown all older revisions. If it does not succeed, either because of | ||
| * failure or just because it's incomplete, we try to reconcile the next | ||
| * revision according to the same algorithm. This maps nicely to tail recursion | ||
| * because at any point in the revision list we are, we are always in one of | ||
| * two modes: | ||
| * * reconcile the head and teardown the tail, or | ||
| * * teardown everything | ||
| */ |
There was a problem hiding this comment.
@JoelSpeed I added this in response to your comment below. Does it read ok?
There was a problem hiding this comment.
Yep, this is helpful for future us i think, thanks
|
/test e2e-aws-ovn-techpreview |
5de775c to
51a5361
Compare
|
/test e2e-aws-capi-techpreview |
51a5361 to
dfefa3f
Compare
|
/pipeline auto |
|
Pipeline controller notification The |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
cmd/capi-operator/main.go (1)
167-185: Ensure deterministic provider image ordering throughout the pipeline.The issue runs deeper than map iteration order. The
ReadProviderImagesfunction uses concurrent goroutine processing (errgroup with limit 5) to fetch provider metadata, and results are appended to the output slice in the order they arrive from the channel—making the output order nondeterministic regardless of input order. This can cause unnecessary revision churn and unpredictable reconciliation behavior.Sort
containerImageRefsbefore passing toReadProviderImagesas a defensive measure to ensure at least one stable boundary:♻️ Suggested change
containerImageRefs := slices.Collect(maps.Values(containerImages)) + slices.Sort(containerImageRefs) providerProfiles, err := providerimages.ReadProviderImages(ctx, mgr.GetAPIReader(), mgr.GetLogger(), containerImageRefs, providerImageDir)For a complete fix,
ReadProviderImagesshould also sort its results before returning to guarantee stable output across restarts.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmd/capi-operator/main.go` around lines 167 - 185, The provider image output is nondeterministic because concurrent ReadProviderImages appends results in arrival order; to mitigate, sort the input slice before calling ReadProviderImages by deterministically ordering containerImageRefs (e.g., lexicographically) so loadProviderImages feeds a stable sequence, and also update ReadProviderImages to sort its final []providerimages.ProviderImageManifests result before returning to guarantee stable output across runs; reference loadProviderImages, containerImageRefs, and ReadProviderImages when making these changes.pkg/controllers/installer/related_objects.go (1)
54-71: Deduplicate the dynamic tail as well.Right now only overlaps with
staticare removed. The installer aggregates related objects across revisions before calling this helper (pkg/controllers/installer/installer_controller.goLines 212-217), so the same CRD/RBAC object can still be appended multiple times during revision overlap and leak duplicates intostatus.relatedObjects.Proposed fix
func mergeRelatedObjects(static, dynamic []configv1.ObjectReference) []configv1.ObjectReference { - staticSet := make(map[configv1.ObjectReference]struct{}, len(static)) + seen := make(map[configv1.ObjectReference]struct{}, len(static)+len(dynamic)) for _, obj := range static { - staticSet[obj] = struct{}{} + seen[obj] = struct{}{} } var deduped []configv1.ObjectReference for _, obj := range dynamic { - if _, exists := staticSet[obj]; !exists { + if _, exists := seen[obj]; !exists { + seen[obj] = struct{}{} deduped = append(deduped, obj) } } slices.SortFunc(deduped, compareObjectReference)Please add a
related_objects_test.gocase for duplicate dynamic entries alongside the code change.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/controllers/installer/related_objects.go` around lines 54 - 71, The mergeRelatedObjects function currently only removes entries from dynamic that overlap static; update mergeRelatedObjects to also deduplicate duplicate entries within the dynamic slice itself (e.g., track seen entries with a map[configv1.ObjectReference]struct{} while iterating dynamic, skip already-seen ones and ones present in staticSet), then sort the deduped dynamic tail with slices.SortFunc(compareObjectReference) and append to a cloned static slice; also add a unit test in related_objects_test.go that calls mergeRelatedObjects with dynamic containing duplicate CRD/RBAC entries (and overlapping entries with static) and asserts the returned slice has no duplicates in the dynamic tail and preserves expected ordering.pkg/operatorstatus/controller_status.go (1)
37-42: Avoid a second source of truth for theClusterOperatorname.
pkg/operatorstatus/operator_status.gostill reads/creates the singleton viacontrollers.ClusterOperatorName, while this file now patches it viaClusterOperatorName. Keeping both exported constants around makes future drift a correctness bug. Please collapse these call sites onto one shared constant before more code depends on both names.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/operatorstatus/controller_status.go` around lines 37 - 42, There are two exported constants for the ClusterOperator name (ClusterOperatorName in pkg/operatorstatus/controller_status.go and controllers.ClusterOperatorName used in pkg/operatorstatus/operator_status.go); collapse them to a single shared constant and update call sites to use that one symbol. Choose one location (preferably the existing controllers.ClusterOperatorName) to hold the canonical constant, remove the duplicate ClusterOperatorName declaration, and update any references in operator_status.go and controller_status.go to import and use controllers.ClusterOperatorName (or conversely move the canonical constant and update the other file) so there is only one exported source of truth.pkg/controllers/installer/revision_reconciler.go (1)
459-466: Naive pluralization may produce incorrect resource names.
strings.ToLower(gvk.Kind) + "s"doesn't handle irregular plurals (e.g.,Ingress→ingresssinstead ofingresses). While this is informational forrelatedObjects/must-gather and won't break functionality, consider using a proper pluralization helper or the REST mapper if accuracy matters.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/controllers/installer/revision_reconciler.go` around lines 459 - 466, The code naively builds a plural by doing strings.ToLower(gvk.Kind)+"s" which yields incorrect plurals; replace this with a proper resource lookup (e.g., use meta.UnsafeGuessKindToResource(gvk) or the controller's RESTMapper) and use the returned GroupVersionResource's Resource value when calling r.relatedObjects.Insert. Update the branch handling obj.GetNamespace()=="" to compute resource via meta.UnsafeGuessKindToResource(gvk) (or call r.restMapper.ResourceFor(...) if you have a RESTMapper instance available) and fall back to the current naive plural only if the lookup fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@e2e/go.mod`:
- Around line 23-25: The e2e module's Kubernetes and klog versions (k8s.io/api,
k8s.io/apimachinery, k8s.io/client-go pinned to v0.35.2 and k8s.io/klog at
v2.140.0) drift from the root module's replace pins (which set the operator to
v0.35.1 and v2.130.1); fix by making the pins consistent—either add matching
replace directives in e2e/go.mod to force the same replacements as the root
(e.g., replace k8s.io/* and k8s.io/klog to the root's pinned module versions) or
update the root module's replace block to the e2e versions—ensure you target the
symbols k8s.io/api, k8s.io/apimachinery, k8s.io/client-go, and k8s.io/klog so
e2e uses identical Kubernetes/klog patch versions as the operator.
In `@pkg/controllers/installer/installer_controller_test.go`:
- Line 179: The test is calling checkConfigMap(ctx, coreCMName) immediately and
passing its error result to Eventually, so Gomega polls a fixed value; change
the Eventually argument to a closure that calls checkConfigMap each poll (e.g.,
pass func() error { return checkConfigMap(ctx, coreCMName) }) and keep the
existing Should(Satisfy(apierrors.IsNotFound)) assertion so Eventually
re-evaluates the checkConfigMap call on each retry.
In `@pkg/controllers/installer/installer_controller.go`:
- Around line 203-209: The early return when clusterAPI.Status.Revisions is
empty skips calling updateWatches(), leaving stale tracking-cache watches
registered; change the branch so that before returning (after
writeRelatedObjects/staticRelatedObjects), you invoke updateWatches(...) to
clear or reconcile watches for the now-empty revisions set (i.e., call the
controller's updateWatches(ctx, ...) / tracking-cache cleanup function using the
current Cluster API object), then return opresult.WaitingOnExternal("ClusterAPI
revisions"); ensure you reference clusterAPI.Status.Revisions and
updateWatches() so the watches are updated even when revisions go from non-empty
to empty.
In `@pkg/controllers/installer/revision_reconciler.go`:
- Around line 139-146: reconcile() currently assumes converted[0] exists when
isComplete is true — add a guard to avoid an index-out-of-bounds panic by
checking that the converted (or revisions) slice has at least one element before
accessing converted[0]; if the slice is empty, return nil (or an appropriate nil
name) with messages and errs instead of dereferencing converted[0]; update the
block around the call to reconcileRevisions in reconcile() so it validates
len(converted) > 0 (or len(revisions) > 0) before calling RevisionName() on
converted[0].
---
Nitpick comments:
In `@cmd/capi-operator/main.go`:
- Around line 167-185: The provider image output is nondeterministic because
concurrent ReadProviderImages appends results in arrival order; to mitigate,
sort the input slice before calling ReadProviderImages by deterministically
ordering containerImageRefs (e.g., lexicographically) so loadProviderImages
feeds a stable sequence, and also update ReadProviderImages to sort its final
[]providerimages.ProviderImageManifests result before returning to guarantee
stable output across runs; reference loadProviderImages, containerImageRefs, and
ReadProviderImages when making these changes.
In `@pkg/controllers/installer/related_objects.go`:
- Around line 54-71: The mergeRelatedObjects function currently only removes
entries from dynamic that overlap static; update mergeRelatedObjects to also
deduplicate duplicate entries within the dynamic slice itself (e.g., track seen
entries with a map[configv1.ObjectReference]struct{} while iterating dynamic,
skip already-seen ones and ones present in staticSet), then sort the deduped
dynamic tail with slices.SortFunc(compareObjectReference) and append to a cloned
static slice; also add a unit test in related_objects_test.go that calls
mergeRelatedObjects with dynamic containing duplicate CRD/RBAC entries (and
overlapping entries with static) and asserts the returned slice has no
duplicates in the dynamic tail and preserves expected ordering.
In `@pkg/controllers/installer/revision_reconciler.go`:
- Around line 459-466: The code naively builds a plural by doing
strings.ToLower(gvk.Kind)+"s" which yields incorrect plurals; replace this with
a proper resource lookup (e.g., use meta.UnsafeGuessKindToResource(gvk) or the
controller's RESTMapper) and use the returned GroupVersionResource's Resource
value when calling r.relatedObjects.Insert. Update the branch handling
obj.GetNamespace()=="" to compute resource via
meta.UnsafeGuessKindToResource(gvk) (or call r.restMapper.ResourceFor(...) if
you have a RESTMapper instance available) and fall back to the current naive
plural only if the lookup fails.
In `@pkg/operatorstatus/controller_status.go`:
- Around line 37-42: There are two exported constants for the ClusterOperator
name (ClusterOperatorName in pkg/operatorstatus/controller_status.go and
controllers.ClusterOperatorName used in pkg/operatorstatus/operator_status.go);
collapse them to a single shared constant and update call sites to use that one
symbol. Choose one location (preferably the existing
controllers.ClusterOperatorName) to hold the canonical constant, remove the
duplicate ClusterOperatorName declaration, and update any references in
operator_status.go and controller_status.go to import and use
controllers.ClusterOperatorName (or conversely move the canonical constant and
update the other file) so there is only one exported source of truth.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: af313bf3-68c0-4bd5-9bd7-92a57b7bf4b5
⛔ Files ignored due to path filters (273)
e2e/go.sumis excluded by!**/*.sumgo.sumis excluded by!**/*.sumhack/tools/go.sumis excluded by!**/*.summanifests-gen/go.sumis excluded by!**/*.sumvendor/github.com/go-openapi/jsonpointer/.cliff.tomlis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/.gitignoreis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/.golangci.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/NOTICEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/SECURITY.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/errors.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonpointer/pointer.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/.editorconfigis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/.gitignoreis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/.golangci.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/NOTICEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/SECURITY.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/internal/normalize_url.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/jsonreference/reference.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/.codecov.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/.gitignoreis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/.golangci.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/.mockery.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/CONTRIBUTORS.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/SECURITY.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/cmdutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/cmdutils/cmd_utils.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/cmdutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/cmdutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/convert.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/convert_types.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/format.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/sizeof.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv/type_constraints.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/conv_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/convert.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/convert_types.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/errors.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/file.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/fileutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/fileutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/fileutils/file.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/fileutils/path.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/fileutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/go.workis excluded by!**/*.work,!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/go.work.sumis excluded by!**/*.sum,!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/initialism_index.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/json.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonname/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonname/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonname/name_provider.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonname_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/ifaces.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/registry_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/registry.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/adapter.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/lexer.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/ordered_map.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/pool.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/register.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/writer.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/concat.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/json.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils/ordered_map.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/jsonutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/errors.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/json.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/loading.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/options.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading/yaml.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/loading_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/BENCHMARK.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/initialism_index.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/name_lexem.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/name_mangler.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/options.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/pools.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/split.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/string_bytes.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling/util.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/mangling_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/name_lexem.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/net.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/netutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/netutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/netutils/net.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/netutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/split.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/stringutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/stringutils/collection_formats.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/stringutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/stringutils/strings.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/stringutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/typeutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/typeutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/typeutils/types.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/typeutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/util.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yaml.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yamlutils/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yamlutils/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yamlutils/errors.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yamlutils/ordered_map.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yamlutils/yaml.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/go-openapi/swag/yamlutils_iface.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/cel/BUILD.bazelis excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/cel/library.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/cel/optimizer.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/checker/checker.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/checker/env.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/checker/scopes.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/ast/ast.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/debug/debug.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/env/BUILD.bazelis excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/env/env.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/BUILD.bazelis excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/bool.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/bytes.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/double.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/duration.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/int.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/json_value.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/list.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/map.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/null.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/object.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/string.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/timestamp.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/common/types/uint.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/bindings.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/comprehensions.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/extension_option_factory.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/formatting_v2.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/native.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/ext/regex.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/interpreter/attribute_patterns.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/interpreter/attributes.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/interpreter/interpretable.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/interpreter/interpreter.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/interpreter/planner.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/cel-go/parser/helper.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/gnostic-models/extensions/extension.protois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/gnostic-models/openapiv2/OpenAPIv2.protois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/gnostic-models/openapiv3/OpenAPIv3.protois excluded by!**/vendor/**,!vendor/**vendor/github.com/google/gnostic-models/openapiv3/annotations.protois excluded by!**/vendor/**,!vendor/**vendor/github.com/josharian/intern/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/josharian/intern/intern.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/josharian/intern/license.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/buffer/pool.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/jlexer/bytestostr.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/jlexer/error.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/jlexer/lexer.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/mailru/easyjson/jwriter/writer.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/common/expfmt/expfmt.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/common/expfmt/fuzz.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/.golangci.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/Makefile.commonis excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_armx.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_loong64.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_mipsx.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_others.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_ppcx.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_riscvx.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_s390x.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/cpuinfo_x86.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/fs_statfs_notype.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/fs_statfs_type.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/internal/util/sysreadfile.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/kernel_hung.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/kernel_random.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/net_tcp.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/proc_interrupts.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/proc_maps.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/proc_smaps.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/proc_statm.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/proc_status.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/vm.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/prometheus/procfs/zoneinfo.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/.gitignoreis excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/.golangci.ymlis excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/README.mdis excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/camel.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/doc.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/helper.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/kebab.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/stoewer/go-strcase/snake.gois excluded by!**/vendor/**,!vendor/**vendor/github.com/stretchr/objx/README.mdis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/CHANGELOG.mdis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/CONTRIBUTING.mdis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/Makefileis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/README.mdis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/propagation/trace_context.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/requirements.txtis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.39.0/httpconv/metric.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/MIGRATION.mdis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/README.mdis excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/attribute_group.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/doc.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/error_type.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/exception.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/semconv/v1.40.0/schema.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/trace/auto.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/trace/trace.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/trace/tracestate.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/version.gois excluded by!**/vendor/**,!vendor/**vendor/go.opentelemetry.io/otel/versions.yamlis excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/net/http2/http2.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/net/http2/server.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/net/http2/transport.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/net/http2/writesched.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/net/http2/writesched_priority_rfc7540.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/net/http2/writesched_random.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sync/singleflight/singleflight.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/asm_darwin_arm64_gc.sis excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/cpu_arm64.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/cpu_darwin_arm64.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/cpu_other_arm64.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/cpu/syscall_darwin_arm64_gc.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/plan9/syscall_plan9.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/unix/ztypes_linux.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/windows/aliases.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/windows/registry/key.gois excluded by!**/vendor/**,!vendor/**vendor/golang.org/x/sys/windows/syscall_windows.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/client-go/openapi3/root.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/client-go/util/csaupgrade/OWNERSis excluded by!**/vendor/**,!vendor/**vendor/k8s.io/client-go/util/csaupgrade/options.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/client-go/util/csaupgrade/upgrade.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/kube-openapi/pkg/validation/spec/ref.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/kube-openapi/pkg/validation/validate/schema.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/kube-openapi/pkg/validation/validate/validator.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/utils/buffer/ring_fixed.gois excluded by!**/vendor/**,!vendor/**vendor/k8s.io/utils/strings/slices/slices.gois excluded by!**/vendor/**,!vendor/**vendor/modules.txtis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/.codecov.yamlis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/.gitignoreis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/.golangci.yamlis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/.pre-commit-config.yamlis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/CONTRIBUTING.mdis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/LICENSEis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/README.mdis excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/boxcutter.gois excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/dois excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/machinery/comparator.gois excluded by!**/vendor/**,!vendor/**vendor/pkg.package-operator.run/boxcutter/machinery/doc.gois excluded by!**/vendor/**,!vendor/**
📒 Files selected for processing (27)
cmd/capi-operator/main.goe2e/go.modgo.modhack/tools/go.modmanifests-gen/go.modmanifests/0000_30_cluster-api-installer_06_clusterapi.yamlpkg/controllers/capiinstaller/apiextensions.gopkg/controllers/capiinstaller/capi_installer_controller.gopkg/controllers/capiinstaller/capi_installer_controller_test.gopkg/controllers/capiinstaller/component_customizer.gopkg/controllers/capiinstaller/suite_test.gopkg/controllers/capiinstaller/watch_predicates.gopkg/controllers/corecluster/corecluster_controller.gopkg/controllers/installer/boxcutter.gopkg/controllers/installer/helpers_test.gopkg/controllers/installer/installer_controller.gopkg/controllers/installer/installer_controller_test.gopkg/controllers/installer/probes.gopkg/controllers/installer/related_objects.gopkg/controllers/installer/related_objects_test.gopkg/controllers/installer/revision_reconciler.gopkg/controllers/installer/suite_test.gopkg/operatorstatus/controller_status.gopkg/operatorstatus/controller_status_test.gopkg/operatorstatus/operator_status.gopkg/revisiongenerator/revision.gopkg/test/namespace_cleanup.go
💤 Files with no reviewable changes (6)
- pkg/controllers/capiinstaller/suite_test.go
- pkg/controllers/capiinstaller/capi_installer_controller_test.go
- pkg/controllers/capiinstaller/component_customizer.go
- pkg/controllers/capiinstaller/apiextensions.go
- pkg/controllers/capiinstaller/watch_predicates.go
- pkg/controllers/capiinstaller/capi_installer_controller.go
|
|
||
| // Delete the ConfigMap and wait for it to be not found | ||
| Expect(cl.Delete(ctx, cm)).To(Succeed()) | ||
| Eventually(checkConfigMap(ctx, coreCMName)).Should(Satisfy(apierrors.IsNotFound)) |
There was a problem hiding this comment.
Eventually receives a pre-evaluated error instead of a polling function.
Eventually(checkConfigMap(ctx, coreCMName)) calls checkConfigMap once and passes its result (an error) to Eventually. Gomega will then repeatedly check the same error value rather than re-calling the function. Wrap it in a closure:
🐛 Proposed fix
- Eventually(checkConfigMap(ctx, coreCMName)).Should(Satisfy(apierrors.IsNotFound))
+ Eventually(func() error { return checkConfigMap(ctx, coreCMName) }).Should(Satisfy(apierrors.IsNotFound))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Eventually(checkConfigMap(ctx, coreCMName)).Should(Satisfy(apierrors.IsNotFound)) | |
| Eventually(func() error { return checkConfigMap(ctx, coreCMName) }).Should(Satisfy(apierrors.IsNotFound)) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/controllers/installer/installer_controller_test.go` at line 179, The test
is calling checkConfigMap(ctx, coreCMName) immediately and passing its error
result to Eventually, so Gomega polls a fixed value; change the Eventually
argument to a closure that calls checkConfigMap each poll (e.g., pass func()
error { return checkConfigMap(ctx, coreCMName) }) and keep the existing
Should(Satisfy(apierrors.IsNotFound)) assertion so Eventually re-evaluates the
checkConfigMap call on each retry.
There was a problem hiding this comment.
I have reworked this test entirely. Expecting to observe not found is a race.
| if len(clusterAPI.Status.Revisions) == 0 { | ||
| if err := writeRelatedObjects(ctx, c.client, staticRelatedObjects()); err != nil { | ||
| return opresult.Error(fmt.Errorf("writing relatedObjects: %w", err)) | ||
| } | ||
|
|
||
| return opresult.WaitingOnExternal("ClusterAPI revisions") | ||
| } |
There was a problem hiding this comment.
Clear stale tracking-cache watches when revisions disappear.
This branch returns before updateWatches(). If status.revisions goes from non-empty to empty, the old GVK watches stay registered and keep enqueueing reconciles for resources that are no longer part of the desired state.
Proposed fix
if len(clusterAPI.Status.Revisions) == 0 {
+ if err := c.updateWatches(ctx, log, clusterAPI, sets.New[schema.GroupVersionKind]()); err != nil {
+ return opresult.Error(err)
+ }
+
if err := writeRelatedObjects(ctx, c.client, staticRelatedObjects()); err != nil {
return opresult.Error(fmt.Errorf("writing relatedObjects: %w", err))
}
return opresult.WaitingOnExternal("ClusterAPI revisions")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if len(clusterAPI.Status.Revisions) == 0 { | |
| if err := writeRelatedObjects(ctx, c.client, staticRelatedObjects()); err != nil { | |
| return opresult.Error(fmt.Errorf("writing relatedObjects: %w", err)) | |
| } | |
| return opresult.WaitingOnExternal("ClusterAPI revisions") | |
| } | |
| if len(clusterAPI.Status.Revisions) == 0 { | |
| if err := c.updateWatches(ctx, log, clusterAPI, sets.New[schema.GroupVersionKind]()); err != nil { | |
| return opresult.Error(err) | |
| } | |
| if err := writeRelatedObjects(ctx, c.client, staticRelatedObjects()); err != nil { | |
| return opresult.Error(fmt.Errorf("writing relatedObjects: %w", err)) | |
| } | |
| return opresult.WaitingOnExternal("ClusterAPI revisions") | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/controllers/installer/installer_controller.go` around lines 203 - 209,
The early return when clusterAPI.Status.Revisions is empty skips calling
updateWatches(), leaving stale tracking-cache watches registered; change the
branch so that before returning (after
writeRelatedObjects/staticRelatedObjects), you invoke updateWatches(...) to
clear or reconcile watches for the now-empty revisions set (i.e., call the
controller's updateWatches(ctx, ...) / tracking-cache cleanup function using the
current Cluster API object), then return opresult.WaitingOnExternal("ClusterAPI
revisions"); ensure you reference clusterAPI.Status.Revisions and
updateWatches() so the watches are updated even when revisions go from non-empty
to empty.
There was a problem hiding this comment.
Revisions can never become empty after it has been non-empty.
| Should(HaveField("Data", HaveKeyWithValue("version", "v1"))) | ||
| }, defaultNodeTimeout) | ||
|
|
||
| It("re-creates a deleted managed object", func(ctx context.Context) { |
There was a problem hiding this comment.
same here - event? too noisy?
| waitForRelatedObjects(ctx, Not(BeEmpty())) | ||
|
|
||
| initial := getRelatedObjects(ctx) | ||
| Expect(initial).To(HaveLen(10 + len(staticRelatedObjects()))) |
| }) | ||
|
|
||
| var _ = Describe("InstallerController without ClusterAPI", Serial, func() { | ||
| It("reports WaitingOnExternal when ClusterAPI does not exist", func(ctx context.Context) { |
There was a problem hiding this comment.
probably duplicate test / tests already tested code path?
|
The e2e-openstack-ovn-techpreview failure is because we missed ORC when upgrading CAPO. I've submitted a PR for it here: openshift/openstack-resource-controller#30 |
1812b00 to
a404b74
Compare
|
For now, I've removed the commit which removes capiinstaller. capiinstaller should continue to run and install the ORC manifests for CAPO. |
|
Scheduling required tests: Scheduling tests matching the |
|
Infra flake (no lease): |
|
/test e2e-vsphere-capi-techpreview |
|
/test e2e-aws-ovn |
| } | ||
|
|
||
| revision := conv.revision | ||
| bcRevision := toBoxcutterRevision(revision) |
| waiting := phase.Waiting() | ||
|
|
||
| // Logging gone objects is currently problematic due to | ||
| // https://github.com/package-operator/boxcutter/issues/497 |
|
/verified by CI and manual testing |
|
@mdbooth: This PR has been marked as verified by DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Permafailing: /override pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-ovn-techpreview |
|
@mdbooth: Overrode contexts on behalf of mdbooth: ci/prow/e2e-openstack-ovn-techpreview DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
/lgtm looks good - a few nits /comments but nothing blocking. |
|
/approve Lets ship this, CI is green and we won't work out whats broken if we don't |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: theobarberbany The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
@mdbooth: The following test failed, say
Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
ee07af3
into
openshift:main
No description provided.