From 4308d5640497bfeff93c45b853012ad126f747aa Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Mon, 17 Mar 2025 12:49:32 -0400 Subject: [PATCH 1/3] WIP: vendor library-go/api PRs Signed-off-by: Peter Hunt --- go.mod | 7 +- go.sum | 10 +- .../github.com/evanphx/json-patch/.gitignore | 6 - vendor/github.com/evanphx/json-patch/LICENSE | 25 - .../github.com/evanphx/json-patch/README.md | 317 ------- .../github.com/evanphx/json-patch/errors.go | 38 - vendor/github.com/evanphx/json-patch/merge.go | 389 --------- vendor/github.com/evanphx/json-patch/patch.go | 809 ------------------ .../github.com/openshift/api/.golangci.yaml | 2 + .../openshift/api/config/v1/types_feature.go | 47 + .../openshift/api/config/v1/types_node.go | 26 +- ...r_01_featuregates-CustomNoUpgrade.crd.yaml | 339 ++++++++ ...operator_01_featuregates-Default.crd.yaml} | 1 + ..._featuregates-DevPreviewNoUpgrade.crd.yaml | 339 ++++++++ ...featuregates-TechPreviewNoUpgrade.crd.yaml | 339 ++++++++ ...operator_01_nodes-CustomNoUpgrade.crd.yaml | 25 + ..._config-operator_01_nodes-Default.crd.yaml | 1 + ...ator_01_nodes-DevPreviewNoUpgrade.crd.yaml | 25 + ...tor_01_nodes-TechPreviewNoUpgrade.crd.yaml | 25 + .../api/config/v1/zz_generated.deepcopy.go | 32 +- ..._generated.featuregated-crd-manifests.yaml | 3 +- .../v1/zz_generated.swagger_doc_generated.go | 23 +- .../openshift/api/features/features.go | 3 + .../github.com/openshift/api/features/util.go | 51 +- .../v1alpha1/types_machineconfignode.go | 162 ++-- ...achineconfignodes-CustomNoUpgrade.crd.yaml | 176 ++-- ...neconfignodes-DevPreviewNoUpgrade.crd.yaml | 176 ++-- ...econfignodes-TechPreviewNoUpgrade.crd.yaml | 176 ++-- .../v1alpha1/zz_generated.deepcopy.go | 32 +- ..._generated.featuregated-crd-manifests.yaml | 10 +- .../zz_generated.swagger_doc_generated.go | 57 +- .../api/payload-command/render/render.go | 126 ++- .../render/write_featureset.go | 9 +- .../pkg/operator/certrotation/annotations.go | 8 + .../pkg/operator/certrotation/cabundle.go | 21 +- .../client_cert_rotation_controller.go | 2 +- .../pkg/operator/certrotation/signer.go | 14 +- .../pkg/operator/certrotation/target.go | 13 +- .../featuregates/featuregate.go | 19 +- .../hardcoded_featuregate_reader.go | 3 +- .../featuregates/simple_featuregate_reader.go | 14 +- .../resourceapply/json_patch_helpers.go | 2 +- .../resource/resourceread/apiregistration.go | 26 + vendor/modules.txt | 9 +- 44 files changed, 1886 insertions(+), 2051 deletions(-) delete mode 100644 vendor/github.com/evanphx/json-patch/.gitignore delete mode 100644 vendor/github.com/evanphx/json-patch/LICENSE delete mode 100644 vendor/github.com/evanphx/json-patch/README.md delete mode 100644 vendor/github.com/evanphx/json-patch/errors.go delete mode 100644 vendor/github.com/evanphx/json-patch/merge.go delete mode 100644 vendor/github.com/evanphx/json-patch/patch.go create mode 100644 vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-CustomNoUpgrade.crd.yaml rename vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/{0000_10_config-operator_01_featuregates.crd.yaml => 0000_10_config-operator_01_featuregates-Default.crd.yaml} (99%) create mode 100644 vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-DevPreviewNoUpgrade.crd.yaml create mode 100644 vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-TechPreviewNoUpgrade.crd.yaml create mode 100644 vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiregistration.go diff --git a/go.mod b/go.mod index 82a51195ec..4a8e797c0e 100644 --- a/go.mod +++ b/go.mod @@ -194,7 +194,6 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/ettle/strcase v0.2.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fatih/structtag v1.2.0 // indirect @@ -349,4 +348,8 @@ require ( sigs.k8s.io/yaml v1.4.0 ) -replace k8s.io/kube-openapi => github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0 +replace ( + github.com/openshift/api => github.com/haircommander/api v0.0.0-20250326145233-4e692eb778c9 + github.com/openshift/library-go => github.com/haircommander/library-go v0.0.0-20250320175542-74e1e32dfa76 + k8s.io/kube-openapi => github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0 +) diff --git a/go.sum b/go.sum index faa3da68a6..cc256babc4 100644 --- a/go.sum +++ b/go.sum @@ -175,8 +175,6 @@ github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtz github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= @@ -353,6 +351,10 @@ github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+ github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/haircommander/api v0.0.0-20250326145233-4e692eb778c9 h1:jIXShZeM5WspAIoEUrn4LiX7wUGgRB9DbhJQ2ja6/8s= +github.com/haircommander/api v0.0.0-20250326145233-4e692eb778c9/go.mod h1:nEKlkdw/X9V+7gyPxl/ZeP7T14q8e1EvmQ/XsIHVZ90= +github.com/haircommander/library-go v0.0.0-20250320175542-74e1e32dfa76 h1:wR5ZTd7JUYf6rrYe2X3Cq4KqoXvu0kOB8GBvrH7y+GM= +github.com/haircommander/library-go v0.0.0-20250320175542-74e1e32dfa76/go.mod h1:Z7PxlyxJDS5OZBapcjOi9ARH1eCmhCn1jt3v7apEyuU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -513,14 +515,10 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/openshift/api v0.0.0-20250402094343-3d7abe90f97e h1:+nJrGJMAhBH8yhXe7u3z44IWA/kHtzgjmpOAry+aeb4= -github.com/openshift/api v0.0.0-20250402094343-3d7abe90f97e/go.mod h1:yk60tHAmHhtVpJQo3TwVYq2zpuP70iJIFDCmeKMIzPw= github.com/openshift/client-go v0.0.0-20250402181141-b3bad3b645f2 h1:bPXR0R8zp1o12nSUphN26hSM+OKYq5pMorbDCpApzDQ= github.com/openshift/client-go v0.0.0-20250402181141-b3bad3b645f2/go.mod h1:dT1cJyVTperQ53GvVRa+GZ27r02fDZy2k5j+9QoQsCo= github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0 h1:GPlAy197Jkr+D0T2FNWanamraTdzS/r9ZkT29lxvHaA= github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -github.com/openshift/library-go v0.0.0-20250129210218-fe56c2cf5d70 h1:VLj8CU9q009xlMuR4wNcqDX4lVa2Ji3u/iYnBLHtQUc= -github.com/openshift/library-go v0.0.0-20250129210218-fe56c2cf5d70/go.mod h1:TQx0VEhZ/92qRXIMDu2Wg4bUPmw5HRNE6wpSZ+IsP0Y= github.com/openshift/runtime-utils v0.0.0-20230921210328-7bdb5b9c177b h1:oXzC1N6E9gw76/WH2gEA8GEHvuq09wuVQ9GoCuR8GF4= github.com/openshift/runtime-utils v0.0.0-20230921210328-7bdb5b9c177b/go.mod h1:l9/qeKZuAmYUMl0yicJlbkPGDsIycGhwxOvOAWyaP0E= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= diff --git a/vendor/github.com/evanphx/json-patch/.gitignore b/vendor/github.com/evanphx/json-patch/.gitignore deleted file mode 100644 index b7ed7f956d..0000000000 --- a/vendor/github.com/evanphx/json-patch/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# editor and IDE paraphernalia -.idea -.vscode - -# macOS paraphernalia -.DS_Store diff --git a/vendor/github.com/evanphx/json-patch/LICENSE b/vendor/github.com/evanphx/json-patch/LICENSE deleted file mode 100644 index df76d7d771..0000000000 --- a/vendor/github.com/evanphx/json-patch/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2014, Evan Phoenix -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of the Evan Phoenix nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/evanphx/json-patch/README.md b/vendor/github.com/evanphx/json-patch/README.md deleted file mode 100644 index 28e3516937..0000000000 --- a/vendor/github.com/evanphx/json-patch/README.md +++ /dev/null @@ -1,317 +0,0 @@ -# JSON-Patch -`jsonpatch` is a library which provides functionality for both applying -[RFC6902 JSON patches](http://tools.ietf.org/html/rfc6902) against documents, as -well as for calculating & applying [RFC7396 JSON merge patches](https://tools.ietf.org/html/rfc7396). - -[![GoDoc](https://godoc.org/github.com/evanphx/json-patch?status.svg)](http://godoc.org/github.com/evanphx/json-patch) -[![Build Status](https://travis-ci.org/evanphx/json-patch.svg?branch=master)](https://travis-ci.org/evanphx/json-patch) -[![Report Card](https://goreportcard.com/badge/github.com/evanphx/json-patch)](https://goreportcard.com/report/github.com/evanphx/json-patch) - -# Get It! - -**Latest and greatest**: -```bash -go get -u github.com/evanphx/json-patch/v5 -``` - -**Stable Versions**: -* Version 5: `go get -u gopkg.in/evanphx/json-patch.v5` -* Version 4: `go get -u gopkg.in/evanphx/json-patch.v4` - -(previous versions below `v3` are unavailable) - -# Use It! -* [Create and apply a merge patch](#create-and-apply-a-merge-patch) -* [Create and apply a JSON Patch](#create-and-apply-a-json-patch) -* [Comparing JSON documents](#comparing-json-documents) -* [Combine merge patches](#combine-merge-patches) - - -# Configuration - -* There is a global configuration variable `jsonpatch.SupportNegativeIndices`. - This defaults to `true` and enables the non-standard practice of allowing - negative indices to mean indices starting at the end of an array. This - functionality can be disabled by setting `jsonpatch.SupportNegativeIndices = - false`. - -* There is a global configuration variable `jsonpatch.AccumulatedCopySizeLimit`, - which limits the total size increase in bytes caused by "copy" operations in a - patch. It defaults to 0, which means there is no limit. - -These global variables control the behavior of `jsonpatch.Apply`. - -An alternative to `jsonpatch.Apply` is `jsonpatch.ApplyWithOptions` whose behavior -is controlled by an `options` parameter of type `*jsonpatch.ApplyOptions`. - -Structure `jsonpatch.ApplyOptions` includes the configuration options above -and adds two new options: `AllowMissingPathOnRemove` and `EnsurePathExistsOnAdd`. - -When `AllowMissingPathOnRemove` is set to `true`, `jsonpatch.ApplyWithOptions` will ignore -`remove` operations whose `path` points to a non-existent location in the JSON document. -`AllowMissingPathOnRemove` defaults to `false` which will lead to `jsonpatch.ApplyWithOptions` -returning an error when hitting a missing `path` on `remove`. - -When `EnsurePathExistsOnAdd` is set to `true`, `jsonpatch.ApplyWithOptions` will make sure -that `add` operations produce all the `path` elements that are missing from the target object. - -Use `jsonpatch.NewApplyOptions` to create an instance of `jsonpatch.ApplyOptions` -whose values are populated from the global configuration variables. - -## Create and apply a merge patch -Given both an original JSON document and a modified JSON document, you can create -a [Merge Patch](https://tools.ietf.org/html/rfc7396) document. - -It can describe the changes needed to convert from the original to the -modified JSON document. - -Once you have a merge patch, you can apply it to other JSON documents using the -`jsonpatch.MergePatch(document, patch)` function. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - // Let's create a merge patch from these two documents... - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - target := []byte(`{"name": "Jane", "age": 24}`) - - patch, err := jsonpatch.CreateMergePatch(original, target) - if err != nil { - panic(err) - } - - // Now lets apply the patch against a different JSON document... - - alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`) - modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch) - - fmt.Printf("patch document: %s\n", patch) - fmt.Printf("updated alternative doc: %s\n", modifiedAlternative) -} -``` - -When ran, you get the following output: - -```bash -$ go run main.go -patch document: {"height":null,"name":"Jane"} -updated alternative doc: {"age":28,"name":"Jane"} -``` - -## Create and apply a JSON Patch -You can create patch objects using `DecodePatch([]byte)`, which can then -be applied against JSON documents. - -The following is an example of creating a patch from two operations, and -applying it against a JSON document. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - patchJSON := []byte(`[ - {"op": "replace", "path": "/name", "value": "Jane"}, - {"op": "remove", "path": "/height"} - ]`) - - patch, err := jsonpatch.DecodePatch(patchJSON) - if err != nil { - panic(err) - } - - modified, err := patch.Apply(original) - if err != nil { - panic(err) - } - - fmt.Printf("Original document: %s\n", original) - fmt.Printf("Modified document: %s\n", modified) -} -``` - -When ran, you get the following output: - -```bash -$ go run main.go -Original document: {"name": "John", "age": 24, "height": 3.21} -Modified document: {"age":24,"name":"Jane"} -``` - -## Comparing JSON documents -Due to potential whitespace and ordering differences, one cannot simply compare -JSON strings or byte-arrays directly. - -As such, you can instead use `jsonpatch.Equal(document1, document2)` to -determine if two JSON documents are _structurally_ equal. This ignores -whitespace differences, and key-value ordering. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - similar := []byte(` - { - "age": 24, - "height": 3.21, - "name": "John" - } - `) - different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`) - - if jsonpatch.Equal(original, similar) { - fmt.Println(`"original" is structurally equal to "similar"`) - } - - if !jsonpatch.Equal(original, different) { - fmt.Println(`"original" is _not_ structurally equal to "different"`) - } -} -``` - -When ran, you get the following output: -```bash -$ go run main.go -"original" is structurally equal to "similar" -"original" is _not_ structurally equal to "different" -``` - -## Combine merge patches -Given two JSON merge patch documents, it is possible to combine them into a -single merge patch which can describe both set of changes. - -The resulting merge patch can be used such that applying it results in a -document structurally similar as merging each merge patch to the document -in succession. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - - nameAndHeight := []byte(`{"height":null,"name":"Jane"}`) - ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`) - - // Let's combine these merge patch documents... - combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes) - if err != nil { - panic(err) - } - - // Apply each patch individual against the original document - withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight) - if err != nil { - panic(err) - } - - withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes) - if err != nil { - panic(err) - } - - // Apply the combined patch against the original document - - withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch) - if err != nil { - panic(err) - } - - // Do both result in the same thing? They should! - if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) { - fmt.Println("Both JSON documents are structurally the same!") - } - - fmt.Printf("combined merge patch: %s", combinedPatch) -} -``` - -When ran, you get the following output: -```bash -$ go run main.go -Both JSON documents are structurally the same! -combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"} -``` - -# CLI for comparing JSON documents -You can install the commandline program `json-patch`. - -This program can take multiple JSON patch documents as arguments, -and fed a JSON document from `stdin`. It will apply the patch(es) against -the document and output the modified doc. - -**patch.1.json** -```json -[ - {"op": "replace", "path": "/name", "value": "Jane"}, - {"op": "remove", "path": "/height"} -] -``` - -**patch.2.json** -```json -[ - {"op": "add", "path": "/address", "value": "123 Main St"}, - {"op": "replace", "path": "/age", "value": "21"} -] -``` - -**document.json** -```json -{ - "name": "John", - "age": 24, - "height": 3.21 -} -``` - -You can then run: - -```bash -$ go install github.com/evanphx/json-patch/cmd/json-patch -$ cat document.json | json-patch -p patch.1.json -p patch.2.json -{"address":"123 Main St","age":"21","name":"Jane"} -``` - -# Help It! -Contributions are welcomed! Leave [an issue](https://github.com/evanphx/json-patch/issues) -or [create a PR](https://github.com/evanphx/json-patch/compare). - - -Before creating a pull request, we'd ask that you make sure tests are passing -and that you have added new tests when applicable. - -Contributors can run tests using: - -```bash -go test -cover ./... -``` - -Builds for pull requests are tested automatically -using [TravisCI](https://travis-ci.org/evanphx/json-patch). diff --git a/vendor/github.com/evanphx/json-patch/errors.go b/vendor/github.com/evanphx/json-patch/errors.go deleted file mode 100644 index 75304b4437..0000000000 --- a/vendor/github.com/evanphx/json-patch/errors.go +++ /dev/null @@ -1,38 +0,0 @@ -package jsonpatch - -import "fmt" - -// AccumulatedCopySizeError is an error type returned when the accumulated size -// increase caused by copy operations in a patch operation has exceeded the -// limit. -type AccumulatedCopySizeError struct { - limit int64 - accumulated int64 -} - -// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError. -func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError { - return &AccumulatedCopySizeError{limit: l, accumulated: a} -} - -// Error implements the error interface. -func (a *AccumulatedCopySizeError) Error() string { - return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit) -} - -// ArraySizeError is an error type returned when the array size has exceeded -// the limit. -type ArraySizeError struct { - limit int - size int -} - -// NewArraySizeError returns an ArraySizeError. -func NewArraySizeError(l, s int) *ArraySizeError { - return &ArraySizeError{limit: l, size: s} -} - -// Error implements the error interface. -func (a *ArraySizeError) Error() string { - return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit) -} diff --git a/vendor/github.com/evanphx/json-patch/merge.go b/vendor/github.com/evanphx/json-patch/merge.go deleted file mode 100644 index ad88d40181..0000000000 --- a/vendor/github.com/evanphx/json-patch/merge.go +++ /dev/null @@ -1,389 +0,0 @@ -package jsonpatch - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" -) - -func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode { - curDoc, err := cur.intoDoc() - - if err != nil { - pruneNulls(patch) - return patch - } - - patchDoc, err := patch.intoDoc() - - if err != nil { - return patch - } - - mergeDocs(curDoc, patchDoc, mergeMerge) - - return cur -} - -func mergeDocs(doc, patch *partialDoc, mergeMerge bool) { - for k, v := range *patch { - if v == nil { - if mergeMerge { - (*doc)[k] = nil - } else { - delete(*doc, k) - } - } else { - cur, ok := (*doc)[k] - - if !ok || cur == nil { - if !mergeMerge { - pruneNulls(v) - } - - (*doc)[k] = v - } else { - (*doc)[k] = merge(cur, v, mergeMerge) - } - } - } -} - -func pruneNulls(n *lazyNode) { - sub, err := n.intoDoc() - - if err == nil { - pruneDocNulls(sub) - } else { - ary, err := n.intoAry() - - if err == nil { - pruneAryNulls(ary) - } - } -} - -func pruneDocNulls(doc *partialDoc) *partialDoc { - for k, v := range *doc { - if v == nil { - delete(*doc, k) - } else { - pruneNulls(v) - } - } - - return doc -} - -func pruneAryNulls(ary *partialArray) *partialArray { - newAry := []*lazyNode{} - - for _, v := range *ary { - if v != nil { - pruneNulls(v) - } - newAry = append(newAry, v) - } - - *ary = newAry - - return ary -} - -var ErrBadJSONDoc = fmt.Errorf("Invalid JSON Document") -var ErrBadJSONPatch = fmt.Errorf("Invalid JSON Patch") -var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents") - -// MergeMergePatches merges two merge patches together, such that -// applying this resulting merged merge patch to a document yields the same -// as merging each merge patch to the document in succession. -func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) { - return doMergePatch(patch1Data, patch2Data, true) -} - -// MergePatch merges the patchData into the docData. -func MergePatch(docData, patchData []byte) ([]byte, error) { - return doMergePatch(docData, patchData, false) -} - -func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) { - doc := &partialDoc{} - - docErr := json.Unmarshal(docData, doc) - - patch := &partialDoc{} - - patchErr := json.Unmarshal(patchData, patch) - - if _, ok := docErr.(*json.SyntaxError); ok { - return nil, ErrBadJSONDoc - } - - if _, ok := patchErr.(*json.SyntaxError); ok { - return nil, ErrBadJSONPatch - } - - if docErr == nil && *doc == nil { - return nil, ErrBadJSONDoc - } - - if patchErr == nil && *patch == nil { - return nil, ErrBadJSONPatch - } - - if docErr != nil || patchErr != nil { - // Not an error, just not a doc, so we turn straight into the patch - if patchErr == nil { - if mergeMerge { - doc = patch - } else { - doc = pruneDocNulls(patch) - } - } else { - patchAry := &partialArray{} - patchErr = json.Unmarshal(patchData, patchAry) - - if patchErr != nil { - return nil, ErrBadJSONPatch - } - - pruneAryNulls(patchAry) - - out, patchErr := json.Marshal(patchAry) - - if patchErr != nil { - return nil, ErrBadJSONPatch - } - - return out, nil - } - } else { - mergeDocs(doc, patch, mergeMerge) - } - - return json.Marshal(doc) -} - -// resemblesJSONArray indicates whether the byte-slice "appears" to be -// a JSON array or not. -// False-positives are possible, as this function does not check the internal -// structure of the array. It only checks that the outer syntax is present and -// correct. -func resemblesJSONArray(input []byte) bool { - input = bytes.TrimSpace(input) - - hasPrefix := bytes.HasPrefix(input, []byte("[")) - hasSuffix := bytes.HasSuffix(input, []byte("]")) - - return hasPrefix && hasSuffix -} - -// CreateMergePatch will return a merge patch document capable of converting -// the original document(s) to the modified document(s). -// The parameters can be bytes of either two JSON Documents, or two arrays of -// JSON documents. -// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07 -func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalResemblesArray := resemblesJSONArray(originalJSON) - modifiedResemblesArray := resemblesJSONArray(modifiedJSON) - - // Do both byte-slices seem like JSON arrays? - if originalResemblesArray && modifiedResemblesArray { - return createArrayMergePatch(originalJSON, modifiedJSON) - } - - // Are both byte-slices are not arrays? Then they are likely JSON objects... - if !originalResemblesArray && !modifiedResemblesArray { - return createObjectMergePatch(originalJSON, modifiedJSON) - } - - // None of the above? Then return an error because of mismatched types. - return nil, errBadMergeTypes -} - -// createObjectMergePatch will return a merge-patch document capable of -// converting the original document to the modified document. -func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalDoc := map[string]interface{}{} - modifiedDoc := map[string]interface{}{} - - err := json.Unmarshal(originalJSON, &originalDoc) - if err != nil { - return nil, ErrBadJSONDoc - } - - err = json.Unmarshal(modifiedJSON, &modifiedDoc) - if err != nil { - return nil, ErrBadJSONDoc - } - - dest, err := getDiff(originalDoc, modifiedDoc) - if err != nil { - return nil, err - } - - return json.Marshal(dest) -} - -// createArrayMergePatch will return an array of merge-patch documents capable -// of converting the original document to the modified document for each -// pair of JSON documents provided in the arrays. -// Arrays of mismatched sizes will result in an error. -func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalDocs := []json.RawMessage{} - modifiedDocs := []json.RawMessage{} - - err := json.Unmarshal(originalJSON, &originalDocs) - if err != nil { - return nil, ErrBadJSONDoc - } - - err = json.Unmarshal(modifiedJSON, &modifiedDocs) - if err != nil { - return nil, ErrBadJSONDoc - } - - total := len(originalDocs) - if len(modifiedDocs) != total { - return nil, ErrBadJSONDoc - } - - result := []json.RawMessage{} - for i := 0; i < len(originalDocs); i++ { - original := originalDocs[i] - modified := modifiedDocs[i] - - patch, err := createObjectMergePatch(original, modified) - if err != nil { - return nil, err - } - - result = append(result, json.RawMessage(patch)) - } - - return json.Marshal(result) -} - -// Returns true if the array matches (must be json types). -// As is idiomatic for go, an empty array is not the same as a nil array. -func matchesArray(a, b []interface{}) bool { - if len(a) != len(b) { - return false - } - if (a == nil && b != nil) || (a != nil && b == nil) { - return false - } - for i := range a { - if !matchesValue(a[i], b[i]) { - return false - } - } - return true -} - -// Returns true if the values matches (must be json types) -// The types of the values must match, otherwise it will always return false -// If two map[string]interface{} are given, all elements must match. -func matchesValue(av, bv interface{}) bool { - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - return false - } - switch at := av.(type) { - case string: - bt := bv.(string) - if bt == at { - return true - } - case float64: - bt := bv.(float64) - if bt == at { - return true - } - case bool: - bt := bv.(bool) - if bt == at { - return true - } - case nil: - // Both nil, fine. - return true - case map[string]interface{}: - bt := bv.(map[string]interface{}) - if len(bt) != len(at) { - return false - } - for key := range bt { - av, aOK := at[key] - bv, bOK := bt[key] - if aOK != bOK { - return false - } - if !matchesValue(av, bv) { - return false - } - } - return true - case []interface{}: - bt := bv.([]interface{}) - return matchesArray(at, bt) - } - return false -} - -// getDiff returns the (recursive) difference between a and b as a map[string]interface{}. -func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { - into := map[string]interface{}{} - for key, bv := range b { - av, ok := a[key] - // value was added - if !ok { - into[key] = bv - continue - } - // If types have changed, replace completely - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - into[key] = bv - continue - } - // Types are the same, compare values - switch at := av.(type) { - case map[string]interface{}: - bt := bv.(map[string]interface{}) - dst := make(map[string]interface{}, len(bt)) - dst, err := getDiff(at, bt) - if err != nil { - return nil, err - } - if len(dst) > 0 { - into[key] = dst - } - case string, float64, bool: - if !matchesValue(av, bv) { - into[key] = bv - } - case []interface{}: - bt := bv.([]interface{}) - if !matchesArray(at, bt) { - into[key] = bv - } - case nil: - switch bv.(type) { - case nil: - // Both nil, fine. - default: - into[key] = bv - } - default: - panic(fmt.Sprintf("Unknown type:%T in key %s", av, key)) - } - } - // Now add all deleted values as nil - for key := range a { - _, found := b[key] - if !found { - into[key] = nil - } - } - return into, nil -} diff --git a/vendor/github.com/evanphx/json-patch/patch.go b/vendor/github.com/evanphx/json-patch/patch.go deleted file mode 100644 index 4bce5936d5..0000000000 --- a/vendor/github.com/evanphx/json-patch/patch.go +++ /dev/null @@ -1,809 +0,0 @@ -package jsonpatch - -import ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -const ( - eRaw = iota - eDoc - eAry -) - -var ( - // SupportNegativeIndices decides whether to support non-standard practice of - // allowing negative indices to mean indices starting at the end of an array. - // Default to true. - SupportNegativeIndices bool = true - // AccumulatedCopySizeLimit limits the total size increase in bytes caused by - // "copy" operations in a patch. - AccumulatedCopySizeLimit int64 = 0 -) - -var ( - ErrTestFailed = errors.New("test failed") - ErrMissing = errors.New("missing value") - ErrUnknownType = errors.New("unknown object type") - ErrInvalid = errors.New("invalid state detected") - ErrInvalidIndex = errors.New("invalid index referenced") -) - -type lazyNode struct { - raw *json.RawMessage - doc partialDoc - ary partialArray - which int -} - -// Operation is a single JSON-Patch step, such as a single 'add' operation. -type Operation map[string]*json.RawMessage - -// Patch is an ordered collection of Operations. -type Patch []Operation - -type partialDoc map[string]*lazyNode -type partialArray []*lazyNode - -type container interface { - get(key string) (*lazyNode, error) - set(key string, val *lazyNode) error - add(key string, val *lazyNode) error - remove(key string) error -} - -func newLazyNode(raw *json.RawMessage) *lazyNode { - return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw} -} - -func (n *lazyNode) MarshalJSON() ([]byte, error) { - switch n.which { - case eRaw: - return json.Marshal(n.raw) - case eDoc: - return json.Marshal(n.doc) - case eAry: - return json.Marshal(n.ary) - default: - return nil, ErrUnknownType - } -} - -func (n *lazyNode) UnmarshalJSON(data []byte) error { - dest := make(json.RawMessage, len(data)) - copy(dest, data) - n.raw = &dest - n.which = eRaw - return nil -} - -func deepCopy(src *lazyNode) (*lazyNode, int, error) { - if src == nil { - return nil, 0, nil - } - a, err := src.MarshalJSON() - if err != nil { - return nil, 0, err - } - sz := len(a) - ra := make(json.RawMessage, sz) - copy(ra, a) - return newLazyNode(&ra), sz, nil -} - -func (n *lazyNode) intoDoc() (*partialDoc, error) { - if n.which == eDoc { - return &n.doc, nil - } - - if n.raw == nil { - return nil, ErrInvalid - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return nil, err - } - - n.which = eDoc - return &n.doc, nil -} - -func (n *lazyNode) intoAry() (*partialArray, error) { - if n.which == eAry { - return &n.ary, nil - } - - if n.raw == nil { - return nil, ErrInvalid - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return nil, err - } - - n.which = eAry - return &n.ary, nil -} - -func (n *lazyNode) compact() []byte { - buf := &bytes.Buffer{} - - if n.raw == nil { - return nil - } - - err := json.Compact(buf, *n.raw) - - if err != nil { - return *n.raw - } - - return buf.Bytes() -} - -func (n *lazyNode) tryDoc() bool { - if n.raw == nil { - return false - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return false - } - - n.which = eDoc - return true -} - -func (n *lazyNode) tryAry() bool { - if n.raw == nil { - return false - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return false - } - - n.which = eAry - return true -} - -func (n *lazyNode) equal(o *lazyNode) bool { - if n.which == eRaw { - if !n.tryDoc() && !n.tryAry() { - if o.which != eRaw { - return false - } - - return bytes.Equal(n.compact(), o.compact()) - } - } - - if n.which == eDoc { - if o.which == eRaw { - if !o.tryDoc() { - return false - } - } - - if o.which != eDoc { - return false - } - - if len(n.doc) != len(o.doc) { - return false - } - - for k, v := range n.doc { - ov, ok := o.doc[k] - - if !ok { - return false - } - - if (v == nil) != (ov == nil) { - return false - } - - if v == nil && ov == nil { - continue - } - - if !v.equal(ov) { - return false - } - } - - return true - } - - if o.which != eAry && !o.tryAry() { - return false - } - - if len(n.ary) != len(o.ary) { - return false - } - - for idx, val := range n.ary { - if !val.equal(o.ary[idx]) { - return false - } - } - - return true -} - -// Kind reads the "op" field of the Operation. -func (o Operation) Kind() string { - if obj, ok := o["op"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown" - } - - return op - } - - return "unknown" -} - -// Path reads the "path" field of the Operation. -func (o Operation) Path() (string, error) { - if obj, ok := o["path"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown", err - } - - return op, nil - } - - return "unknown", errors.Wrapf(ErrMissing, "operation missing path field") -} - -// From reads the "from" field of the Operation. -func (o Operation) From() (string, error) { - if obj, ok := o["from"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown", err - } - - return op, nil - } - - return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field") -} - -func (o Operation) value() *lazyNode { - if obj, ok := o["value"]; ok { - return newLazyNode(obj) - } - - return nil -} - -// ValueInterface decodes the operation value into an interface. -func (o Operation) ValueInterface() (interface{}, error) { - if obj, ok := o["value"]; ok && obj != nil { - var v interface{} - - err := json.Unmarshal(*obj, &v) - - if err != nil { - return nil, err - } - - return v, nil - } - - return nil, errors.Wrapf(ErrMissing, "operation, missing value field") -} - -func isArray(buf []byte) bool { -Loop: - for _, c := range buf { - switch c { - case ' ': - case '\n': - case '\t': - continue - case '[': - return true - default: - break Loop - } - } - - return false -} - -func findObject(pd *container, path string) (container, string) { - doc := *pd - - split := strings.Split(path, "/") - - if len(split) < 2 { - return nil, "" - } - - parts := split[1 : len(split)-1] - - key := split[len(split)-1] - - var err error - - for _, part := range parts { - - next, ok := doc.get(decodePatchKey(part)) - - if next == nil || ok != nil { - return nil, "" - } - - if isArray(*next.raw) { - doc, err = next.intoAry() - - if err != nil { - return nil, "" - } - } else { - doc, err = next.intoDoc() - - if err != nil { - return nil, "" - } - } - } - - return doc, decodePatchKey(key) -} - -func (d *partialDoc) set(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) add(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) get(key string) (*lazyNode, error) { - return (*d)[key], nil -} - -func (d *partialDoc) remove(key string) error { - _, ok := (*d)[key] - if !ok { - return errors.Wrapf(ErrMissing, "Unable to remove nonexistent key: %s", key) - } - - delete(*d, key) - return nil -} - -// set should only be used to implement the "replace" operation, so "key" must -// be an already existing index in "d". -func (d *partialArray) set(key string, val *lazyNode) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(*d) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(*d) - } - - (*d)[idx] = val - return nil -} - -func (d *partialArray) add(key string, val *lazyNode) error { - if key == "-" { - *d = append(*d, val) - return nil - } - - idx, err := strconv.Atoi(key) - if err != nil { - return errors.Wrapf(err, "value was not a proper array index: '%s'", key) - } - - sz := len(*d) + 1 - - ary := make([]*lazyNode, sz) - - cur := *d - - if idx >= len(ary) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(ary) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(ary) - } - - copy(ary[0:idx], cur[0:idx]) - ary[idx] = val - copy(ary[idx+1:], cur[idx:]) - - *d = ary - return nil -} - -func (d *partialArray) get(key string) (*lazyNode, error) { - idx, err := strconv.Atoi(key) - - if err != nil { - return nil, err - } - - if idx < 0 { - if !SupportNegativeIndices { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(*d) { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(*d) - } - - if idx >= len(*d) { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - return (*d)[idx], nil -} - -func (d *partialArray) remove(key string) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - cur := *d - - if idx >= len(cur) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(cur) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(cur) - } - - ary := make([]*lazyNode, len(cur)-1) - - copy(ary[0:idx], cur[0:idx]) - copy(ary[idx:], cur[idx+1:]) - - *d = ary - return nil - -} - -func (p Patch) add(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "add operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path) - } - - err = con.add(key, op.value()) - if err != nil { - return errors.Wrapf(err, "error in add for path: '%s'", path) - } - - return nil -} - -func (p Patch) remove(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "remove operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path) - } - - err = con.remove(key) - if err != nil { - return errors.Wrapf(err, "error in remove for path: '%s'", path) - } - - return nil -} - -func (p Patch) replace(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "replace operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path) - } - - _, ok := con.get(key) - if ok != nil { - return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path) - } - - err = con.set(key, op.value()) - if err != nil { - return errors.Wrapf(err, "error in remove for path: '%s'", path) - } - - return nil -} - -func (p Patch) move(doc *container, op Operation) error { - from, err := op.From() - if err != nil { - return errors.Wrapf(err, "move operation failed to decode from") - } - - con, key := findObject(doc, from) - - if con == nil { - return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", key) - } - - err = con.remove(key) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", key) - } - - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "move operation failed to decode path") - } - - con, key = findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path) - } - - err = con.add(key, val) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", path) - } - - return nil -} - -func (p Patch) test(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "test operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in test for path: '%s'", path) - } - - if val == nil { - if op.value().raw == nil { - return nil - } - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } else if op.value() == nil { - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } - - if val.equal(op.value()) { - return nil - } - - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) -} - -func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error { - from, err := op.From() - if err != nil { - return errors.Wrapf(err, "copy operation failed to decode from") - } - - con, key := findObject(doc, from) - - if con == nil { - return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in copy for from: '%s'", from) - } - - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "copy operation failed to decode path") - } - - con, key = findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path) - } - - valCopy, sz, err := deepCopy(val) - if err != nil { - return errors.Wrapf(err, "error while performing deep copy") - } - - (*accumulatedCopySize) += int64(sz) - if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit { - return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize) - } - - err = con.add(key, valCopy) - if err != nil { - return errors.Wrapf(err, "error while adding value during copy") - } - - return nil -} - -// Equal indicates if 2 JSON documents have the same structural equality. -func Equal(a, b []byte) bool { - ra := make(json.RawMessage, len(a)) - copy(ra, a) - la := newLazyNode(&ra) - - rb := make(json.RawMessage, len(b)) - copy(rb, b) - lb := newLazyNode(&rb) - - return la.equal(lb) -} - -// DecodePatch decodes the passed JSON document as an RFC 6902 patch. -func DecodePatch(buf []byte) (Patch, error) { - var p Patch - - err := json.Unmarshal(buf, &p) - - if err != nil { - return nil, err - } - - return p, nil -} - -// Apply mutates a JSON document according to the patch, and returns the new -// document. -func (p Patch) Apply(doc []byte) ([]byte, error) { - return p.ApplyIndent(doc, "") -} - -// ApplyIndent mutates a JSON document according to the patch, and returns the new -// document indented. -func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { - if len(doc) == 0 { - return doc, nil - } - - var pd container - if doc[0] == '[' { - pd = &partialArray{} - } else { - pd = &partialDoc{} - } - - err := json.Unmarshal(doc, pd) - - if err != nil { - return nil, err - } - - err = nil - - var accumulatedCopySize int64 - - for _, op := range p { - switch op.Kind() { - case "add": - err = p.add(&pd, op) - case "remove": - err = p.remove(&pd, op) - case "replace": - err = p.replace(&pd, op) - case "move": - err = p.move(&pd, op) - case "test": - err = p.test(&pd, op) - case "copy": - err = p.copy(&pd, op, &accumulatedCopySize) - default: - err = fmt.Errorf("Unexpected kind: %s", op.Kind()) - } - - if err != nil { - return nil, err - } - } - - if indent != "" { - return json.MarshalIndent(pd, "", indent) - } - - return json.Marshal(pd) -} - -// From http://tools.ietf.org/html/rfc6901#section-4 : -// -// Evaluation of each reference token begins by decoding any escaped -// character sequence. This is performed by first transforming any -// occurrence of the sequence '~1' to '/', and then transforming any -// occurrence of the sequence '~0' to '~'. - -var ( - rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~") -) - -func decodePatchKey(k string) string { - return rfc6901Decoder.Replace(k) -} diff --git a/vendor/github.com/openshift/api/.golangci.yaml b/vendor/github.com/openshift/api/.golangci.yaml index 848960e946..d2d3ffd601 100644 --- a/vendor/github.com/openshift/api/.golangci.yaml +++ b/vendor/github.com/openshift/api/.golangci.yaml @@ -23,3 +23,5 @@ issues: # Want to make sure that those adding new fields have an # opportunity to fix them when running the linter locally. max-issues-per-linter: 1000 + exclude-dirs: + - features/ diff --git a/vendor/github.com/openshift/api/config/v1/types_feature.go b/vendor/github.com/openshift/api/config/v1/types_feature.go index 0709a75ae8..a648cd89c5 100644 --- a/vendor/github.com/openshift/api/config/v1/types_feature.go +++ b/vendor/github.com/openshift/api/config/v1/types_feature.go @@ -125,6 +125,15 @@ type FeatureGateDetails struct { // disabled is a list of all feature gates that are disabled in the cluster for the named version. // +optional Disabled []FeatureGateAttributes `json:"disabled"` + // renderedMinimumComponentVersions are the component versions that the feature gate list of this status were rendered from. + // Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + // feature set was rendered given the minimumKubeletVersion in the nodes.config object was lower than or equal to the given MinimumComponentVersion.Version + // +kubebuilder:validation:MaxItems:=1 + // +listType=map + // +listMapKey=component + // +openshift:enable:FeatureGate=MinimumKubeletVersion + // +optional + RenderedMinimumComponentVersions []MinimumComponentVersion `json:"renderedMinimumComponentVersions,omitempty"` } type FeatureGateAttributes struct { @@ -132,11 +141,49 @@ type FeatureGateAttributes struct { // +required Name FeatureGateName `json:"name"` + // requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + // component may be in this cluster to have this feature turned on in the Default featureset. + // Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + // this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + // or equal to the given MinimumComponentVersion.Version + // +kubebuilder:validation:MaxItems:=1 + // +listType=map + // +listMapKey=component + // +openshift:enable:FeatureGate=MinimumKubeletVersion + // +optional + RequiredMinimumComponentVersions []MinimumComponentVersion `json:"requiredMinimumComponentVersions,omitempty"` + // possible (probable?) future additions include // 1. support level (Stable, ServiceDeliveryOnly, TechPreview, DevPreview) // 2. description } +// MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component +// to enable this feature. +type MinimumComponentVersion struct { + // component is the entity whose version must be above a certain version. + // The only valid value is Kubelet + // +required + Component MinimumComponent `json:"component"` + // version is the minimum version the given component may be in this cluster. + // version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + // Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + // not the corresponding Openshift version (4.19.0) + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="minmumKubeletVersion must be in a semver compatible format of x.y.z, or empty" + // +kubebuilder:validation:MaxLength:=8 + // +required + Version string `json:"version"` +} + +// MinimumComponent is a type defining a component that can have a minimum version declared. +// Currently, the only supported value is "Kubelet". +// +kubebuilder:validation:Enum:=Kubelet +type MinimumComponent string + +// MinimumComponentKubelet can be used to define the required minimum version for kubelets. +// It will be compared against the "minimumKubeletVersion" field in the nodes.config.openshift.io object. +var MinimumComponentKubelet MinimumComponent = "Kubelet" + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). diff --git a/vendor/github.com/openshift/api/config/v1/types_node.go b/vendor/github.com/openshift/api/config/v1/types_node.go index 1282f33158..765293bfc2 100644 --- a/vendor/github.com/openshift/api/config/v1/types_node.go +++ b/vendor/github.com/openshift/api/config/v1/types_node.go @@ -72,16 +72,38 @@ type NodeStatus struct { // +listMapKey=type // +optional Conditions []metav1.Condition `json:"conditions,omitempty"` + + // minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. + // Specifically, the apiserver will deny most authorization requests of kubelets that are older + // than the specified version, only allowing the kubelet to get and update its node object, and perform + // subjectaccessreviews. + // This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, + // and will eventually be marked as not ready. + // Its max length is 8, so maximum version allowed is either "9.999.99" or "99.99.99". + // Since the kubelet reports the version of the kubernetes release, not Openshift, this field references + // the underlying kubernetes version this version of Openshift is based off of. + // In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then + // they should set the minimumKubeletVersion to 1.30.0. + // When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. + // Thus, a kubelet with version "1.0.0-ec.0" will be compatible with minimumKubeletVersion "1.0.0" or earlier. + // This status field is used to reflect the actualized minimum kubelet version, which can be interpreted from the + // FeatureGateStatus.RenderedMinimumComponentVersion when Component == Kubelet, after that FeatureGateStatus finishes rolling out to + // all kubelets. + // +kubebuilder:validation:XValidation:rule="self.matches('^[0-9]*.[0-9]*.[0-9]*$')",message="minmumKubeletVersion must be in a semver compatible format of x.y.z, or empty" + // +kubebuilder:validation:MaxLength:=8 + // +openshift:enable:FeatureGate=MinimumKubeletVersion + // +optional + MinimumKubeletVersion string `json:"minimumKubeletVersion,omitempty"` } -// +kubebuilder:validation:Enum=v2;"" +// +kubebuilder:validation:Enum=v1;v2;"" type CgroupMode string const ( CgroupModeEmpty CgroupMode = "" // Empty string indicates to honor user set value on the system that should not be overridden by OpenShift CgroupModeV1 CgroupMode = "v1" CgroupModeV2 CgroupMode = "v2" - CgroupModeDefault CgroupMode = CgroupModeV2 + CgroupModeDefault CgroupMode = CgroupModeV1 ) // +kubebuilder:validation:Enum=Default;MediumUpdateAverageReaction;LowUpdateSlowReaction diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-CustomNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-CustomNoUpgrade.crd.yaml new file mode 100644 index 0000000000..e9194e1d68 --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-CustomNoUpgrade.crd.yaml @@ -0,0 +1,339 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/470 + api.openshift.io/merged-by-featuregates: "true" + include.release.openshift.io/ibm-cloud-managed: "true" + include.release.openshift.io/self-managed-high-availability: "true" + release.openshift.io/bootstrap-required: "true" + release.openshift.io/feature-set: CustomNoUpgrade + name: featuregates.config.openshift.io +spec: + group: config.openshift.io + names: + kind: FeatureGate + listKind: FeatureGateList + plural: featuregates + singular: featuregate + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + Feature holds cluster-wide information about feature gates. The canonical name is `cluster` + + Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec holds user settable values for configuration + properties: + customNoUpgrade: + description: |- + customNoUpgrade allows the enabling or disabling of any feature. Turning this feature set on IS NOT SUPPORTED, CANNOT BE UNDONE, and PREVENTS UPGRADES. + Because of its nature, this setting cannot be validated. If you have any typos or accidentally apply invalid combinations + your cluster may fail in an unrecoverable way. featureSet must equal "CustomNoUpgrade" must be set to use this field. + nullable: true + properties: + disabled: + description: disabled is a list of all feature gates that you + want to force off + items: + description: FeatureGateName is a string to enforce patterns + on the name of a FeatureGate + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + type: array + enabled: + description: enabled is a list of all feature gates that you want + to force on + items: + description: FeatureGateName is a string to enforce patterns + on the name of a FeatureGate + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + type: array + type: object + featureSet: + description: |- + featureSet changes the list of features in the cluster. The default is empty. Be very careful adjusting this setting. + Turning on or off features may cause irreversible changes in your cluster which cannot be undone. + enum: + - CustomNoUpgrade + - DevPreviewNoUpgrade + - TechPreviewNoUpgrade + - "" + type: string + x-kubernetes-validations: + - message: CustomNoUpgrade may not be changed + rule: 'oldSelf == ''CustomNoUpgrade'' ? self == ''CustomNoUpgrade'' + : true' + - message: TechPreviewNoUpgrade may not be changed + rule: 'oldSelf == ''TechPreviewNoUpgrade'' ? self == ''TechPreviewNoUpgrade'' + : true' + - message: DevPreviewNoUpgrade may not be changed + rule: 'oldSelf == ''DevPreviewNoUpgrade'' ? self == ''DevPreviewNoUpgrade'' + : true' + type: object + x-kubernetes-validations: + - message: .spec.featureSet cannot be removed + rule: 'has(oldSelf.featureSet) ? has(self.featureSet) : true' + status: + description: status holds observed values from the cluster. They may not + be overridden. + properties: + conditions: + description: |- + conditions represent the observations of the current state. + Known .status.conditions.type are: "DeterminationDegraded" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + featureGates: + description: |- + featureGates contains a list of enabled and disabled featureGates that are keyed by payloadVersion. + Operators other than the CVO and cluster-config-operator, must read the .status.featureGates, locate + the version they are managing, find the enabled/disabled featuregates and make the operand and operator match. + The enabled/disabled values for a particular version may change during the life of the cluster as various + .spec.featureSet values are selected. + Operators may choose to restart their processes to pick up these changes, but remembering past enable/disable + lists is beyond the scope of this API and is the responsibility of individual operators. + Only featureGates with .version in the ClusterVersion.status will be present in this list. + items: + properties: + disabled: + description: disabled is a list of all feature gates that are + disabled in the cluster for the named version. + items: + properties: + name: + description: name is the name of the FeatureGate. + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + requiredMinimumComponentVersions: + description: |- + requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + component may be in this cluster to have this feature turned on in the Default featureset. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver + compatible format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + required: + - name + type: object + type: array + enabled: + description: enabled is a list of all feature gates that are + enabled in the cluster for the named version. + items: + properties: + name: + description: name is the name of the FeatureGate. + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + requiredMinimumComponentVersions: + description: |- + requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + component may be in this cluster to have this feature turned on in the Default featureset. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver + compatible format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + required: + - name + type: object + type: array + renderedMinimumComponentVersions: + description: |- + renderedMinimumComponentVersions are the component versions that the feature gate list of this status were rendered from. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + feature set was rendered given the minimumKubeletVersion in the nodes.config object was lower than or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver compatible + format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + version: + description: version matches the version provided by the ClusterVersion + and in the ClusterOperator.Status.Versions field. + type: string + required: + - version + type: object + type: array + x-kubernetes-list-map-keys: + - version + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-Default.crd.yaml similarity index 99% rename from vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates.crd.yaml rename to vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-Default.crd.yaml index 55e5ddcb2c..44dad520c0 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-Default.crd.yaml @@ -7,6 +7,7 @@ metadata: include.release.openshift.io/ibm-cloud-managed: "true" include.release.openshift.io/self-managed-high-availability: "true" release.openshift.io/bootstrap-required: "true" + release.openshift.io/feature-set: Default name: featuregates.config.openshift.io spec: group: config.openshift.io diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-DevPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-DevPreviewNoUpgrade.crd.yaml new file mode 100644 index 0000000000..b9bb774b9a --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-DevPreviewNoUpgrade.crd.yaml @@ -0,0 +1,339 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/470 + api.openshift.io/merged-by-featuregates: "true" + include.release.openshift.io/ibm-cloud-managed: "true" + include.release.openshift.io/self-managed-high-availability: "true" + release.openshift.io/bootstrap-required: "true" + release.openshift.io/feature-set: DevPreviewNoUpgrade + name: featuregates.config.openshift.io +spec: + group: config.openshift.io + names: + kind: FeatureGate + listKind: FeatureGateList + plural: featuregates + singular: featuregate + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + Feature holds cluster-wide information about feature gates. The canonical name is `cluster` + + Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec holds user settable values for configuration + properties: + customNoUpgrade: + description: |- + customNoUpgrade allows the enabling or disabling of any feature. Turning this feature set on IS NOT SUPPORTED, CANNOT BE UNDONE, and PREVENTS UPGRADES. + Because of its nature, this setting cannot be validated. If you have any typos or accidentally apply invalid combinations + your cluster may fail in an unrecoverable way. featureSet must equal "CustomNoUpgrade" must be set to use this field. + nullable: true + properties: + disabled: + description: disabled is a list of all feature gates that you + want to force off + items: + description: FeatureGateName is a string to enforce patterns + on the name of a FeatureGate + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + type: array + enabled: + description: enabled is a list of all feature gates that you want + to force on + items: + description: FeatureGateName is a string to enforce patterns + on the name of a FeatureGate + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + type: array + type: object + featureSet: + description: |- + featureSet changes the list of features in the cluster. The default is empty. Be very careful adjusting this setting. + Turning on or off features may cause irreversible changes in your cluster which cannot be undone. + enum: + - CustomNoUpgrade + - DevPreviewNoUpgrade + - TechPreviewNoUpgrade + - "" + type: string + x-kubernetes-validations: + - message: CustomNoUpgrade may not be changed + rule: 'oldSelf == ''CustomNoUpgrade'' ? self == ''CustomNoUpgrade'' + : true' + - message: TechPreviewNoUpgrade may not be changed + rule: 'oldSelf == ''TechPreviewNoUpgrade'' ? self == ''TechPreviewNoUpgrade'' + : true' + - message: DevPreviewNoUpgrade may not be changed + rule: 'oldSelf == ''DevPreviewNoUpgrade'' ? self == ''DevPreviewNoUpgrade'' + : true' + type: object + x-kubernetes-validations: + - message: .spec.featureSet cannot be removed + rule: 'has(oldSelf.featureSet) ? has(self.featureSet) : true' + status: + description: status holds observed values from the cluster. They may not + be overridden. + properties: + conditions: + description: |- + conditions represent the observations of the current state. + Known .status.conditions.type are: "DeterminationDegraded" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + featureGates: + description: |- + featureGates contains a list of enabled and disabled featureGates that are keyed by payloadVersion. + Operators other than the CVO and cluster-config-operator, must read the .status.featureGates, locate + the version they are managing, find the enabled/disabled featuregates and make the operand and operator match. + The enabled/disabled values for a particular version may change during the life of the cluster as various + .spec.featureSet values are selected. + Operators may choose to restart their processes to pick up these changes, but remembering past enable/disable + lists is beyond the scope of this API and is the responsibility of individual operators. + Only featureGates with .version in the ClusterVersion.status will be present in this list. + items: + properties: + disabled: + description: disabled is a list of all feature gates that are + disabled in the cluster for the named version. + items: + properties: + name: + description: name is the name of the FeatureGate. + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + requiredMinimumComponentVersions: + description: |- + requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + component may be in this cluster to have this feature turned on in the Default featureset. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver + compatible format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + required: + - name + type: object + type: array + enabled: + description: enabled is a list of all feature gates that are + enabled in the cluster for the named version. + items: + properties: + name: + description: name is the name of the FeatureGate. + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + requiredMinimumComponentVersions: + description: |- + requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + component may be in this cluster to have this feature turned on in the Default featureset. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver + compatible format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + required: + - name + type: object + type: array + renderedMinimumComponentVersions: + description: |- + renderedMinimumComponentVersions are the component versions that the feature gate list of this status were rendered from. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + feature set was rendered given the minimumKubeletVersion in the nodes.config object was lower than or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver compatible + format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + version: + description: version matches the version provided by the ClusterVersion + and in the ClusterOperator.Status.Versions field. + type: string + required: + - version + type: object + type: array + x-kubernetes-list-map-keys: + - version + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-TechPreviewNoUpgrade.crd.yaml new file mode 100644 index 0000000000..46e5ce8817 --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_featuregates-TechPreviewNoUpgrade.crd.yaml @@ -0,0 +1,339 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.openshift.io: https://github.com/openshift/api/pull/470 + api.openshift.io/merged-by-featuregates: "true" + include.release.openshift.io/ibm-cloud-managed: "true" + include.release.openshift.io/self-managed-high-availability: "true" + release.openshift.io/bootstrap-required: "true" + release.openshift.io/feature-set: TechPreviewNoUpgrade + name: featuregates.config.openshift.io +spec: + group: config.openshift.io + names: + kind: FeatureGate + listKind: FeatureGateList + plural: featuregates + singular: featuregate + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + Feature holds cluster-wide information about feature gates. The canonical name is `cluster` + + Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec holds user settable values for configuration + properties: + customNoUpgrade: + description: |- + customNoUpgrade allows the enabling or disabling of any feature. Turning this feature set on IS NOT SUPPORTED, CANNOT BE UNDONE, and PREVENTS UPGRADES. + Because of its nature, this setting cannot be validated. If you have any typos or accidentally apply invalid combinations + your cluster may fail in an unrecoverable way. featureSet must equal "CustomNoUpgrade" must be set to use this field. + nullable: true + properties: + disabled: + description: disabled is a list of all feature gates that you + want to force off + items: + description: FeatureGateName is a string to enforce patterns + on the name of a FeatureGate + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + type: array + enabled: + description: enabled is a list of all feature gates that you want + to force on + items: + description: FeatureGateName is a string to enforce patterns + on the name of a FeatureGate + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + type: array + type: object + featureSet: + description: |- + featureSet changes the list of features in the cluster. The default is empty. Be very careful adjusting this setting. + Turning on or off features may cause irreversible changes in your cluster which cannot be undone. + enum: + - CustomNoUpgrade + - DevPreviewNoUpgrade + - TechPreviewNoUpgrade + - "" + type: string + x-kubernetes-validations: + - message: CustomNoUpgrade may not be changed + rule: 'oldSelf == ''CustomNoUpgrade'' ? self == ''CustomNoUpgrade'' + : true' + - message: TechPreviewNoUpgrade may not be changed + rule: 'oldSelf == ''TechPreviewNoUpgrade'' ? self == ''TechPreviewNoUpgrade'' + : true' + - message: DevPreviewNoUpgrade may not be changed + rule: 'oldSelf == ''DevPreviewNoUpgrade'' ? self == ''DevPreviewNoUpgrade'' + : true' + type: object + x-kubernetes-validations: + - message: .spec.featureSet cannot be removed + rule: 'has(oldSelf.featureSet) ? has(self.featureSet) : true' + status: + description: status holds observed values from the cluster. They may not + be overridden. + properties: + conditions: + description: |- + conditions represent the observations of the current state. + Known .status.conditions.type are: "DeterminationDegraded" + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + featureGates: + description: |- + featureGates contains a list of enabled and disabled featureGates that are keyed by payloadVersion. + Operators other than the CVO and cluster-config-operator, must read the .status.featureGates, locate + the version they are managing, find the enabled/disabled featuregates and make the operand and operator match. + The enabled/disabled values for a particular version may change during the life of the cluster as various + .spec.featureSet values are selected. + Operators may choose to restart their processes to pick up these changes, but remembering past enable/disable + lists is beyond the scope of this API and is the responsibility of individual operators. + Only featureGates with .version in the ClusterVersion.status will be present in this list. + items: + properties: + disabled: + description: disabled is a list of all feature gates that are + disabled in the cluster for the named version. + items: + properties: + name: + description: name is the name of the FeatureGate. + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + requiredMinimumComponentVersions: + description: |- + requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + component may be in this cluster to have this feature turned on in the Default featureset. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver + compatible format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + required: + - name + type: object + type: array + enabled: + description: enabled is a list of all feature gates that are + enabled in the cluster for the named version. + items: + properties: + name: + description: name is the name of the FeatureGate. + pattern: ^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$ + type: string + requiredMinimumComponentVersions: + description: |- + requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given + component may be in this cluster to have this feature turned on in the Default featureset. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than + or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver + compatible format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + required: + - name + type: object + type: array + renderedMinimumComponentVersions: + description: |- + renderedMinimumComponentVersions are the component versions that the feature gate list of this status were rendered from. + Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to "Kubelet" will mean + feature set was rendered given the minimumKubeletVersion in the nodes.config object was lower than or equal to the given MinimumComponentVersion.Version + items: + description: |- + MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component + to enable this feature. + properties: + component: + description: |- + component is the entity whose version must be above a certain version. + The only valid value is Kubelet + enum: + - Kubelet + type: string + version: + description: |- + version is the minimum version the given component may be in this cluster. + version must be in semver format (x.y.z) and must consist only of numbers and periods (.). + Note: this is the version of the component, not Openshift. For instance, when Component is "Kubelet", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), + not the corresponding Openshift version (4.19.0) + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver compatible + format of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') + required: + - component + - version + type: object + maxItems: 1 + type: array + x-kubernetes-list-map-keys: + - component + x-kubernetes-list-type: map + version: + description: version matches the version provided by the ClusterVersion + and in the ClusterOperator.Status.Versions field. + type: string + required: + - version + type: object + type: array + x-kubernetes-list-map-keys: + - version + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-CustomNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-CustomNoUpgrade.crd.yaml index 1274ac4d54..99dc49ab14 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-CustomNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-CustomNoUpgrade.crd.yaml @@ -49,6 +49,7 @@ spec: cgroupMode: description: cgroupMode determines the cgroups version on the node enum: + - v1 - v2 - "" type: string @@ -147,6 +148,30 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map + minimumKubeletVersion: + description: |- + minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. + Specifically, the apiserver will deny most authorization requests of kubelets that are older + than the specified version, only allowing the kubelet to get and update its node object, and perform + subjectaccessreviews. + This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, + and will eventually be marked as not ready. + Its max length is 8, so maximum version allowed is either "9.999.99" or "99.99.99". + Since the kubelet reports the version of the kubernetes release, not Openshift, this field references + the underlying kubernetes version this version of Openshift is based off of. + In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then + they should set the minimumKubeletVersion to 1.30.0. + When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. + Thus, a kubelet with version "1.0.0-ec.0" will be compatible with minimumKubeletVersion "1.0.0" or earlier. + This status field is used to reflect the actualized minimum kubelet version, which can be interpreted from the + FeatureGateStatus.RenderedMinimumComponentVersion when Component == Kubelet, after that FeatureGateStatus finishes rolling out to + all kubelets. + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver compatible format + of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') type: object required: - spec diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-Default.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-Default.crd.yaml index bc50d3702b..a4d69857db 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-Default.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-Default.crd.yaml @@ -49,6 +49,7 @@ spec: cgroupMode: description: cgroupMode determines the cgroups version on the node enum: + - v1 - v2 - "" type: string diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-DevPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-DevPreviewNoUpgrade.crd.yaml index 0cd65142fb..ebc64ac69e 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-DevPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-DevPreviewNoUpgrade.crd.yaml @@ -49,6 +49,7 @@ spec: cgroupMode: description: cgroupMode determines the cgroups version on the node enum: + - v1 - v2 - "" type: string @@ -147,6 +148,30 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map + minimumKubeletVersion: + description: |- + minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. + Specifically, the apiserver will deny most authorization requests of kubelets that are older + than the specified version, only allowing the kubelet to get and update its node object, and perform + subjectaccessreviews. + This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, + and will eventually be marked as not ready. + Its max length is 8, so maximum version allowed is either "9.999.99" or "99.99.99". + Since the kubelet reports the version of the kubernetes release, not Openshift, this field references + the underlying kubernetes version this version of Openshift is based off of. + In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then + they should set the minimumKubeletVersion to 1.30.0. + When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. + Thus, a kubelet with version "1.0.0-ec.0" will be compatible with minimumKubeletVersion "1.0.0" or earlier. + This status field is used to reflect the actualized minimum kubelet version, which can be interpreted from the + FeatureGateStatus.RenderedMinimumComponentVersion when Component == Kubelet, after that FeatureGateStatus finishes rolling out to + all kubelets. + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver compatible format + of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') type: object required: - spec diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-TechPreviewNoUpgrade.crd.yaml index 13d3adce9a..3895fb5f03 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-TechPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_nodes-TechPreviewNoUpgrade.crd.yaml @@ -49,6 +49,7 @@ spec: cgroupMode: description: cgroupMode determines the cgroups version on the node enum: + - v1 - v2 - "" type: string @@ -147,6 +148,30 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map + minimumKubeletVersion: + description: |- + minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. + Specifically, the apiserver will deny most authorization requests of kubelets that are older + than the specified version, only allowing the kubelet to get and update its node object, and perform + subjectaccessreviews. + This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, + and will eventually be marked as not ready. + Its max length is 8, so maximum version allowed is either "9.999.99" or "99.99.99". + Since the kubelet reports the version of the kubernetes release, not Openshift, this field references + the underlying kubernetes version this version of Openshift is based off of. + In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then + they should set the minimumKubeletVersion to 1.30.0. + When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. + Thus, a kubelet with version "1.0.0-ec.0" will be compatible with minimumKubeletVersion "1.0.0" or earlier. + This status field is used to reflect the actualized minimum kubelet version, which can be interpreted from the + FeatureGateStatus.RenderedMinimumComponentVersion when Component == Kubelet, after that FeatureGateStatus finishes rolling out to + all kubelets. + maxLength: 8 + type: string + x-kubernetes-validations: + - message: minmumKubeletVersion must be in a semver compatible format + of x.y.z, or empty + rule: self.matches('^[0-9]*.[0-9]*.[0-9]*$') type: object required: - spec diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go index 22bd77fc5b..720f120013 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go @@ -2052,6 +2052,11 @@ func (in *FeatureGate) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FeatureGateAttributes) DeepCopyInto(out *FeatureGateAttributes) { *out = *in + if in.RequiredMinimumComponentVersions != nil { + in, out := &in.RequiredMinimumComponentVersions, &out.RequiredMinimumComponentVersions + *out = make([]MinimumComponentVersion, len(*in)) + copy(*out, *in) + } return } @@ -2071,11 +2076,20 @@ func (in *FeatureGateDetails) DeepCopyInto(out *FeatureGateDetails) { if in.Enabled != nil { in, out := &in.Enabled, &out.Enabled *out = make([]FeatureGateAttributes, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.Disabled != nil { in, out := &in.Disabled, &out.Disabled *out = make([]FeatureGateAttributes, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RenderedMinimumComponentVersions != nil { + in, out := &in.RenderedMinimumComponentVersions, &out.RenderedMinimumComponentVersions + *out = make([]MinimumComponentVersion, len(*in)) copy(*out, *in) } return @@ -3582,6 +3596,22 @@ func (in *MaxAgePolicy) DeepCopy() *MaxAgePolicy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MinimumComponentVersion) DeepCopyInto(out *MinimumComponentVersion) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MinimumComponentVersion. +func (in *MinimumComponentVersion) DeepCopy() *MinimumComponentVersion { + if in == nil { + return nil + } + out := new(MinimumComponentVersion) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ModernTLSProfile) DeepCopyInto(out *ModernTLSProfile) { *out = *in diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml index c53b4772e0..3195557c46 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml @@ -198,7 +198,8 @@ featuregates.config.openshift.io: CRDName: featuregates.config.openshift.io Capability: "" Category: "" - FeatureGates: [] + FeatureGates: + - MinimumKubeletVersion FilenameOperatorName: config-operator FilenameOperatorOrdering: "01" FilenameRunLevel: "0000_10" diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index 83d16f09f0..f44f198902 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -950,7 +950,8 @@ func (FeatureGate) SwaggerDoc() map[string]string { } var map_FeatureGateAttributes = map[string]string{ - "name": "name is the name of the FeatureGate.", + "name": "name is the name of the FeatureGate.", + "requiredMinimumComponentVersions": "requiredMinimumComponentVersions is a list of component/version pairs that declares the is the lowest version the given component may be in this cluster to have this feature turned on in the Default featureset. Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to \"Kubelet\" will mean this feature will be added to the Default set if the minimumKubeletVersion in the nodes.config object is lower than or equal to the given MinimumComponentVersion.Version", } func (FeatureGateAttributes) SwaggerDoc() map[string]string { @@ -958,9 +959,10 @@ func (FeatureGateAttributes) SwaggerDoc() map[string]string { } var map_FeatureGateDetails = map[string]string{ - "version": "version matches the version provided by the ClusterVersion and in the ClusterOperator.Status.Versions field.", - "enabled": "enabled is a list of all feature gates that are enabled in the cluster for the named version.", - "disabled": "disabled is a list of all feature gates that are disabled in the cluster for the named version.", + "version": "version matches the version provided by the ClusterVersion and in the ClusterOperator.Status.Versions field.", + "enabled": "enabled is a list of all feature gates that are enabled in the cluster for the named version.", + "disabled": "disabled is a list of all feature gates that are disabled in the cluster for the named version.", + "renderedMinimumComponentVersions": "renderedMinimumComponentVersions are the component versions that the feature gate list of this status were rendered from. Currently, the only supported component is Kubelet, and setting the MinimumComponentVersion.Component to \"Kubelet\" will mean feature set was rendered given the minimumKubeletVersion in the nodes.config object was lower than or equal to the given MinimumComponentVersion.Version", } func (FeatureGateDetails) SwaggerDoc() map[string]string { @@ -994,6 +996,16 @@ func (FeatureGateStatus) SwaggerDoc() map[string]string { return map_FeatureGateStatus } +var map_MinimumComponentVersion = map[string]string{ + "": "MinimumComponentVersion is a pair of Component and Version that specifies the required minimum Version of the given Component to enable this feature.", + "component": "component is the entity whose version must be above a certain version. The only valid value is Kubelet", + "version": "version is the minimum version the given component may be in this cluster. version must be in semver format (x.y.z) and must consist only of numbers and periods (.). Note: this is the version of the component, not Openshift. For instance, when Component is \"Kubelet\", it is a required version of the Kubelet (i.e: kubernetes version, like 1.32.0), not the corresponding Openshift version (4.19.0)", +} + +func (MinimumComponentVersion) SwaggerDoc() map[string]string { + return map_MinimumComponentVersion +} + var map_Image = map[string]string{ "": "Image governs policies related to imagestream imports and runtime configuration for external registries. It allows cluster admins to configure which registries OpenShift is allowed to import images from, extra CA trust bundles for external registries, and policies to block or allow registry hostnames. When exposing OpenShift's image registry to the public, this also lets cluster admins specify the external hostname.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "metadata": "metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", @@ -2165,7 +2177,8 @@ func (NodeSpec) SwaggerDoc() map[string]string { } var map_NodeStatus = map[string]string{ - "conditions": "conditions contain the details and the current state of the nodes.config object", + "conditions": "conditions contain the details and the current state of the nodes.config object", + "minimumKubeletVersion": "minimumKubeletVersion is the lowest version of a kubelet that can join the cluster. Specifically, the apiserver will deny most authorization requests of kubelets that are older than the specified version, only allowing the kubelet to get and update its node object, and perform subjectaccessreviews. This means any kubelet that attempts to join the cluster will not be able to run any assigned workloads, and will eventually be marked as not ready. Its max length is 8, so maximum version allowed is either \"9.999.99\" or \"99.99.99\". Since the kubelet reports the version of the kubernetes release, not Openshift, this field references the underlying kubernetes version this version of Openshift is based off of. In other words: if an admin wishes to ensure no nodes run an older version than Openshift 4.17, then they should set the minimumKubeletVersion to 1.30.0. When comparing versions, the kubelet's version is stripped of any contents outside of major.minor.patch version. Thus, a kubelet with version \"1.0.0-ec.0\" will be compatible with minimumKubeletVersion \"1.0.0\" or earlier. This status field is used to reflect the actualized minimum kubelet version, which can be interpreted from the FeatureGateStatus.RenderedMinimumComponentVersion when Component == Kubelet, after that FeatureGateStatus finishes rolling out to all kubelets.", } func (NodeStatus) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/features/features.go b/vendor/github.com/openshift/api/features/features.go index 8f30373e92..6583ec09eb 100644 --- a/vendor/github.com/openshift/api/features/features.go +++ b/vendor/github.com/openshift/api/features/features.go @@ -677,6 +677,7 @@ var ( productScope(kubernetes). enhancementPR("https://github.com/kubernetes/enhancements/issues/127"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + enableInDefaultWhenRequiredMinimumComponentVersion(configv1.MinimumComponentKubelet, "1.30.0"). mustRegister() FeatureGateUserNamespacesPodSecurityStandards = newFeatureGate("UserNamespacesPodSecurityStandards"). @@ -685,6 +686,7 @@ var ( productScope(kubernetes). enhancementPR("https://github.com/kubernetes/enhancements/issues/127"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + enableInDefaultWhenRequiredMinimumComponentVersion(configv1.MinimumComponentKubelet, "1.30.0"). mustRegister() FeatureGateProcMountType = newFeatureGate("ProcMountType"). @@ -693,6 +695,7 @@ var ( productScope(kubernetes). enhancementPR("https://github.com/kubernetes/enhancements/issues/4265"). enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade). + enableInDefaultWhenRequiredMinimumComponentVersion(configv1.MinimumComponentKubelet, "1.30.0"). mustRegister() FeatureGateVSphereMultiNetworks = newFeatureGate("VSphereMultiNetworks"). diff --git a/vendor/github.com/openshift/api/features/util.go b/vendor/github.com/openshift/api/features/util.go index 59bb7bff40..21c4b2e2b3 100644 --- a/vendor/github.com/openshift/api/features/util.go +++ b/vendor/github.com/openshift/api/features/util.go @@ -2,9 +2,10 @@ package features import ( "fmt" - configv1 "github.com/openshift/api/config/v1" "net/url" "strings" + + configv1 "github.com/openshift/api/config/v1" ) // FeatureGateDescription is a golang-only interface used to contains details for a feature gate. @@ -27,6 +28,11 @@ type FeatureGateDescription struct { type FeatureGateEnabledDisabled struct { Enabled []FeatureGateDescription Disabled []FeatureGateDescription + // Map of component -> map of version -> description + // It would likely be better as map of component -> map of featureName -> version + // but let's revisit that. + // TODO FIXME + EnabledGivenMinimumVersion map[configv1.MinimumComponent]map[string][]configv1.FeatureGateAttributes } type ClusterProfileName string @@ -45,11 +51,12 @@ var ( ) type featureGateBuilder struct { - name string - owningJiraComponent string - responsiblePerson string - owningProduct OwningProduct - enhancementPRURL string + name string + owningJiraComponent string + responsiblePerson string + owningProduct OwningProduct + enhancementPRURL string + minimumKubeletVersion string statusByClusterProfileByFeatureSet map[ClusterProfileName]map[configv1.FeatureSet]bool } @@ -110,6 +117,11 @@ func (b *featureGateBuilder) enableForClusterProfile(clusterProfile ClusterProfi return b } +func (b *featureGateBuilder) enableInDefaultWhenRequiredMinimumComponentVersion(component configv1.MinimumComponent, version string) *featureGateBuilder { + b.minimumKubeletVersion = version + return b +} + func (b *featureGateBuilder) register() (configv1.FeatureGateName, error) { if len(b.name) == 0 { return "", fmt.Errorf("missing name") @@ -141,9 +153,20 @@ func (b *featureGateBuilder) register() (configv1.FeatureGateName, error) { } featureGateName := configv1.FeatureGateName(b.name) + var minComponentVersions []configv1.MinimumComponentVersion + if b.minimumKubeletVersion != "" { + if minComponentVersions == nil { + minComponentVersions = []configv1.MinimumComponentVersion{} + } + minComponentVersions = append(minComponentVersions, configv1.MinimumComponentVersion{ + Component: configv1.MinimumComponentKubelet, + Version: b.minimumKubeletVersion, + }) + } description := FeatureGateDescription{ FeatureGateAttributes: configv1.FeatureGateAttributes{ - Name: featureGateName, + Name: featureGateName, + RequiredMinimumComponentVersions: minComponentVersions, }, OwningJiraComponent: b.owningJiraComponent, ResponsiblePerson: b.responsiblePerson, @@ -166,6 +189,20 @@ func (b *featureGateBuilder) register() (configv1.FeatureGateName, error) { } else { allFeatureGates[clusterProfile][featureSet].Disabled = append(allFeatureGates[clusterProfile][featureSet].Disabled, description) } + if b.minimumKubeletVersion != "" && featureSet == configv1.Default { + if allFeatureGates[clusterProfile][featureSet].EnabledGivenMinimumVersion == nil { + allFeatureGates[clusterProfile][featureSet].EnabledGivenMinimumVersion = map[configv1.MinimumComponent]map[string][]configv1.FeatureGateAttributes{} + } + if _, ok := allFeatureGates[clusterProfile][featureSet].EnabledGivenMinimumVersion[configv1.MinimumComponentKubelet]; !ok { + allFeatureGates[clusterProfile][featureSet].EnabledGivenMinimumVersion[configv1.MinimumComponentKubelet] = map[string][]configv1.FeatureGateAttributes{} + } + features, ok := allFeatureGates[clusterProfile][featureSet].EnabledGivenMinimumVersion[configv1.MinimumComponentKubelet][b.minimumKubeletVersion] + if !ok { + features = []configv1.FeatureGateAttributes{} + } + // TODO FIXME: This is hellish, is there a better way? + allFeatureGates[clusterProfile][featureSet].EnabledGivenMinimumVersion[configv1.MinimumComponentKubelet][b.minimumKubeletVersion] = append(features, description.FeatureGateAttributes) + } } } diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/types_machineconfignode.go b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/types_machineconfignode.go index fdb6509373..965549d4e3 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/types_machineconfignode.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/types_machineconfignode.go @@ -10,7 +10,7 @@ import ( // +kubebuilder:object:root=true // +kubebuilder:resource:path=machineconfignodes,scope=Cluster // +kubebuilder:subresource:status -// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/2256 +// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/1596 // +openshift:file-pattern=cvoRunLevel=0000_80,operatorName=machine-config,operatorOrdering=01 // +openshift:enable:FeatureGate=MachineConfigNodes // +kubebuilder:printcolumn:name="PoolName",type="string",JSONPath=.spec.pool.name,priority=0 @@ -22,10 +22,12 @@ import ( // +kubebuilder:printcolumn:name="UpdatePostActionComplete",type="string",JSONPath=.status.conditions[?(@.type=="UpdatePostActionComplete")].status,priority=1 // +kubebuilder:printcolumn:name="UpdateComplete",type="string",JSONPath=.status.conditions[?(@.type=="UpdateComplete")].status,priority=1 // +kubebuilder:printcolumn:name="Resumed",type="string",JSONPath=.status.conditions[?(@.type=="Resumed")].status,priority=1 +// +kubebuilder:printcolumn:name="UpdateCompatible",type="string",JSONPath=.status.conditions[?(@.type=="UpdateCompatible")].status,priority=1 // +kubebuilder:printcolumn:name="UpdatedFilesAndOS",type="string",JSONPath=.status.conditions[?(@.type=="AppliedFilesAndOS")].status,priority=1 // +kubebuilder:printcolumn:name="CordonedNode",type="string",JSONPath=.status.conditions[?(@.type=="Cordoned")].status,priority=1 // +kubebuilder:printcolumn:name="DrainedNode",type="string",JSONPath=.status.conditions[?(@.type=="Drained")].status,priority=1 // +kubebuilder:printcolumn:name="RebootedNode",type="string",JSONPath=.status.conditions[?(@.type=="RebootedNode")].status,priority=1 +// +kubebuilder:printcolumn:name="ReloadedCRIO",type="string",JSONPath=.status.conditions[?(@.type=="ReloadedCRIO")].status,priority=1 // +kubebuilder:printcolumn:name="UncordonedNode",type="string",JSONPath=.status.conditions[?(@.type=="Uncordoned")].status,priority=1 // +kubebuilder:metadata:labels=openshift.io/operator-managed= @@ -34,10 +36,7 @@ import ( // +openshift:compatibility-gen:level=4 // +kubebuilder:validation:XValidation:rule="self.metadata.name == self.spec.node.name",message="spec.node.name should match metadata.name" type MachineConfigNode struct { - metav1.TypeMeta `json:",inline"` - - // metadata is the standard object metadata. - // +optional + metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` // spec describes the configuration of the machine config node. @@ -57,27 +56,20 @@ type MachineConfigNode struct { // +openshift:compatibility-gen:level=4 type MachineConfigNodeList struct { metav1.TypeMeta `json:",inline"` - - // metadata is the standard list metadata. - // +optional metav1.ListMeta `json:"metadata"` - // items contains a collection of MachineConfigNode resources. - // +kubebuilder:validation:MaxItems=100 - // +optional Items []MachineConfigNode `json:"items"` } // MCOObjectReference holds information about an object the MCO either owns // or modifies in some way type MCOObjectReference struct { - // name is the name of the object being referenced. For example, this can represent a machine - // config pool or node name. - // Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - // of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - // with an alphanumeric character, and be at most 253 characters in length. + // name is the object name. + // Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // It may consist of only alphanumeric characters, hyphens (-) and periods (.) + // and must be at most 253 characters in length. // +kubebuilder:validation:MaxLength:=253 - // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$` // +required Name string `json:"name"` } @@ -94,20 +86,17 @@ type MachineConfigNodeSpec struct { Pool MCOObjectReference `json:"pool"` // configVersion holds the desired config version for the node targeted by this machine config node resource. - // The desired version represents the machine config the node will attempt to update to and gets set before the machine config operator validates + // The desired version represents the machine config the node will attempt to update to. This gets set before the machine config operator validates // the new machine config against the current machine config. // +required ConfigVersion MachineConfigNodeSpecMachineConfigVersion `json:"configVersion"` - // pinnedImageSets is a user defined value that holds the names of the desired image sets that the node should pull and pin. + // pinnedImageSets holds the desired pinned image sets that this node should pin and pull. // +listType=map // +listMapKey=name // +kubebuilder:validation:MaxItems=100 // +optional - // Tombstone: Functionality to correctly and consistely populate this field was not implemented in the MCO, so - // when applying a PIS, this field is not being updated. Since this field is not being used, it is being removed - // before this API is GAed. - // PinnedImageSets []MachineConfigNodeSpecPinnedImageSet `json:"pinnedImageSets,omitempty"` + PinnedImageSets []MachineConfigNodeSpecPinnedImageSet `json:"pinnedImageSets,omitempty"` } // MachineConfigNodeStatus holds the reported information on a particular machine config node. @@ -115,19 +104,21 @@ type MachineConfigNodeStatus struct { // conditions represent the observations of a machine config node's current state. // +listType=map // +listMapKey=type - // +kubebuilder:validation:MaxItems=20 // +optional Conditions []metav1.Condition `json:"conditions,omitempty"` - // observedGeneration represents the generation of the MachineConfigNode object observed by the Machine Config Operator's controller. + // observedGeneration represents the generation observed by the controller. // This field is updated when the controller observes a change to the desiredConfig in the configVersion of the machine config node spec. - // +kubebuilder:validation:XValidation:rule="self >= oldSelf", message="observedGeneration must not decrease" - // +kubebuilder:validation:Minimum=0 - // +optional + // +required ObservedGeneration int64 `json:"observedGeneration,omitempty"` - // configVersion describes the current and desired machine config version for this node. + // configVersion describes the current and desired machine config for this node. + // The current version represents the current machine config for the node and is updated after a successful update. + // The desired version represents the machine config the node will attempt to update to. + // This desired machine config has been compared to the current machine config and has been validated by the machine config operator as one that is valid and that exists. // +required ConfigVersion MachineConfigNodeStatusMachineConfigVersion `json:"configVersion"` // pinnedImageSets describes the current and desired pinned image sets for this node. + // The current version is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. + // The desired version is the generation of the pinned image set that is targeted to be pulled and pinned on this node. // +listType=map // +listMapKey=name // +kubebuilder:validation:MaxItems=100 @@ -135,110 +126,95 @@ type MachineConfigNodeStatus struct { PinnedImageSets []MachineConfigNodeStatusPinnedImageSet `json:"pinnedImageSets,omitempty"` } -// MachineConfigNodeStatusPinnedImageSet holds information about the current, desired, and failed pinned image sets for the observed machine config node. // +kubebuilder:validation:XValidation:rule="has(self.desiredGeneration) && has(self.currentGeneration) ? self.desiredGeneration >= self.currentGeneration : true",message="desired generation must be greater than or equal to the current generation" -// +kubebuilder:validation:XValidation:rule="has(self.lastFailedGeneration) && has(self.desiredGeneration) ? self.desiredGeneration >= self.lastFailedGeneration : true",message="desired generation must be greater than or equal to the last failed generation" -// +kubebuilder:validation:XValidation:rule="has(self.lastFailedGeneration) ? has(self.lastFailedGenerationError) : true",message="last failed generation error must be defined on image pull and pin failure" +// +kubebuilder:validation:XValidation:rule="has(self.lastFailedGeneration) && has(self.desiredGeneration) ? self.desiredGeneration >= self.lastFailedGeneration : true",message="desired generation must be greater than last failed generation" +// +kubebuilder:validation:XValidation:rule="has(self.lastFailedGeneration) ? has(self.desiredGeneration): true",message="desired generation must be defined if last failed generation is defined" type MachineConfigNodeStatusPinnedImageSet struct { // name is the name of the pinned image set. - // Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - // of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - // with an alphanumeric character, and be at most 253 characters in length. + // Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // It may consist of only alphanumeric characters, hyphens (-) and periods (.) + // and must be at most 253 characters in length. // +kubebuilder:validation:MaxLength:=253 - // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$` // +required Name string `json:"name"` // currentGeneration is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. - // +kubebuilder:validation:XValidation:rule="self >= oldSelf", message="currentGeneration must not decrease" - // +kubebuilder:validation:Minimum=0 // +optional CurrentGeneration int32 `json:"currentGeneration,omitempty"` - // desiredGeneration is the generation of the pinned image set that is targeted to be pulled and pinned on this node. - // +kubebuilder:validation:XValidation:rule="self >= oldSelf", message="desiredGeneration must not decrease" + // desiredGeneration version is the generation of the pinned image set that is targeted to be pulled and pinned on this node. // +kubebuilder:validation:Minimum=0 // +optional DesiredGeneration int32 `json:"desiredGeneration,omitempty"` // lastFailedGeneration is the generation of the most recent pinned image set that failed to be pulled and pinned on this node. - // +kubebuilder:validation:XValidation:rule="self >= oldSelf", message="lastFailedGeneration must not decrease" // +kubebuilder:validation:Minimum=0 // +optional LastFailedGeneration int32 `json:"lastFailedGeneration,omitempty"` - // lastFailedGenerationError is the error explaining why the desired images failed to be pulled and pinned. - // The error is an empty string if the image pull and pin is successful. - // +kubebuilder:validation:MaxLength=32768 + // lastFailedGenerationErrors is a list of errors why the lastFailed generation failed to be pulled and pinned. + // +kubebuilder:validation:MaxItems=10 // +optional - LastFailedGenerationError string `json:"lastFailedGenerationError,omitempty"` - // Previously, failures associated with pinning and pulling images where shared in a list of strings under `LastFailedGenerationErrors`. - // This field is being removed and a `LastFailedGenerationError` field of type string is being added in its place as this field will - // contain a single error and there is no need for a list anymore. - // Tombstone: legacy field no longer needed - // LastFailedGenerationErrors []string `json:"lastFailedGenerationErrors,omitempty"` + LastFailedGenerationErrors []string `json:"lastFailedGenerationErrors,omitempty"` } // MachineConfigNodeStatusMachineConfigVersion holds the current and desired config versions as last updated in the MCN status. -// When the current and desired versions do not match, the machine config pool is processing an upgrade and the machine config node will +// When the current and desired versions are not matched, the machine config pool is processing an upgrade and the machine config node will // monitor the upgrade process. -// When the current and desired versions do match, the machine config node will ignore these events given that certain operations -// happen both during the MCO's upgrade mode and the daily operations mode. +// When the current and desired versions do not match, +// the machine config node will ignore these events given that certain operations happen both during the MCO's upgrade mode and the daily operations mode. type MachineConfigNodeStatusMachineConfigVersion struct { // current is the name of the machine config currently in use on the node. // This value is updated once the machine config daemon has completed the update of the configuration for the node. // This value should match the desired version unless an upgrade is in progress. - // Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - // of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - // with an alphanumeric character, and be at most 253 characters in length. - // +kubebuilder:validation:MaxLength:=253 - // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." + // Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // It may consist of only alphanumeric characters, hyphens (-) and periods (.) + // and must be at most 253 characters in length. + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$` // +optional Current string `json:"current"` // desired is the MachineConfig the node wants to upgrade to. // This value gets set in the machine config node status once the machine config has been validated // against the current machine config. - // Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - // of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - // with an alphanumeric character, and be at most 253 characters in length. - // +kubebuilder:validation:MaxLength:=253 - // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." + // Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // It may consist of only alphanumeric characters, hyphens (-) and periods (.) + // and must be at most 253 characters in length. + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$` // +required Desired string `json:"desired"` } // MachineConfigNodeSpecMachineConfigVersion holds the desired config version for the current observed machine config node. -// When Current is not equal to Desired, the MachineConfigOperator is in an upgrade phase and the machine config node will -// take account of upgrade related events. Otherwise, they will be ignored given that certain operations +// When Current is not equal to Desired; the MachineConfigOperator is in an upgrade phase and the machine config node will +// take account of upgrade related events. Otherwise they will be ignored given that certain operations // happen both during the MCO's upgrade mode and the daily operations mode. type MachineConfigNodeSpecMachineConfigVersion struct { // desired is the name of the machine config that the the node should be upgraded to. // This value is set when the machine config pool generates a new version of its rendered configuration. // When this value is changed, the machine config daemon starts the node upgrade process. // This value gets set in the machine config node spec once the machine config has been targeted for upgrade and before it is validated. - // Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - // of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - // with an alphanumeric character, and be at most 253 characters in length. - // +kubebuilder:validation:MaxLength:=253 - // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." + // Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // It may consist of only alphanumeric characters, hyphens (-) and periods (.) + // and must be at most 253 characters in length. + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$` // +required Desired string `json:"desired"` } -// Tombstone: This struct defines the type of `Spec.PinnedImageSets`, which is being removed. Therefore, this field -// is also being tombstoned. -// MachineConfigNodeSpecPinnedImageSet holds information on the desired pinned image sets that the current observed machine config node -// should pin and pull. -// type MachineConfigNodeSpecPinnedImageSet struct { -// // name is the name of the pinned image set. -// // Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting -// // of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end -// // with an alphanumeric character, and be at most 253 characters in length. -// // +kubebuilder:validation:MaxLength:=253 -// // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character." -// // +required -// Name string `json:"name"` -// } +type MachineConfigNodeSpecPinnedImageSet struct { + // name is the name of the pinned image set. + // Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // It may consist of only alphanumeric characters, hyphens (-) and periods (.) + // and must be at most 253 characters in length. + // +kubebuilder:validation:MaxLength:=253 + // +kubebuilder:validation:Pattern=`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$` + // +required + Name string `json:"name"` +} // StateProgress is each possible state for each possible MachineConfigNodeType +// UpgradeProgression Kind will only use the "MachinConfigPoolUpdate..." types for example // Please note: These conditions are subject to change. Both additions and deletions may be made. -// +enum type StateProgress string const ( @@ -248,24 +224,26 @@ const ( MachineConfigNodeUpdateExecuted StateProgress = "UpdateExecuted" // MachineConfigNodeUpdatePostActionComplete describes a machine that has executed its post update action MachineConfigNodeUpdatePostActionComplete StateProgress = "UpdatePostActionComplete" - // MachineConfigNodeUpdateComplete describes a machine that has completed the core parts of an upgrade + // MachineConfigNodeUpdateComplete describes a machine that has completed the core parts of an upgrade. MachineConfigNodeUpdateComplete StateProgress = "UpdateComplete" - // MachineConfigNodeUpdated describes a machine that is fully updated and has a matching desired and current config + // MachineConfigNodeUpdated describes a machine that has a matching desired and current config after executing an update MachineConfigNodeUpdated StateProgress = "Updated" // MachineConfigNodeUpdateResumed describes a machine that has resumed normal processes MachineConfigNodeResumed StateProgress = "Resumed" - // MachineConfigNodeUpdateDrained describes the part of the in progress phase where the node drains + // MachineConfigNodeUpdateCompatible the part of the preparing phase where the mco decides whether it can update + MachineConfigNodeUpdateCompatible StateProgress = "UpdateCompatible" + // MachineConfigNodeUpdateDrained describes the part of the inprogress phase where the node drains MachineConfigNodeUpdateDrained StateProgress = "Drained" - // MachineConfigNodeUpdateFilesAndOS describes the part of the in progress phase where the nodes files and OS config change + // MachineConfigNodeUpdateFilesAndOS describes the part of the inprogress phase where the nodes file and OS config change MachineConfigNodeUpdateFilesAndOS StateProgress = "AppliedFilesAndOS" - // MachineConfigNodeUpdateCordoned describes the part of the in progress phase where the node cordons + // MachineConfigNodeUpdateCordoned describes the part of the completing phase where the node cordons MachineConfigNodeUpdateCordoned StateProgress = "Cordoned" // MachineConfigNodeUpdateUncordoned describes the part of the completing phase where the node uncordons MachineConfigNodeUpdateUncordoned StateProgress = "Uncordoned" // MachineConfigNodeUpdateRebooted describes the part of the post action phase where the node reboots itself MachineConfigNodeUpdateRebooted StateProgress = "RebootedNode" - // MachineConfigNodeNodeDegraded describes a machine that has failed to update to the desired machine config and is in a degraded state - MachineConfigNodeNodeDegraded StateProgress = "NodeDegraded" + // MachineConfigNodeUpdateReloaded describes the part of the post action phase where the node reloads its CRIO service + MachineConfigNodeUpdateReloaded StateProgress = "ReloadedCRIO" // MachineConfigNodePinnedImageSetsProgressing describes a machine currently progressing to the desired pinned image sets MachineConfigNodePinnedImageSetsProgressing StateProgress = "PinnedImageSetsProgressing" // MachineConfigNodePinnedImageSetsDegraded describes a machine that has failed to progress to the desired pinned image sets diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-CustomNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-CustomNoUpgrade.crd.yaml index 89bbbd61d7..b5f36f5205 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-CustomNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-CustomNoUpgrade.crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.openshift.io: https://github.com/openshift/api/pull/2256 + api-approved.openshift.io: https://github.com/openshift/api/pull/1596 api.openshift.io/merged-by-featuregates: "true" include.release.openshift.io/ibm-cloud-managed: "true" include.release.openshift.io/self-managed-high-availability: "true" @@ -52,6 +52,10 @@ spec: name: Resumed priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="UpdateCompatible")].status + name: UpdateCompatible + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="AppliedFilesAndOS")].status name: UpdatedFilesAndOS priority: 1 @@ -68,6 +72,10 @@ spec: name: RebootedNode priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="ReloadedCRIO")].status + name: ReloadedCRIO + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Uncordoned")].status name: UncordonedNode priority: 1 @@ -102,7 +110,7 @@ spec: configVersion: description: |- configVersion holds the desired config version for the node targeted by this machine config node resource. - The desired version represents the machine config the node will attempt to update to and gets set before the machine config operator validates + The desired version represents the machine config the node will attempt to update to. This gets set before the machine config operator validates the new machine config against the current machine config. properties: desired: @@ -111,16 +119,12 @@ spec: This value is set when the machine config pool generates a new version of its rendered configuration. When this value is changed, the machine config daemon starts the node upgrade process. This value gets set in the machine config node spec once the machine config has been targeted for upgrade and before it is validated. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - desired type: object @@ -130,21 +134,38 @@ spec: properties: name: description: |- - name is the name of the object being referenced. For example, this can represent a machine - config pool or node name. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + name is the object name. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object + pinnedImageSets: + description: pinnedImageSets holds the desired pinned image sets that + this node should pin and pull. + items: + properties: + name: + description: |- + name is the name of the pinned image set. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map pool: description: |- pool contains a reference to the machine config pool that this machine config node's @@ -152,18 +173,13 @@ spec: properties: name: description: |- - name is the name of the object being referenced. For example, this can represent a machine - config pool or node name. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + name is the object name. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object @@ -233,86 +249,68 @@ spec: - status - type type: object - maxItems: 20 type: array x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map configVersion: - description: configVersion describes the current and desired machine - config version for this node. + description: |- + configVersion describes the current and desired machine config for this node. + The current version represents the current machine config for the node and is updated after a successful update. + The desired version represents the machine config the node will attempt to update to. + This desired machine config has been compared to the current machine config and has been validated by the machine config operator as one that is valid and that exists. properties: current: description: |- current is the name of the machine config currently in use on the node. This value is updated once the machine config daemon has completed the update of the configuration for the node. This value should match the desired version unless an upgrade is in progress. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' desired: description: |- desired is the MachineConfig the node wants to upgrade to. This value gets set in the machine config node status once the machine config has been validated against the current machine config. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - desired type: object observedGeneration: description: |- - observedGeneration represents the generation of the MachineConfigNode object observed by the Machine Config Operator's controller. + observedGeneration represents the generation observed by the controller. This field is updated when the controller observes a change to the desiredConfig in the configVersion of the machine config node spec. format: int64 - minimum: 0 type: integer - x-kubernetes-validations: - - message: observedGeneration must not decrease - rule: self >= oldSelf pinnedImageSets: - description: pinnedImageSets describes the current and desired pinned - image sets for this node. + description: |- + pinnedImageSets describes the current and desired pinned image sets for this node. + The current version is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. + The desired version is the generation of the pinned image set that is targeted to be pulled and pinned on this node. items: - description: MachineConfigNodeStatusPinnedImageSet holds information - about the current, desired, and failed pinned image sets for the - observed machine config node. properties: currentGeneration: description: currentGeneration is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. format: int32 - minimum: 0 type: integer - x-kubernetes-validations: - - message: currentGeneration must not decrease - rule: self >= oldSelf desiredGeneration: - description: desiredGeneration is the generation of the pinned - image set that is targeted to be pulled and pinned on this - node. + description: desiredGeneration version is the generation of + the pinned image set that is targeted to be pulled and pinned + on this node. format: int32 minimum: 0 type: integer - x-kubernetes-validations: - - message: desiredGeneration must not decrease - rule: self >= oldSelf lastFailedGeneration: description: lastFailedGeneration is the generation of the most recent pinned image set that failed to be pulled and pinned @@ -320,28 +318,22 @@ spec: format: int32 minimum: 0 type: integer - x-kubernetes-validations: - - message: lastFailedGeneration must not decrease - rule: self >= oldSelf - lastFailedGenerationError: - description: |- - lastFailedGenerationError is the error explaining why the desired images failed to be pulled and pinned. - The error is an empty string if the image pull and pin is successful. - maxLength: 32768 - type: string + lastFailedGenerationErrors: + description: lastFailedGenerationErrors is a list of errors + why the lastFailed generation failed to be pulled and pinned. + items: + type: string + maxItems: 10 + type: array name: description: |- name is the name of the pinned image set. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start - and end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object @@ -350,14 +342,13 @@ spec: current generation rule: 'has(self.desiredGeneration) && has(self.currentGeneration) ? self.desiredGeneration >= self.currentGeneration : true' - - message: desired generation must be greater than or equal to the - last failed generation + - message: desired generation must be greater than last failed generation rule: 'has(self.lastFailedGeneration) && has(self.desiredGeneration) ? self.desiredGeneration >= self.lastFailedGeneration : true' - - message: last failed generation error must be defined on image - pull and pin failure - rule: 'has(self.lastFailedGeneration) ? has(self.lastFailedGenerationError) - : true' + - message: desired generation must be defined if last failed generation + is defined + rule: 'has(self.lastFailedGeneration) ? has(self.desiredGeneration): + true' maxItems: 100 type: array x-kubernetes-list-map-keys: @@ -365,6 +356,7 @@ spec: x-kubernetes-list-type: map required: - configVersion + - observedGeneration type: object required: - spec diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-DevPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-DevPreviewNoUpgrade.crd.yaml index 374dc144db..daddf9c98b 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-DevPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-DevPreviewNoUpgrade.crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.openshift.io: https://github.com/openshift/api/pull/2256 + api-approved.openshift.io: https://github.com/openshift/api/pull/1596 api.openshift.io/merged-by-featuregates: "true" include.release.openshift.io/ibm-cloud-managed: "true" include.release.openshift.io/self-managed-high-availability: "true" @@ -52,6 +52,10 @@ spec: name: Resumed priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="UpdateCompatible")].status + name: UpdateCompatible + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="AppliedFilesAndOS")].status name: UpdatedFilesAndOS priority: 1 @@ -68,6 +72,10 @@ spec: name: RebootedNode priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="ReloadedCRIO")].status + name: ReloadedCRIO + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Uncordoned")].status name: UncordonedNode priority: 1 @@ -102,7 +110,7 @@ spec: configVersion: description: |- configVersion holds the desired config version for the node targeted by this machine config node resource. - The desired version represents the machine config the node will attempt to update to and gets set before the machine config operator validates + The desired version represents the machine config the node will attempt to update to. This gets set before the machine config operator validates the new machine config against the current machine config. properties: desired: @@ -111,16 +119,12 @@ spec: This value is set when the machine config pool generates a new version of its rendered configuration. When this value is changed, the machine config daemon starts the node upgrade process. This value gets set in the machine config node spec once the machine config has been targeted for upgrade and before it is validated. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - desired type: object @@ -130,21 +134,38 @@ spec: properties: name: description: |- - name is the name of the object being referenced. For example, this can represent a machine - config pool or node name. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + name is the object name. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object + pinnedImageSets: + description: pinnedImageSets holds the desired pinned image sets that + this node should pin and pull. + items: + properties: + name: + description: |- + name is the name of the pinned image set. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map pool: description: |- pool contains a reference to the machine config pool that this machine config node's @@ -152,18 +173,13 @@ spec: properties: name: description: |- - name is the name of the object being referenced. For example, this can represent a machine - config pool or node name. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + name is the object name. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object @@ -233,86 +249,68 @@ spec: - status - type type: object - maxItems: 20 type: array x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map configVersion: - description: configVersion describes the current and desired machine - config version for this node. + description: |- + configVersion describes the current and desired machine config for this node. + The current version represents the current machine config for the node and is updated after a successful update. + The desired version represents the machine config the node will attempt to update to. + This desired machine config has been compared to the current machine config and has been validated by the machine config operator as one that is valid and that exists. properties: current: description: |- current is the name of the machine config currently in use on the node. This value is updated once the machine config daemon has completed the update of the configuration for the node. This value should match the desired version unless an upgrade is in progress. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' desired: description: |- desired is the MachineConfig the node wants to upgrade to. This value gets set in the machine config node status once the machine config has been validated against the current machine config. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - desired type: object observedGeneration: description: |- - observedGeneration represents the generation of the MachineConfigNode object observed by the Machine Config Operator's controller. + observedGeneration represents the generation observed by the controller. This field is updated when the controller observes a change to the desiredConfig in the configVersion of the machine config node spec. format: int64 - minimum: 0 type: integer - x-kubernetes-validations: - - message: observedGeneration must not decrease - rule: self >= oldSelf pinnedImageSets: - description: pinnedImageSets describes the current and desired pinned - image sets for this node. + description: |- + pinnedImageSets describes the current and desired pinned image sets for this node. + The current version is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. + The desired version is the generation of the pinned image set that is targeted to be pulled and pinned on this node. items: - description: MachineConfigNodeStatusPinnedImageSet holds information - about the current, desired, and failed pinned image sets for the - observed machine config node. properties: currentGeneration: description: currentGeneration is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. format: int32 - minimum: 0 type: integer - x-kubernetes-validations: - - message: currentGeneration must not decrease - rule: self >= oldSelf desiredGeneration: - description: desiredGeneration is the generation of the pinned - image set that is targeted to be pulled and pinned on this - node. + description: desiredGeneration version is the generation of + the pinned image set that is targeted to be pulled and pinned + on this node. format: int32 minimum: 0 type: integer - x-kubernetes-validations: - - message: desiredGeneration must not decrease - rule: self >= oldSelf lastFailedGeneration: description: lastFailedGeneration is the generation of the most recent pinned image set that failed to be pulled and pinned @@ -320,28 +318,22 @@ spec: format: int32 minimum: 0 type: integer - x-kubernetes-validations: - - message: lastFailedGeneration must not decrease - rule: self >= oldSelf - lastFailedGenerationError: - description: |- - lastFailedGenerationError is the error explaining why the desired images failed to be pulled and pinned. - The error is an empty string if the image pull and pin is successful. - maxLength: 32768 - type: string + lastFailedGenerationErrors: + description: lastFailedGenerationErrors is a list of errors + why the lastFailed generation failed to be pulled and pinned. + items: + type: string + maxItems: 10 + type: array name: description: |- name is the name of the pinned image set. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start - and end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object @@ -350,14 +342,13 @@ spec: current generation rule: 'has(self.desiredGeneration) && has(self.currentGeneration) ? self.desiredGeneration >= self.currentGeneration : true' - - message: desired generation must be greater than or equal to the - last failed generation + - message: desired generation must be greater than last failed generation rule: 'has(self.lastFailedGeneration) && has(self.desiredGeneration) ? self.desiredGeneration >= self.lastFailedGeneration : true' - - message: last failed generation error must be defined on image - pull and pin failure - rule: 'has(self.lastFailedGeneration) ? has(self.lastFailedGenerationError) - : true' + - message: desired generation must be defined if last failed generation + is defined + rule: 'has(self.lastFailedGeneration) ? has(self.desiredGeneration): + true' maxItems: 100 type: array x-kubernetes-list-map-keys: @@ -365,6 +356,7 @@ spec: x-kubernetes-list-type: map required: - configVersion + - observedGeneration type: object required: - spec diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-TechPreviewNoUpgrade.crd.yaml b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-TechPreviewNoUpgrade.crd.yaml index 938a4b71c5..830f0734d2 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-TechPreviewNoUpgrade.crd.yaml +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-TechPreviewNoUpgrade.crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - api-approved.openshift.io: https://github.com/openshift/api/pull/2256 + api-approved.openshift.io: https://github.com/openshift/api/pull/1596 api.openshift.io/merged-by-featuregates: "true" include.release.openshift.io/ibm-cloud-managed: "true" include.release.openshift.io/self-managed-high-availability: "true" @@ -52,6 +52,10 @@ spec: name: Resumed priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="UpdateCompatible")].status + name: UpdateCompatible + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="AppliedFilesAndOS")].status name: UpdatedFilesAndOS priority: 1 @@ -68,6 +72,10 @@ spec: name: RebootedNode priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="ReloadedCRIO")].status + name: ReloadedCRIO + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Uncordoned")].status name: UncordonedNode priority: 1 @@ -102,7 +110,7 @@ spec: configVersion: description: |- configVersion holds the desired config version for the node targeted by this machine config node resource. - The desired version represents the machine config the node will attempt to update to and gets set before the machine config operator validates + The desired version represents the machine config the node will attempt to update to. This gets set before the machine config operator validates the new machine config against the current machine config. properties: desired: @@ -111,16 +119,12 @@ spec: This value is set when the machine config pool generates a new version of its rendered configuration. When this value is changed, the machine config daemon starts the node upgrade process. This value gets set in the machine config node spec once the machine config has been targeted for upgrade and before it is validated. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - desired type: object @@ -130,21 +134,38 @@ spec: properties: name: description: |- - name is the name of the object being referenced. For example, this can represent a machine - config pool or node name. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + name is the object name. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object + pinnedImageSets: + description: pinnedImageSets holds the desired pinned image sets that + this node should pin and pull. + items: + properties: + name: + description: |- + name is the name of the pinned image set. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + required: + - name + type: object + maxItems: 100 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map pool: description: |- pool contains a reference to the machine config pool that this machine config node's @@ -152,18 +173,13 @@ spec: properties: name: description: |- - name is the name of the object being referenced. For example, this can represent a machine - config pool or node name. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + name is the object name. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object @@ -233,86 +249,68 @@ spec: - status - type type: object - maxItems: 20 type: array x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map configVersion: - description: configVersion describes the current and desired machine - config version for this node. + description: |- + configVersion describes the current and desired machine config for this node. + The current version represents the current machine config for the node and is updated after a successful update. + The desired version represents the machine config the node will attempt to update to. + This desired machine config has been compared to the current machine config and has been validated by the machine config operator as one that is valid and that exists. properties: current: description: |- current is the name of the machine config currently in use on the node. This value is updated once the machine config daemon has completed the update of the configuration for the node. This value should match the desired version unless an upgrade is in progress. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' desired: description: |- desired is the MachineConfig the node wants to upgrade to. This value gets set in the machine config node status once the machine config has been validated against the current machine config. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start and - end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - desired type: object observedGeneration: description: |- - observedGeneration represents the generation of the MachineConfigNode object observed by the Machine Config Operator's controller. + observedGeneration represents the generation observed by the controller. This field is updated when the controller observes a change to the desiredConfig in the configVersion of the machine config node spec. format: int64 - minimum: 0 type: integer - x-kubernetes-validations: - - message: observedGeneration must not decrease - rule: self >= oldSelf pinnedImageSets: - description: pinnedImageSets describes the current and desired pinned - image sets for this node. + description: |- + pinnedImageSets describes the current and desired pinned image sets for this node. + The current version is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. + The desired version is the generation of the pinned image set that is targeted to be pulled and pinned on this node. items: - description: MachineConfigNodeStatusPinnedImageSet holds information - about the current, desired, and failed pinned image sets for the - observed machine config node. properties: currentGeneration: description: currentGeneration is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. format: int32 - minimum: 0 type: integer - x-kubernetes-validations: - - message: currentGeneration must not decrease - rule: self >= oldSelf desiredGeneration: - description: desiredGeneration is the generation of the pinned - image set that is targeted to be pulled and pinned on this - node. + description: desiredGeneration version is the generation of + the pinned image set that is targeted to be pulled and pinned + on this node. format: int32 minimum: 0 type: integer - x-kubernetes-validations: - - message: desiredGeneration must not decrease - rule: self >= oldSelf lastFailedGeneration: description: lastFailedGeneration is the generation of the most recent pinned image set that failed to be pulled and pinned @@ -320,28 +318,22 @@ spec: format: int32 minimum: 0 type: integer - x-kubernetes-validations: - - message: lastFailedGeneration must not decrease - rule: self >= oldSelf - lastFailedGenerationError: - description: |- - lastFailedGenerationError is the error explaining why the desired images failed to be pulled and pinned. - The error is an empty string if the image pull and pin is successful. - maxLength: 32768 - type: string + lastFailedGenerationErrors: + description: lastFailedGenerationErrors is a list of errors + why the lastFailed generation failed to be pulled and pinned. + items: + type: string + maxItems: 10 + type: array name: description: |- name is the name of the pinned image set. - Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting - of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end - with an alphanumeric character, and be at most 253 characters in length. + Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + It may consist of only alphanumeric characters, hyphens (-) and periods (.) + and must be at most 253 characters in length. maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ type: string - x-kubernetes-validations: - - message: a lowercase RFC 1123 subdomain must consist of lower - case alphanumeric characters, '-' or '.', and must start - and end with an alphanumeric character. - rule: '!format.dns1123Subdomain().validate(self).hasValue()' required: - name type: object @@ -350,14 +342,13 @@ spec: current generation rule: 'has(self.desiredGeneration) && has(self.currentGeneration) ? self.desiredGeneration >= self.currentGeneration : true' - - message: desired generation must be greater than or equal to the - last failed generation + - message: desired generation must be greater than last failed generation rule: 'has(self.lastFailedGeneration) && has(self.desiredGeneration) ? self.desiredGeneration >= self.lastFailedGeneration : true' - - message: last failed generation error must be defined on image - pull and pin failure - rule: 'has(self.lastFailedGeneration) ? has(self.lastFailedGenerationError) - : true' + - message: desired generation must be defined if last failed generation + is defined + rule: 'has(self.lastFailedGeneration) ? has(self.desiredGeneration): + true' maxItems: 100 type: array x-kubernetes-list-map-keys: @@ -365,6 +356,7 @@ spec: x-kubernetes-list-type: map required: - configVersion + - observedGeneration type: object required: - spec diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.deepcopy.go index 53dfa95b27..32e37bb5ff 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.deepcopy.go @@ -92,7 +92,7 @@ func (in *MachineConfigNode) DeepCopyInto(out *MachineConfigNode) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } @@ -154,6 +154,11 @@ func (in *MachineConfigNodeSpec) DeepCopyInto(out *MachineConfigNodeSpec) { out.Node = in.Node out.Pool = in.Pool out.ConfigVersion = in.ConfigVersion + if in.PinnedImageSets != nil { + in, out := &in.PinnedImageSets, &out.PinnedImageSets + *out = make([]MachineConfigNodeSpecPinnedImageSet, len(*in)) + copy(*out, *in) + } return } @@ -183,6 +188,22 @@ func (in *MachineConfigNodeSpecMachineConfigVersion) DeepCopy() *MachineConfigNo return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MachineConfigNodeSpecPinnedImageSet) DeepCopyInto(out *MachineConfigNodeSpecPinnedImageSet) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfigNodeSpecPinnedImageSet. +func (in *MachineConfigNodeSpecPinnedImageSet) DeepCopy() *MachineConfigNodeSpecPinnedImageSet { + if in == nil { + return nil + } + out := new(MachineConfigNodeSpecPinnedImageSet) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MachineConfigNodeStatus) DeepCopyInto(out *MachineConfigNodeStatus) { *out = *in @@ -197,7 +218,9 @@ func (in *MachineConfigNodeStatus) DeepCopyInto(out *MachineConfigNodeStatus) { if in.PinnedImageSets != nil { in, out := &in.PinnedImageSets, &out.PinnedImageSets *out = make([]MachineConfigNodeStatusPinnedImageSet, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } return } @@ -231,6 +254,11 @@ func (in *MachineConfigNodeStatusMachineConfigVersion) DeepCopy() *MachineConfig // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MachineConfigNodeStatusPinnedImageSet) DeepCopyInto(out *MachineConfigNodeStatusPinnedImageSet) { *out = *in + if in.LastFailedGenerationErrors != nil { + in, out := &in.LastFailedGenerationErrors, &out.LastFailedGenerationErrors + *out = make([]string, len(*in)) + copy(*out, *in) + } return } diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests.yaml index dd5be0d37f..ea7bbeeb54 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests.yaml @@ -1,6 +1,6 @@ machineconfignodes.machineconfiguration.openshift.io: Annotations: {} - ApprovedPRNumber: https://github.com/openshift/api/pull/2256 + ApprovedPRNumber: https://github.com/openshift/api/pull/1596 CRDName: machineconfignodes.machineconfiguration.openshift.io Capability: "" Category: "" @@ -48,6 +48,10 @@ machineconfignodes.machineconfiguration.openshift.io: name: Resumed priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="UpdateCompatible")].status + name: UpdateCompatible + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="AppliedFilesAndOS")].status name: UpdatedFilesAndOS priority: 1 @@ -64,6 +68,10 @@ machineconfignodes.machineconfiguration.openshift.io: name: RebootedNode priority: 1 type: string + - jsonPath: .status.conditions[?(@.type=="ReloadedCRIO")].status + name: ReloadedCRIO + priority: 1 + type: string - jsonPath: .status.conditions[?(@.type=="Uncordoned")].status name: UncordonedNode priority: 1 diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go index efb4ef8378..f2592eaf73 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go @@ -13,7 +13,7 @@ package v1alpha1 // AUTO-GENERATED FUNCTIONS START HERE var map_MCOObjectReference = map[string]string{ "": "MCOObjectReference holds information about an object the MCO either owns or modifies in some way", - "name": "name is the name of the object being referenced. For example, this can represent a machine config pool or node name. Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end with an alphanumeric character, and be at most 253 characters in length.", + "name": "name is the object name. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) It may consist of only alphanumeric characters, hyphens (-) and periods (.) and must be at most 253 characters in length.", } func (MCOObjectReference) SwaggerDoc() map[string]string { @@ -21,10 +21,9 @@ func (MCOObjectReference) SwaggerDoc() map[string]string { } var map_MachineConfigNode = map[string]string{ - "": "MachineConfigNode describes the health of the Machines on the system Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", - "metadata": "metadata is the standard object metadata.", - "spec": "spec describes the configuration of the machine config node.", - "status": "status describes the last observed state of this machine config node.", + "": "MachineConfigNode describes the health of the Machines on the system Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", + "spec": "spec describes the configuration of the machine config node.", + "status": "status describes the last observed state of this machine config node.", } func (MachineConfigNode) SwaggerDoc() map[string]string { @@ -32,9 +31,7 @@ func (MachineConfigNode) SwaggerDoc() map[string]string { } var map_MachineConfigNodeList = map[string]string{ - "": "MachineConfigNodeList describes all of the MachinesStates on the system\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", - "metadata": "metadata is the standard list metadata.", - "items": "items contains a collection of MachineConfigNode resources.", + "": "MachineConfigNodeList describes all of the MachinesStates on the system\n\nCompatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.", } func (MachineConfigNodeList) SwaggerDoc() map[string]string { @@ -42,10 +39,11 @@ func (MachineConfigNodeList) SwaggerDoc() map[string]string { } var map_MachineConfigNodeSpec = map[string]string{ - "": "MachineConfigNodeSpec describes the MachineConfigNode we are managing.", - "node": "node contains a reference to the node for this machine config node.", - "pool": "pool contains a reference to the machine config pool that this machine config node's referenced node belongs to.", - "configVersion": "configVersion holds the desired config version for the node targeted by this machine config node resource. The desired version represents the machine config the node will attempt to update to and gets set before the machine config operator validates the new machine config against the current machine config.", + "": "MachineConfigNodeSpec describes the MachineConfigNode we are managing.", + "node": "node contains a reference to the node for this machine config node.", + "pool": "pool contains a reference to the machine config pool that this machine config node's referenced node belongs to.", + "configVersion": "configVersion holds the desired config version for the node targeted by this machine config node resource. The desired version represents the machine config the node will attempt to update to. This gets set before the machine config operator validates the new machine config against the current machine config.", + "pinnedImageSets": "pinnedImageSets holds the desired pinned image sets that this node should pin and pull.", } func (MachineConfigNodeSpec) SwaggerDoc() map[string]string { @@ -53,20 +51,28 @@ func (MachineConfigNodeSpec) SwaggerDoc() map[string]string { } var map_MachineConfigNodeSpecMachineConfigVersion = map[string]string{ - "": "MachineConfigNodeSpecMachineConfigVersion holds the desired config version for the current observed machine config node. When Current is not equal to Desired, the MachineConfigOperator is in an upgrade phase and the machine config node will take account of upgrade related events. Otherwise, they will be ignored given that certain operations happen both during the MCO's upgrade mode and the daily operations mode.", - "desired": "desired is the name of the machine config that the the node should be upgraded to. This value is set when the machine config pool generates a new version of its rendered configuration. When this value is changed, the machine config daemon starts the node upgrade process. This value gets set in the machine config node spec once the machine config has been targeted for upgrade and before it is validated. Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end with an alphanumeric character, and be at most 253 characters in length.", + "": "MachineConfigNodeSpecMachineConfigVersion holds the desired config version for the current observed machine config node. When Current is not equal to Desired; the MachineConfigOperator is in an upgrade phase and the machine config node will take account of upgrade related events. Otherwise they will be ignored given that certain operations happen both during the MCO's upgrade mode and the daily operations mode.", + "desired": "desired is the name of the machine config that the the node should be upgraded to. This value is set when the machine config pool generates a new version of its rendered configuration. When this value is changed, the machine config daemon starts the node upgrade process. This value gets set in the machine config node spec once the machine config has been targeted for upgrade and before it is validated. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) It may consist of only alphanumeric characters, hyphens (-) and periods (.) and must be at most 253 characters in length.", } func (MachineConfigNodeSpecMachineConfigVersion) SwaggerDoc() map[string]string { return map_MachineConfigNodeSpecMachineConfigVersion } +var map_MachineConfigNodeSpecPinnedImageSet = map[string]string{ + "name": "name is the name of the pinned image set. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) It may consist of only alphanumeric characters, hyphens (-) and periods (.) and must be at most 253 characters in length.", +} + +func (MachineConfigNodeSpecPinnedImageSet) SwaggerDoc() map[string]string { + return map_MachineConfigNodeSpecPinnedImageSet +} + var map_MachineConfigNodeStatus = map[string]string{ "": "MachineConfigNodeStatus holds the reported information on a particular machine config node.", "conditions": "conditions represent the observations of a machine config node's current state.", - "observedGeneration": "observedGeneration represents the generation of the MachineConfigNode object observed by the Machine Config Operator's controller. This field is updated when the controller observes a change to the desiredConfig in the configVersion of the machine config node spec.", - "configVersion": "configVersion describes the current and desired machine config version for this node.", - "pinnedImageSets": "pinnedImageSets describes the current and desired pinned image sets for this node.", + "observedGeneration": "observedGeneration represents the generation observed by the controller. This field is updated when the controller observes a change to the desiredConfig in the configVersion of the machine config node spec.", + "configVersion": "configVersion describes the current and desired machine config for this node. The current version represents the current machine config for the node and is updated after a successful update. The desired version represents the machine config the node will attempt to update to. This desired machine config has been compared to the current machine config and has been validated by the machine config operator as one that is valid and that exists.", + "pinnedImageSets": "pinnedImageSets describes the current and desired pinned image sets for this node. The current version is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node. The desired version is the generation of the pinned image set that is targeted to be pulled and pinned on this node.", } func (MachineConfigNodeStatus) SwaggerDoc() map[string]string { @@ -74,9 +80,9 @@ func (MachineConfigNodeStatus) SwaggerDoc() map[string]string { } var map_MachineConfigNodeStatusMachineConfigVersion = map[string]string{ - "": "MachineConfigNodeStatusMachineConfigVersion holds the current and desired config versions as last updated in the MCN status. When the current and desired versions do not match, the machine config pool is processing an upgrade and the machine config node will monitor the upgrade process. When the current and desired versions do match, the machine config node will ignore these events given that certain operations happen both during the MCO's upgrade mode and the daily operations mode.", - "current": "current is the name of the machine config currently in use on the node. This value is updated once the machine config daemon has completed the update of the configuration for the node. This value should match the desired version unless an upgrade is in progress. Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end with an alphanumeric character, and be at most 253 characters in length.", - "desired": "desired is the MachineConfig the node wants to upgrade to. This value gets set in the machine config node status once the machine config has been validated against the current machine config. Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end with an alphanumeric character, and be at most 253 characters in length.", + "": "MachineConfigNodeStatusMachineConfigVersion holds the current and desired config versions as last updated in the MCN status. When the current and desired versions are not matched, the machine config pool is processing an upgrade and the machine config node will monitor the upgrade process. When the current and desired versions do not match, the machine config node will ignore these events given that certain operations happen both during the MCO's upgrade mode and the daily operations mode.", + "current": "current is the name of the machine config currently in use on the node. This value is updated once the machine config daemon has completed the update of the configuration for the node. This value should match the desired version unless an upgrade is in progress. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) It may consist of only alphanumeric characters, hyphens (-) and periods (.) and must be at most 253 characters in length.", + "desired": "desired is the MachineConfig the node wants to upgrade to. This value gets set in the machine config node status once the machine config has been validated against the current machine config. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) It may consist of only alphanumeric characters, hyphens (-) and periods (.) and must be at most 253 characters in length.", } func (MachineConfigNodeStatusMachineConfigVersion) SwaggerDoc() map[string]string { @@ -84,12 +90,11 @@ func (MachineConfigNodeStatusMachineConfigVersion) SwaggerDoc() map[string]strin } var map_MachineConfigNodeStatusPinnedImageSet = map[string]string{ - "": "MachineConfigNodeStatusPinnedImageSet holds information about the current, desired, and failed pinned image sets for the observed machine config node.", - "name": "name is the name of the pinned image set. Must be a lowercase RFC-1123 subdomain name (https://tools.ietf.org/html/rfc1123) consisting of only lowercase alphanumeric characters, hyphens (-), and periods (.), and must start and end with an alphanumeric character, and be at most 253 characters in length.", - "currentGeneration": "currentGeneration is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node.", - "desiredGeneration": "desiredGeneration is the generation of the pinned image set that is targeted to be pulled and pinned on this node.", - "lastFailedGeneration": "lastFailedGeneration is the generation of the most recent pinned image set that failed to be pulled and pinned on this node.", - "lastFailedGenerationError": "lastFailedGenerationError is the error explaining why the desired images failed to be pulled and pinned. The error is an empty string if the image pull and pin is successful.", + "name": "name is the name of the pinned image set. Must be a lowercase RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) It may consist of only alphanumeric characters, hyphens (-) and periods (.) and must be at most 253 characters in length.", + "currentGeneration": "currentGeneration is the generation of the pinned image set that has most recently been successfully pulled and pinned on this node.", + "desiredGeneration": "desiredGeneration version is the generation of the pinned image set that is targeted to be pulled and pinned on this node.", + "lastFailedGeneration": "lastFailedGeneration is the generation of the most recent pinned image set that failed to be pulled and pinned on this node.", + "lastFailedGenerationErrors": "lastFailedGenerationErrors is a list of errors why the lastFailed generation failed to be pulled and pinned.", } func (MachineConfigNodeStatusPinnedImageSet) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/payload-command/render/render.go b/vendor/github.com/openshift/api/payload-command/render/render.go index 3fa9c4bc6a..b0cadf9934 100644 --- a/vendor/github.com/openshift/api/payload-command/render/render.go +++ b/vendor/github.com/openshift/api/payload-command/render/render.go @@ -3,17 +3,18 @@ package render import ( "flag" "fmt" - "github.com/openshift/api/features" "os" "path/filepath" "sort" "strings" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - + "github.com/blang/semver/v4" configv1 "github.com/openshift/api/config/v1" + "github.com/openshift/api/features" assets "github.com/openshift/api/payload-command/render/renderassets" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" ) @@ -66,6 +67,32 @@ func (o *RenderOpts) Run() error { if err != nil { return fmt.Errorf("problem with featuregate manifests: %w", err) } + + nodeConfigManifests, err := nodeConfigManifests([]string{o.RenderedManifestInputFilename}) + if err != nil { + return fmt.Errorf("problem with node config manifests: %w", err) + } + var minimumKubeletVersion *semver.Version + for _, manifest := range nodeConfigManifests { + uncastObj, err := manifest.GetDecodedObj() + if err != nil { + return fmt.Errorf("error decoding FeatureGate: %w", err) + } + nodeConfig := &configv1.Node{} + err = runtime.DefaultUnstructuredConverter.FromUnstructured(uncastObj.(*unstructured.Unstructured).Object, nodeConfig) + if err != nil { + return fmt.Errorf("error converting NodeConfig: %w", err) + } + // TODO FIXME: how do we handle multiple? + if nodeConfig.Spec.MinimumKubeletVersion != "" { + v, err := semver.Parse(nodeConfig.Spec.MinimumKubeletVersion) + if err != nil { + return fmt.Errorf("failed to parse provided minimum kubelet version: %w", err) + } + minimumKubeletVersion = &v + } + } + clusterProfileAnnotationName := fmt.Sprintf("include.release.openshift.io/%s", o.UnprefixedClusterProfile) for _, featureGateFile := range featureGateFiles { @@ -109,7 +136,8 @@ func (o *RenderOpts) Run() error { if err != nil { return fmt.Errorf("unable to resolve featureGateStatus: %w", err) } - currentDetails := FeaturesGateDetailsFromFeatureSets(featureGateStatus, o.PayloadVersion) + currentDetails := FeaturesGateDetailsFromFeatureSets(featureGateStatus, o.PayloadVersion, minimumKubeletVersion, featureGates.Spec.FeatureSet) + featureGates.Status.FeatureGates = []configv1.FeatureGateDetails{*currentDetails} featureGateOutBytes := writeFeatureGateV1OrDie(featureGates) @@ -227,6 +255,27 @@ func clusterProfilesFrom(annotations map[string]string) sets.Set[string] { } func featureGateManifests(renderedManifestInputFilenames []string) (assets.RenderedManifests, error) { + inputManifests, err := loadManifests(renderedManifestInputFilenames) + if err != nil { + return nil, err + } + featureGates := inputManifests.ListManifestOfType(configv1.GroupVersion.WithKind("FeatureGate")) + if len(featureGates) == 0 { + return nil, fmt.Errorf("no FeatureGates found in manfest dir: %v", renderedManifestInputFilenames) + } + + return featureGates, nil +} + +func nodeConfigManifests(renderedManifestInputFilenames []string) (assets.RenderedManifests, error) { + inputManifests, err := loadManifests(renderedManifestInputFilenames) + if err != nil { + return nil, err + } + return inputManifests.ListManifestOfType(configv1.GroupVersion.WithKind("Node")), nil +} + +func loadManifests(renderedManifestInputFilenames []string) (assets.RenderedManifests, error) { if len(renderedManifestInputFilenames) == 0 { return nil, fmt.Errorf("cannot return FeatureGate without rendered manifests") } @@ -244,23 +293,72 @@ func featureGateManifests(renderedManifestInputFilenames []string) (assets.Rende }) } } - featureGates := inputManifests.ListManifestOfType(configv1.GroupVersion.WithKind("FeatureGate")) - if len(featureGates) == 0 { - return nil, fmt.Errorf("no FeatureGates found in manfest dir: %v", renderedManifestInputFilenames) - } - - return featureGates, nil + return inputManifests, nil } -func FeaturesGateDetailsFromFeatureSets(featureGateStatus *features.FeatureGateEnabledDisabled, currentVersion string) *configv1.FeatureGateDetails { +func FeaturesGateDetailsFromFeatureSets(featureGateStatus *features.FeatureGateEnabledDisabled, currentVersion string, minimumKubeletVersion *semver.Version, featureSet configv1.FeatureSet) *configv1.FeatureGateDetails { currentDetails := configv1.FeatureGateDetails{ Version: currentVersion, } + skippedForVersion := map[configv1.FeatureGateName]bool{} for _, gateName := range featureGateStatus.Enabled { - currentDetails.Enabled = append(currentDetails.Enabled, *gateName.FeatureGateAttributes.DeepCopy()) + // Skip adding if we have a RequiredMinimumComponentVersion, as we'll handle that below + if len(gateName.FeatureGateAttributes.RequiredMinimumComponentVersions) != 0 && featureSet == configv1.Default { + skippedForVersion[gateName.FeatureGateAttributes.Name] = false + } else { + currentDetails.Enabled = append(currentDetails.Enabled, *gateName.FeatureGateAttributes.DeepCopy()) + } } for _, gateName := range featureGateStatus.Disabled { - currentDetails.Disabled = append(currentDetails.Disabled, *gateName.FeatureGateAttributes.DeepCopy()) + // Skip adding if we have a RequiredMinimumComponentVersion, as we'll handle that below + if len(gateName.FeatureGateAttributes.RequiredMinimumComponentVersions) != 0 && featureSet == configv1.Default { + skippedForVersion[gateName.FeatureGateAttributes.Name] = false + } else { + currentDetails.Disabled = append(currentDetails.Disabled, *gateName.FeatureGateAttributes.DeepCopy()) + } + } + + if minimumKubeletVersion != nil { + for versionStr, attrs := range featureGateStatus.EnabledGivenMinimumVersion[configv1.MinimumComponentKubelet] { + gateVersion, err := semver.Parse(versionStr) + if err != nil { + // Programming error, as these are built into the binary in features/feature.go + panic(err) + } + if minimumKubeletVersion.LTE(gateVersion) { + for _, attr := range attrs { + currentDetails.Enabled = append(currentDetails.Enabled, attr) + skippedForVersion[attr.Name] = true + } + } else { + for _, attr := range attrs { + currentDetails.Disabled = append(currentDetails.Disabled, attr) + skippedForVersion[attr.Name] = true + } + } + } + } else { + for _, attrs := range featureGateStatus.EnabledGivenMinimumVersion[configv1.MinimumComponentKubelet] { + for _, attr := range attrs { + currentDetails.Disabled = append(currentDetails.Disabled, attr) + skippedForVersion[attr.Name] = true + } + } + } + + for name, missed := range skippedForVersion { + if !missed { + // Programming error: a gate was registered as skipped but not addressed + panic(fmt.Errorf("Missed feature gate name %s when constructing featureGateStatus", name)) + } + } + if minimumKubeletVersion != nil { + currentDetails.RenderedMinimumComponentVersions = []configv1.MinimumComponentVersion{ + { + Component: configv1.MinimumComponentKubelet, + Version: minimumKubeletVersion.String(), + }, + } } // sort for stability diff --git a/vendor/github.com/openshift/api/payload-command/render/write_featureset.go b/vendor/github.com/openshift/api/payload-command/render/write_featureset.go index 009d31f6b7..0d00afa7b3 100644 --- a/vendor/github.com/openshift/api/payload-command/render/write_featureset.go +++ b/vendor/github.com/openshift/api/payload-command/render/write_featureset.go @@ -3,13 +3,14 @@ package render import ( "flag" "fmt" + "os" + "path/filepath" + "strings" + configv1 "github.com/openshift/api/config/v1" "github.com/openshift/api/features" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" - "os" - "path/filepath" - "strings" ) var ( @@ -61,7 +62,7 @@ func (o *WriteFeatureSets) Run() error { newLegacyFeatureGates.Insert(string(curr.FeatureGateAttributes.Name)) } } - currentDetails := FeaturesGateDetailsFromFeatureSets(featureGateStatuses, o.PayloadVersion) + currentDetails := FeaturesGateDetailsFromFeatureSets(featureGateStatuses, o.PayloadVersion, nil, featureSetName) featureGateInstance := &configv1.FeatureGate{ ObjectMeta: metav1.ObjectMeta{ diff --git a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/annotations.go b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/annotations.go index 5ce9fa2934..fa9709ec06 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/annotations.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/annotations.go @@ -1,8 +1,10 @@ package certrotation import ( + "github.com/google/go-cmp/cmp" "github.com/openshift/api/annotations" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" ) const ( @@ -25,14 +27,20 @@ func (a AdditionalAnnotations) EnsureTLSMetadataUpdate(meta *metav1.ObjectMeta) meta.Annotations = make(map[string]string) } if len(a.JiraComponent) > 0 && meta.Annotations[annotations.OpenShiftComponent] != a.JiraComponent { + diff := cmp.Diff(meta.Annotations[annotations.OpenShiftComponent], a.JiraComponent) + klog.V(2).Infof("Updating %q annotation for %s/%s, diff: %s", annotations.OpenShiftComponent, meta.Name, meta.Namespace, diff) meta.Annotations[annotations.OpenShiftComponent] = a.JiraComponent modified = true } if len(a.Description) > 0 && meta.Annotations[annotations.OpenShiftDescription] != a.Description { + diff := cmp.Diff(meta.Annotations[annotations.OpenShiftDescription], a.Description) + klog.V(2).Infof("Updating %q annotation for %s/%s, diff: %s", annotations.OpenShiftDescription, meta.Name, meta.Namespace, diff) meta.Annotations[annotations.OpenShiftDescription] = a.Description modified = true } if len(a.AutoRegenerateAfterOfflineExpiry) > 0 && meta.Annotations[AutoRegenerateAfterOfflineExpiryAnnotation] != a.AutoRegenerateAfterOfflineExpiry { + diff := cmp.Diff(meta.Annotations[AutoRegenerateAfterOfflineExpiryAnnotation], a.AutoRegenerateAfterOfflineExpiry) + klog.V(2).Infof("Updating %q annotation for %s/%s, diff: %s", AutoRegenerateAfterOfflineExpiryAnnotation, meta.Name, meta.Namespace, diff) meta.Annotations[AutoRegenerateAfterOfflineExpiryAnnotation] = a.AutoRegenerateAfterOfflineExpiry modified = true } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/cabundle.go b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/cabundle.go index 1cb4685b1f..447b1e0e31 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/cabundle.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/cabundle.go @@ -30,6 +30,10 @@ type CABundleConfigMap struct { Namespace string // Name is the name of the ConfigMap to maintain. Name string + // RefreshOnlyWhenExpired set to true means to ignore 80% of validity and the Refresh duration for rotation, + // but only rotate when the certificate expires. This is useful for auto-recovery when we want to enforce + // rotation on expiration only, but not interfere with the ordinary rotation controller. + RefreshOnlyWhenExpired bool // Owner is an optional reference to add to the secret that this rotator creates. Owner *metav1.OwnerReference // AdditionalAnnotations is a collection of annotations set for the secret @@ -62,12 +66,15 @@ func (c CABundleConfigMap) EnsureConfigMapCABundle(ctx context.Context, signingC creationRequired = true } - needsOwnerUpdate := false - if c.Owner != nil { - needsOwnerUpdate = ensureOwnerReference(&caBundleConfigMap.ObjectMeta, c.Owner) + // run Update if metadata needs changing unless running in RefreshOnlyWhenExpired mode + if !c.RefreshOnlyWhenExpired { + needsOwnerUpdate := false + if c.Owner != nil { + needsOwnerUpdate = ensureOwnerReference(&caBundleConfigMap.ObjectMeta, c.Owner) + } + needsMetadataUpdate := c.AdditionalAnnotations.EnsureTLSMetadataUpdate(&caBundleConfigMap.ObjectMeta) + updateRequired = needsOwnerUpdate || needsMetadataUpdate } - needsMetadataUpdate := c.AdditionalAnnotations.EnsureTLSMetadataUpdate(&caBundleConfigMap.ObjectMeta) - updateRequired = needsOwnerUpdate || needsMetadataUpdate updatedCerts, err := manageCABundleConfigMap(caBundleConfigMap, signingCertKeyPair.Config.Certs[0]) if err != nil { @@ -98,6 +105,10 @@ func (c CABundleConfigMap) EnsureConfigMapCABundle(ctx context.Context, signingC caBundleConfigMap = actualCABundleConfigMap } else if updateRequired { actualCABundleConfigMap, err := c.Client.ConfigMaps(c.Namespace).Update(ctx, caBundleConfigMap, metav1.UpdateOptions{}) + if apierrors.IsConflict(err) { + // ignore error if its attempting to update outdated version of the configmap + return nil, nil + } resourcehelper.ReportUpdateEvent(c.EventRecorder, actualCABundleConfigMap, err) if err != nil { return nil, err diff --git a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/client_cert_rotation_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/client_cert_rotation_controller.go index d8569f2c8d..b7a7a69c7a 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/client_cert_rotation_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/client_cert_rotation_controller.go @@ -130,7 +130,7 @@ func (c CertRotationController) getSigningCertKeyPairLocation() string { func (c CertRotationController) SyncWorker(ctx context.Context) error { signingCertKeyPair, _, err := c.RotatedSigningCASecret.EnsureSigningCertKeyPair(ctx) - if err != nil { + if err != nil || signingCertKeyPair == nil { return err } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/signer.go b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/signer.go index 2eb761bbb3..de9eb11b72 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/signer.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/signer.go @@ -78,10 +78,12 @@ func (c RotatedSigningCASecret) EnsureSigningCertKeyPair(ctx context.Context) (* creationRequired = true } - // run Update if metadata needs changing - needsMetadataUpdate := ensureMetadataUpdate(signingCertKeyPairSecret, c.Owner, c.AdditionalAnnotations) - needsTypeChange := ensureSecretTLSTypeSet(signingCertKeyPairSecret) - updateRequired = needsMetadataUpdate || needsTypeChange + // run Update if metadata needs changing unless we're in RefreshOnlyWhenExpired mode + if !c.RefreshOnlyWhenExpired { + needsMetadataUpdate := ensureMetadataUpdate(signingCertKeyPairSecret, c.Owner, c.AdditionalAnnotations) + needsTypeChange := ensureSecretTLSTypeSet(signingCertKeyPairSecret) + updateRequired = needsMetadataUpdate || needsTypeChange + } // run Update if signer content needs changing signerUpdated := false @@ -110,6 +112,10 @@ func (c RotatedSigningCASecret) EnsureSigningCertKeyPair(ctx context.Context) (* signingCertKeyPairSecret = actualSigningCertKeyPairSecret } else if updateRequired { actualSigningCertKeyPairSecret, err := c.Client.Secrets(c.Namespace).Update(ctx, signingCertKeyPairSecret, metav1.UpdateOptions{}) + if apierrors.IsConflict(err) { + // ignore error if its attempting to update outdated version of the secret + return nil, false, nil + } resourcehelper.ReportUpdateEvent(c.EventRecorder, actualSigningCertKeyPairSecret, err) if err != nil { return nil, false, err diff --git a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/target.go b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/target.go index b68aea1633..65dd87eadd 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/certrotation/target.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/certrotation/target.go @@ -112,9 +112,12 @@ func (c RotatedSelfSignedCertKeySecret) EnsureTargetCertKeyPair(ctx context.Cont creationRequired = true } - needsMetadataUpdate := ensureMetadataUpdate(targetCertKeyPairSecret, c.Owner, c.AdditionalAnnotations) - needsTypeChange := ensureSecretTLSTypeSet(targetCertKeyPairSecret) - updateRequired = needsMetadataUpdate || needsTypeChange + // run Update if metadata needs changing unless we're in RefreshOnlyWhenExpired mode + if !c.RefreshOnlyWhenExpired { + needsMetadataUpdate := ensureMetadataUpdate(targetCertKeyPairSecret, c.Owner, c.AdditionalAnnotations) + needsTypeChange := ensureSecretTLSTypeSet(targetCertKeyPairSecret) + updateRequired = needsMetadataUpdate || needsTypeChange + } if reason := c.CertCreator.NeedNewTargetCertKeyPair(targetCertKeyPairSecret, signingCertKeyPair, caBundleCerts, c.Refresh, c.RefreshOnlyWhenExpired, creationRequired); len(reason) > 0 { c.EventRecorder.Eventf("TargetUpdateRequired", "%q in %q requires a new target cert/key pair: %v", c.Name, c.Namespace, reason) @@ -136,6 +139,10 @@ func (c RotatedSelfSignedCertKeySecret) EnsureTargetCertKeyPair(ctx context.Cont targetCertKeyPairSecret = actualTargetCertKeyPairSecret } else if updateRequired { actualTargetCertKeyPairSecret, err := c.Client.Secrets(c.Namespace).Update(ctx, targetCertKeyPairSecret, metav1.UpdateOptions{}) + if apierrors.IsConflict(err) { + // ignore error if its attempting to update outdated version of the secret + return nil, nil + } resourcehelper.ReportUpdateEvent(c.EventRecorder, actualTargetCertKeyPairSecret, err) if err != nil { return nil, err diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go index 5792ada3a5..d2a3244eed 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/featuregate.go @@ -14,17 +14,22 @@ type FeatureGate interface { Enabled(key configv1.FeatureGateName) bool // KnownFeatures returns a slice of strings describing the FeatureGate's known features. KnownFeatures() []configv1.FeatureGateName + // RenderedMinimumComponentVersion returns the minimum component version that caused this set of features + // to be generated. + RenderedMinimumComponentVersions() []configv1.MinimumComponentVersion } type featureGate struct { - enabled []configv1.FeatureGateName - disabled []configv1.FeatureGateName + enabled []configv1.FeatureGateName + disabled []configv1.FeatureGateName + renderedVersion []configv1.MinimumComponentVersion } -func NewFeatureGate(enabled, disabled []configv1.FeatureGateName) FeatureGate { +func NewFeatureGate(enabled, disabled []configv1.FeatureGateName, renderedVersion []configv1.MinimumComponentVersion) FeatureGate { return &featureGate{ - enabled: enabled, - disabled: disabled, + enabled: enabled, + disabled: disabled, + renderedVersion: renderedVersion, } } @@ -46,3 +51,7 @@ func (f *featureGate) KnownFeatures() []configv1.FeatureGateName { return allKnown } + +func (f *featureGate) RenderedMinimumComponentVersions() []configv1.MinimumComponentVersion { + return f.renderedVersion +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go index 58ae71763f..f71e56fa8c 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/hardcoded_featuregate_reader.go @@ -62,7 +62,8 @@ func (c *hardcodedFeatureGateAccess) AreInitialFeatureGatesObserved() bool { } func (c *hardcodedFeatureGateAccess) CurrentFeatureGates() (FeatureGate, error) { - return NewFeatureGate(c.enabled, c.disabled), c.readErr + // TODO FIXME not hardcoded + return NewFeatureGate(c.enabled, c.disabled, nil), c.readErr } // NewHardcodedFeatureGateAccessFromFeatureGate returns a FeatureGateAccess that is static and initialised from diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go index 4b2caccd69..d8676a044c 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/featuregates/simple_featuregate_reader.go @@ -50,8 +50,9 @@ type FeatureGateAccess interface { } type Features struct { - Enabled []configv1.FeatureGateName - Disabled []configv1.FeatureGateName + Enabled []configv1.FeatureGateName + Disabled []configv1.FeatureGateName + RenderedMinimumComponentVersions []configv1.MinimumComponentVersion } type FeatureChange struct { @@ -263,10 +264,12 @@ func (c *defaultFeatureGateAccess) CurrentFeatureGates() (FeatureGate, error) { } retEnabled := make([]configv1.FeatureGateName, len(c.currentFeatures.Enabled)) retDisabled := make([]configv1.FeatureGateName, len(c.currentFeatures.Disabled)) + retRenderedMinimumComponentVersions := make([]configv1.MinimumComponentVersion, len(c.currentFeatures.RenderedMinimumComponentVersions)) copy(retEnabled, c.currentFeatures.Enabled) copy(retDisabled, c.currentFeatures.Disabled) + copy(retRenderedMinimumComponentVersions, c.currentFeatures.RenderedMinimumComponentVersions) - return NewFeatureGate(retEnabled, retDisabled), nil + return NewFeatureGate(retEnabled, retDisabled, retRenderedMinimumComponentVersions), nil } func (c *defaultFeatureGateAccess) runWorker(ctx context.Context) { @@ -308,6 +311,11 @@ func featuresFromFeatureGate(featureGate *configv1.FeatureGate, desiredVersion s features.Disabled = append(features.Disabled, disabled.Name) } break + features.RenderedMinimumComponentVersions = make([]configv1.MinimumComponentVersion, 0, len(featureGateValues.RenderedMinimumComponentVersions)) + for _, cv := range featureGateValues.RenderedMinimumComponentVersions { + features.RenderedMinimumComponentVersions = append(features.RenderedMinimumComponentVersions, cv) + } + } if !found { diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/json_patch_helpers.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/json_patch_helpers.go index ac9699affe..84b50fde18 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/json_patch_helpers.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/json_patch_helpers.go @@ -3,7 +3,7 @@ package resourceapply import ( "fmt" - patch "github.com/evanphx/json-patch" + patch "gopkg.in/evanphx/json-patch.v4" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiregistration.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiregistration.go new file mode 100644 index 0000000000..05a4146ecf --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiregistration.go @@ -0,0 +1,26 @@ +package resourceread + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" +) + +var ( + apiRegisterScheme = runtime.NewScheme() + apiRegisterCodec = serializer.NewCodecFactory(apiRegisterScheme) +) + +func init() { + if err := apiregistrationv1.AddToScheme(apiRegisterScheme); err != nil { + panic(err) + } +} + +func ReadAPIServiceOrDie(objBytes []byte) *apiregistrationv1.APIService { + requiredObj, err := runtime.Decode(apiRegisterCodec.UniversalDecoder(apiregistrationv1.SchemeGroupVersion), objBytes) + if err != nil { + panic(err) + } + return requiredObj.(*apiregistrationv1.APIService) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 95f2be0fba..b9c59b6300 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -363,9 +363,6 @@ github.com/emicklei/go-restful/v3/log # github.com/ettle/strcase v0.2.0 ## explicit; go 1.12 github.com/ettle/strcase -# github.com/evanphx/json-patch v5.6.0+incompatible -## explicit -github.com/evanphx/json-patch # github.com/evanphx/json-patch/v5 v5.9.11 ## explicit; go 1.18 github.com/evanphx/json-patch/v5 @@ -981,7 +978,7 @@ github.com/opencontainers/image-spec/specs-go/v1 # github.com/opencontainers/runtime-spec v1.2.0 ## explicit github.com/opencontainers/runtime-spec/specs-go -# github.com/openshift/api v0.0.0-20250402094343-3d7abe90f97e +# github.com/openshift/api v0.0.0-20250402094343-3d7abe90f97e => github.com/haircommander/api v0.0.0-20250326145233-4e692eb778c9 ## explicit; go 1.23.0 github.com/openshift/api github.com/openshift/api/annotations @@ -1153,7 +1150,7 @@ github.com/openshift/client-go/route/applyconfigurations/route/v1 github.com/openshift/client-go/route/clientset/versioned github.com/openshift/client-go/route/clientset/versioned/scheme github.com/openshift/client-go/route/clientset/versioned/typed/route/v1 -# github.com/openshift/library-go v0.0.0-20250129210218-fe56c2cf5d70 +# github.com/openshift/library-go v0.0.0-20250129210218-fe56c2cf5d70 => github.com/haircommander/library-go v0.0.0-20250320175542-74e1e32dfa76 ## explicit; go 1.23.0 github.com/openshift/library-go/pkg/apiserver/jsonpatch github.com/openshift/library-go/pkg/certs @@ -2749,4 +2746,6 @@ sigs.k8s.io/structured-merge-diff/v4/value sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 sigs.k8s.io/yaml/goyaml.v3 +# github.com/openshift/api => github.com/haircommander/api v0.0.0-20250326145233-4e692eb778c9 +# github.com/openshift/library-go => github.com/haircommander/library-go v0.0.0-20250320175542-74e1e32dfa76 # k8s.io/kube-openapi => github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0 From cb7f56b9559cae6fae115f1f1494e986f666b27a Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Mon, 17 Mar 2025 15:35:19 -0400 Subject: [PATCH 2/3] kubelet-config: refactor features to generate map at a higher level Signed-off-by: Peter Hunt --- .../kubelet_config_bootstrap.go | 8 ++++++- .../kubelet_config_controller.go | 14 +++++------ .../kubelet-config/kubelet_config_features.go | 23 ++++++++++++++----- .../kubelet_config_features_test.go | 15 ++++++------ .../kubelet-config/kubelet_config_nodes.go | 14 +++++++++-- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/pkg/controller/kubelet-config/kubelet_config_bootstrap.go b/pkg/controller/kubelet-config/kubelet_config_bootstrap.go index c56429d057..f72059248a 100644 --- a/pkg/controller/kubelet-config/kubelet_config_bootstrap.go +++ b/pkg/controller/kubelet-config/kubelet_config_bootstrap.go @@ -26,6 +26,12 @@ func RunKubeletBootstrap(templateDir string, kubeletConfigs []*mcfgv1.KubeletCon if nodeConfig == nil { nodeConfig = createNewDefaultNodeconfig() } + + featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return nil, fmt.Errorf("could not generate features map: %w", err) + } + for _, kubeletConfig := range kubeletConfigs { // use selector since label matching part of a KubeletConfig is not handled during the bootstrap selector, err := metav1.LabelSelectorAsSelector(kubeletConfig.Spec.MachineConfigPoolSelector) @@ -41,7 +47,7 @@ func RunKubeletBootstrap(templateDir string, kubeletConfigs []*mcfgv1.KubeletCon } role := pool.Name - originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(controllerConfig, templateDir, role, featureGateAccess, apiServer) + originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(controllerConfig, templateDir, role, featureGates, apiServer) if err != nil { return nil, err } diff --git a/pkg/controller/kubelet-config/kubelet_config_controller.go b/pkg/controller/kubelet-config/kubelet_config_controller.go index 8dd2189ad2..7daf4e04b3 100644 --- a/pkg/controller/kubelet-config/kubelet_config_controller.go +++ b/pkg/controller/kubelet-config/kubelet_config_controller.go @@ -420,7 +420,7 @@ func (ctrl *Controller) handleFeatureErr(err error, key string) { // generateOriginalKubeletConfigWithFeatureGates generates a KubeletConfig and ensure the correct feature gates are set // based on the given FeatureGate. -func generateOriginalKubeletConfigWithFeatureGates(cc *mcfgv1.ControllerConfig, templatesDir, role string, featureGateAccess featuregates.FeatureGateAccess, apiServer *configv1.APIServer) (*kubeletconfigv1beta1.KubeletConfiguration, error) { +func generateOriginalKubeletConfigWithFeatureGates(cc *mcfgv1.ControllerConfig, templatesDir, role string, featureGates map[string]bool, apiServer *configv1.APIServer) (*kubeletconfigv1beta1.KubeletConfiguration, error) { originalKubeletIgn, err := generateOriginalKubeletConfigIgn(cc, templatesDir, role, apiServer) if err != nil { return nil, fmt.Errorf("could not generate the original Kubelet config ignition: %w", err) @@ -437,11 +437,6 @@ func generateOriginalKubeletConfigWithFeatureGates(cc *mcfgv1.ControllerConfig, return nil, fmt.Errorf("could not deserialize the Kubelet source: %w", err) } - featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) - if err != nil { - return nil, fmt.Errorf("could not generate features map: %w", err) - } - // Merge in Feature Gates. // If they are the same, this will be a no-op if err := mergo.Merge(&originalKubeConfig.FeatureGates, featureGates, mergo.WithOverride); err != nil { @@ -634,7 +629,12 @@ func (ctrl *Controller) syncKubeletConfig(key string) error { return fmt.Errorf("could not get ControllerConfig %w", err) } - originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, role, ctrl.featureGateAccess, apiServer) + featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return fmt.Errorf("could not generate features map: %w", err) + } + + originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, role, featureGates, apiServer) if err != nil { return ctrl.syncStatusOnly(cfg, err, "could not get original kubelet config: %v", err) } diff --git a/pkg/controller/kubelet-config/kubelet_config_features.go b/pkg/controller/kubelet-config/kubelet_config_features.go index eae261ff27..b5992f97b7 100644 --- a/pkg/controller/kubelet-config/kubelet_config_features.go +++ b/pkg/controller/kubelet-config/kubelet_config_features.go @@ -99,7 +99,12 @@ func (ctrl *Controller) syncFeatureHandler(key string) error { } } - rawCfgIgn, err := generateKubeConfigIgnFromFeatures(cc, ctrl.templatesDir, role, ctrl.featureGateAccess, nodeConfig, apiServer) + featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return fmt.Errorf("could not generate features map: %w", err) + } + + rawCfgIgn, err := generateKubeConfigIgnFromFeatures(cc, ctrl.templatesDir, role, featureGates, nodeConfig, apiServer) if err != nil { return err } @@ -174,8 +179,9 @@ func (ctrl *Controller) deleteFeature(obj interface{}) { // generateFeatureMap returns a map of enabled/disabled feature gate selection with exclusion list // //nolint:gocritic -func generateFeatureMap(featuregateAccess featuregates.FeatureGateAccess, exclusions ...osev1.FeatureGateName) (*map[string]bool, error) { +func generateFeatureMap(featuregateAccess featuregates.FeatureGateAccess, exclusions ...osev1.FeatureGateName) (map[string]bool, error) { rv := make(map[string]bool) + if !featuregateAccess.AreInitialFeatureGatesObserved() { return nil, fmt.Errorf("initial feature gates are not observed") } @@ -197,11 +203,11 @@ func generateFeatureMap(featuregateAccess featuregates.FeatureGateAccess, exclus for _, excluded := range exclusions { delete(rv, string(excluded)) } - return &rv, nil + return rv, nil } -func generateKubeConfigIgnFromFeatures(cc *mcfgv1.ControllerConfig, templatesDir, role string, featureGateAccess featuregates.FeatureGateAccess, nodeConfig *osev1.Node, apiServer *osev1.APIServer) ([]byte, error) { - originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, templatesDir, role, featureGateAccess, apiServer) +func generateKubeConfigIgnFromFeatures(cc *mcfgv1.ControllerConfig, templatesDir, role string, featureGates map[string]bool, nodeConfig *osev1.Node, apiServer *osev1.APIServer) ([]byte, error) { + originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, templatesDir, role, featureGates, apiServer) if err != nil { return nil, err } @@ -227,12 +233,17 @@ func generateKubeConfigIgnFromFeatures(cc *mcfgv1.ControllerConfig, templatesDir func RunFeatureGateBootstrap(templateDir string, featureGateAccess featuregates.FeatureGateAccess, nodeConfig *osev1.Node, controllerConfig *mcfgv1.ControllerConfig, mcpPools []*mcfgv1.MachineConfigPool, apiServer *osev1.APIServer) ([]*mcfgv1.MachineConfig, error) { machineConfigs := []*mcfgv1.MachineConfig{} + featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return nil, fmt.Errorf("could not generate features map: %w", err) + } + for _, pool := range mcpPools { role := pool.Name if nodeConfig == nil { nodeConfig = createNewDefaultNodeconfig() } - rawCfgIgn, err := generateKubeConfigIgnFromFeatures(controllerConfig, templateDir, role, featureGateAccess, nodeConfig, apiServer) + rawCfgIgn, err := generateKubeConfigIgnFromFeatures(controllerConfig, templateDir, role, featureGates, nodeConfig, apiServer) if err != nil { return nil, err } diff --git a/pkg/controller/kubelet-config/kubelet_config_features_test.go b/pkg/controller/kubelet-config/kubelet_config_features_test.go index 9f88970dec..c095477d9d 100644 --- a/pkg/controller/kubelet-config/kubelet_config_features_test.go +++ b/pkg/controller/kubelet-config/kubelet_config_features_test.go @@ -44,18 +44,17 @@ func TestFeatureGateDrift(t *testing.T) { fgAccess := featuregates.NewHardcodedFeatureGateAccess(features.Spec.FeatureGateSelection.CustomNoUpgrade.Enabled, features.Spec.FeatureGateSelection.CustomNoUpgrade.Disabled) ctrl := f.newController(fgAccess) + featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + require.NoError(t, err) + // Generate kubelet config with feature gates applied - kubeletConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, "master", fgAccess, nil) + kubeletConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, "master", featureGates, nil) require.NoError(t, err) t.Logf("Generated Kubelet Config Feature Gates: %v", kubeletConfig.FeatureGates) - defaultFeatureGates, err := generateFeatureMap(fgAccess) - require.NoError(t, err) - t.Logf("Expected Feature Gates: %v", *defaultFeatureGates) - - if !reflect.DeepEqual(kubeletConfig.FeatureGates, *defaultFeatureGates) { - t.Errorf("Generated kubelet configuration feature gates do not match expected feature gates: generated=%v, expected=%v", kubeletConfig.FeatureGates, *defaultFeatureGates) + if !reflect.DeepEqual(kubeletConfig.FeatureGates, featureGates) { + t.Errorf("Generated kubelet configuration feature gates do not match expected feature gates: generated=%v, expected=%v", kubeletConfig.FeatureGates, featureGates) } }) } @@ -227,7 +226,7 @@ func TestBootstrapFeaturesCustomNoUpgrade(t *testing.T) { if err != nil { t.Errorf("could not generate defaultFeatureGates: %v", err) } - if reflect.DeepEqual(originalKubeConfig.FeatureGates, *defaultFeatureGates) { + if reflect.DeepEqual(originalKubeConfig.FeatureGates, defaultFeatureGates) { t.Errorf("template FeatureGates should not match default openshift/api FeatureGates: (default=%v)", defaultFeatureGates) } if !originalKubeConfig.FeatureGates["CSIMigration"] { diff --git a/pkg/controller/kubelet-config/kubelet_config_nodes.go b/pkg/controller/kubelet-config/kubelet_config_nodes.go index 65a43676e7..e4bd86ee0f 100644 --- a/pkg/controller/kubelet-config/kubelet_config_nodes.go +++ b/pkg/controller/kubelet-config/kubelet_config_nodes.go @@ -94,6 +94,11 @@ func (ctrl *Controller) syncNodeConfigHandler(key string) error { return fmt.Errorf("could not get the TLSSecurityProfile from %v: %v", ctrlcommon.APIServerInstanceName, err) } + featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return fmt.Errorf("could not generate features map: %w", err) + } + for _, pool := range mcpPools { role := pool.Name // Get MachineConfig @@ -113,7 +118,7 @@ func (ctrl *Controller) syncNodeConfigHandler(key string) error { return err } } - originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, role, ctrl.featureGateAccess, apiServer) + originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, role, featureGates, apiServer) if err != nil { return err } @@ -279,6 +284,11 @@ func RunNodeConfigBootstrap(templateDir string, featureGateAccess featuregates.F configs := []*mcfgv1.MachineConfig{} + featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return nil, fmt.Errorf("could not generate features map: %w", err) + } + for _, pool := range mcpPools { role := pool.Name // Get MachineConfig @@ -291,7 +301,7 @@ func RunNodeConfigBootstrap(templateDir string, featureGateAccess featuregates.F if err != nil { return nil, err } - originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cconfig, templateDir, role, featureGateAccess, apiServer) + originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cconfig, templateDir, role, featureGates, apiServer) if err != nil { return nil, err } From 1a7271d20a0a5f010b3ddfb3cc15545fbcafe74a Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Wed, 19 Mar 2025 16:38:10 -0400 Subject: [PATCH 3/3] kubelet config: write back minimum kubelet version status When a cluster admin rolls out a minimum kubelet verison, the cluster-config-operator (eventually) will render a new set of featuregates based on the new minimum version (enabling ones that are safe given the new minimum). However, on a rollback, we need to make sure the MCS won't return a rendered config using the old features, in the very odd case a cluster admin creates a newly old node and somehow overrides the osImage (unlikely). Thus, we use the similar condition as MCS to serve the config--once one node has updated, we treat the MCP as using the new config. Then, we write the status to the node config object so the node authorization plugin can allow older nodes that are now deemed safe. Signed-off-by: Peter Hunt --- .../kubelet_config_bootstrap.go | 3 +- .../kubelet_config_controller.go | 75 +++++++++++++++++-- .../kubelet-config/kubelet_config_features.go | 40 +++++----- .../kubelet_config_features_test.go | 4 +- .../kubelet-config/kubelet_config_nodes.go | 6 +- test/e2e-bootstrap/bootstrap_test.go | 2 +- 6 files changed, 101 insertions(+), 29 deletions(-) diff --git a/pkg/controller/kubelet-config/kubelet_config_bootstrap.go b/pkg/controller/kubelet-config/kubelet_config_bootstrap.go index f72059248a..450569d05d 100644 --- a/pkg/controller/kubelet-config/kubelet_config_bootstrap.go +++ b/pkg/controller/kubelet-config/kubelet_config_bootstrap.go @@ -27,7 +27,8 @@ func RunKubeletBootstrap(templateDir string, kubeletConfigs []*mcfgv1.KubeletCon nodeConfig = createNewDefaultNodeconfig() } - featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) + // TODO FIXME: ignoring min kubelet version writeback for now + featureGates, _, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) if err != nil { return nil, fmt.Errorf("could not generate features map: %w", err) } diff --git a/pkg/controller/kubelet-config/kubelet_config_controller.go b/pkg/controller/kubelet-config/kubelet_config_controller.go index 7daf4e04b3..2e625309b6 100644 --- a/pkg/controller/kubelet-config/kubelet_config_controller.go +++ b/pkg/controller/kubelet-config/kubelet_config_controller.go @@ -42,6 +42,7 @@ import ( mcfglistersv1 "github.com/openshift/client-go/machineconfiguration/listers/machineconfiguration/v1" "github.com/openshift/library-go/pkg/operator/configobserver/featuregates" "github.com/openshift/machine-config-operator/pkg/apihelpers" + "github.com/openshift/machine-config-operator/pkg/constants" ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common" mtmpl "github.com/openshift/machine-config-operator/pkg/controller/template" "github.com/openshift/machine-config-operator/pkg/version" @@ -528,7 +529,7 @@ func (ctrl *Controller) addAnnotation(cfg *mcfgv1.KubeletConfig, annotationKey, // This function is not meant to be invoked concurrently with the same key. // //nolint:gocyclo -func (ctrl *Controller) syncKubeletConfig(key string) error { +func (ctrl *Controller) syncKubeletConfig(key string) (retErr error) { startTime := time.Now() klog.V(4).Infof("Started syncing kubeletconfig %q (%v)", key, startTime) defer func() { @@ -595,6 +596,13 @@ func (ctrl *Controller) syncKubeletConfig(key string) error { return ctrl.syncStatusOnly(cfg, err, "could not get the TLSSecurityProfile from %v: %v", ctrlcommon.APIServerInstanceName, err) } + updatedPools := map[string]int64{} + + featureGates, renderedVersions, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return fmt.Errorf("could not generate features map: %w", err) + } + for _, pool := range mcpPools { if pool.Spec.Configuration.Name == "" { updateDelay := 5 * time.Second @@ -629,11 +637,6 @@ func (ctrl *Controller) syncKubeletConfig(key string) error { return fmt.Errorf("could not get ControllerConfig %w", err) } - featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) - if err != nil { - return fmt.Errorf("could not generate features map: %w", err) - } - originalKubeConfig, err := generateOriginalKubeletConfigWithFeatureGates(cc, ctrl.templatesDir, role, featureGates, apiServer) if err != nil { return ctrl.syncStatusOnly(cfg, err, "could not get original kubelet config: %v", err) @@ -725,13 +728,73 @@ func (ctrl *Controller) syncKubeletConfig(key string) error { } klog.Infof("Applied KubeletConfig %v on MachineConfigPool %v", key, pool.Name) ctrlcommon.UpdateStateMetric(ctrlcommon.MCCSubControllerState, "machine-config-controller-kubelet-config", "Sync Kubelet Config", pool.Name) + updatedPools[pool.Name] = pool.Status.ObservedGeneration } + go ctrl.writebackMinimumKubeletVersionIfAppropriate(updatedPools, renderedVersions, nodeConfig, func() ([]*mcfgv1.MachineConfigPool, error) { + return ctrl.getPoolsForKubeletConfig(cfg) + }) if err := ctrl.cleanUpDuplicatedMC(managedKubeletConfigKeyPrefix); err != nil { return err } return ctrl.syncStatusOnly(cfg, nil) } +func (ctrl *Controller) writebackMinimumKubeletVersionIfAppropriate(updatedPools map[string]int64, renderedVersions []configv1.MinimumComponentVersion, node *osev1.Node, poolGetter func() ([]*mcfgv1.MachineConfigPool, error)) { + renderedKubeletVersion := "" + for _, cv := range renderedVersions { + if cv.Component == configv1.MinimumComponentKubelet { + renderedKubeletVersion = cv.Version + } + } + if node.Spec.MinimumKubeletVersion == node.Status.MinimumKubeletVersion && + node.Status.MinimumKubeletVersion == renderedKubeletVersion { + klog.InfoS("Skipping writeback to nodes.config.Status.MinimumKubeletVersion because situation not correct", + "nodes.config.Spec.MinimumKubeletVerison", node.Spec.MinimumKubeletVersion, + "nodes.config.Status.MinimumKubeletVerison", node.Status.MinimumKubeletVersion, + "renderedKubeletVersion", renderedKubeletVersion) + return + } + + // This featuregate rollout was done as a result of a new minimum kubelet version rolling out, which means we need to wait for at least one + // node in each MCP to finish updating before we set the spec. + if err := wait.ExponentialBackoff(constants.NodeUpdateBackoff, func() (bool, error) { + mcps, err := poolGetter() + if err != nil { + return true, err + } + allUpdated := true + for _, mcp := range mcps { + if oldGeneration, ok := updatedPools[mcp.Name]; ok && (mcp.Status.UpdatedMachineCount == 0 && mcp.Status.ObservedGeneration > oldGeneration) { + allUpdated = false + } + } + return allUpdated, nil + }); err != nil { + klog.Errorf("Failed to update rendered kubelet version: %v", err) + } + + if err := retry.RetryOnConflict(updateBackoff, func() error { + // Fetch the NodeConfig + nodeConfig, err := ctrl.nodeConfigLister.Get(ctrlcommon.ClusterNodeInstanceName) + if macherrors.IsNotFound(err) { + nodeConfig = createNewDefaultNodeconfig() + } + if nodeConfig.Spec.MinimumKubeletVersion != renderedKubeletVersion { + // skip this update, as we no longer want this spec value + return nil + } + if nodeConfig.Status.MinimumKubeletVersion == renderedKubeletVersion { + // this happened somewhere else, skip + return nil + } + nodeConfig.Status.MinimumKubeletVersion = renderedKubeletVersion + _, err = ctrl.configClient.ConfigV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{}) + return err + }); err != nil { + klog.Errorf("Failed to update rendered kubelet version to node status: %v", err) + } +} + // cleanUpDuplicatedMC removes the MC of non-updated GeneratedByControllerVersionKey if its name contains 'generated-kubelet'. // BZ 1955517: upgrade when there are more than one configs, the duplicated and upgraded MC will be generated (func getManagedKubeletConfigKey()) // MC with old GeneratedByControllerVersionKey fails the upgrade. diff --git a/pkg/controller/kubelet-config/kubelet_config_features.go b/pkg/controller/kubelet-config/kubelet_config_features.go index b5992f97b7..74c99a9359 100644 --- a/pkg/controller/kubelet-config/kubelet_config_features.go +++ b/pkg/controller/kubelet-config/kubelet_config_features.go @@ -17,6 +17,7 @@ import ( "k8s.io/client-go/util/retry" "k8s.io/klog/v2" + configv1 "github.com/openshift/api/config/v1" mcfgv1 "github.com/openshift/api/machineconfiguration/v1" ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common" "github.com/openshift/machine-config-operator/pkg/version" @@ -73,14 +74,20 @@ func (ctrl *Controller) syncFeatureHandler(key string) error { return fmt.Errorf("could not get the TLSSecurityProfile from %v: %v", ctrlcommon.APIServerInstanceName, err) } + featureGates, renderedVersions, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + if err != nil { + return fmt.Errorf("could not generate features map: %w", err) + } + // Fetch the Node Config object + nodeConfig, err := ctrl.nodeConfigLister.Get(ctrlcommon.ClusterNodeInstanceName) + if errors.IsNotFound(err) { + nodeConfig = createNewDefaultNodeconfig() + } + + updatedPools := map[string]int64{} + for _, pool := range mcpPools { - var nodeConfig *osev1.Node role := pool.Name - // Fetch the Node Config object - nodeConfig, err = ctrl.nodeConfigLister.Get(ctrlcommon.ClusterNodeInstanceName) - if errors.IsNotFound(err) { - nodeConfig = createNewDefaultNodeconfig() - } // Get MachineConfig managedKey, err := getManagedFeaturesKey(pool, ctrl.client) if err != nil { @@ -99,11 +106,6 @@ func (ctrl *Controller) syncFeatureHandler(key string) error { } } - featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) - if err != nil { - return fmt.Errorf("could not generate features map: %w", err) - } - rawCfgIgn, err := generateKubeConfigIgnFromFeatures(cc, ctrl.templatesDir, role, featureGates, nodeConfig, apiServer) if err != nil { return err @@ -130,9 +132,12 @@ func (ctrl *Controller) syncFeatureHandler(key string) error { } klog.Infof("Applied FeatureSet %v on MachineConfigPool %v", key, pool.Name) ctrlcommon.UpdateStateMetric(ctrlcommon.MCCSubControllerState, "machine-config-controller-kubelet-config", "Sync FeatureSet", pool.Name) + updatedPools[pool.Name] = pool.Status.ObservedGeneration } + go ctrl.writebackMinimumKubeletVersionIfAppropriate(updatedPools, renderedVersions, nodeConfig, func() ([]*mcfgv1.MachineConfigPool, error) { + return ctrl.mcpLister.List(labels.Everything()) + }) return ctrl.cleanUpDuplicatedMC(managedFeaturesKeyPrefix) - } func (ctrl *Controller) enqueueFeature(feat *osev1.FeatureGate) { @@ -179,16 +184,16 @@ func (ctrl *Controller) deleteFeature(obj interface{}) { // generateFeatureMap returns a map of enabled/disabled feature gate selection with exclusion list // //nolint:gocritic -func generateFeatureMap(featuregateAccess featuregates.FeatureGateAccess, exclusions ...osev1.FeatureGateName) (map[string]bool, error) { +func generateFeatureMap(featuregateAccess featuregates.FeatureGateAccess, exclusions ...osev1.FeatureGateName) (map[string]bool, []configv1.MinimumComponentVersion, error) { rv := make(map[string]bool) if !featuregateAccess.AreInitialFeatureGatesObserved() { - return nil, fmt.Errorf("initial feature gates are not observed") + return nil, nil, fmt.Errorf("initial feature gates are not observed") } features, err := featuregateAccess.CurrentFeatureGates() if err != nil { - return nil, fmt.Errorf("could not get current feature gates: %w", err) + return nil, nil, fmt.Errorf("could not get current feature gates: %w", err) } for _, feat := range features.KnownFeatures() { @@ -203,7 +208,7 @@ func generateFeatureMap(featuregateAccess featuregates.FeatureGateAccess, exclus for _, excluded := range exclusions { delete(rv, string(excluded)) } - return rv, nil + return rv, features.RenderedMinimumComponentVersions(), nil } func generateKubeConfigIgnFromFeatures(cc *mcfgv1.ControllerConfig, templatesDir, role string, featureGates map[string]bool, nodeConfig *osev1.Node, apiServer *osev1.APIServer) ([]byte, error) { @@ -233,7 +238,8 @@ func generateKubeConfigIgnFromFeatures(cc *mcfgv1.ControllerConfig, templatesDir func RunFeatureGateBootstrap(templateDir string, featureGateAccess featuregates.FeatureGateAccess, nodeConfig *osev1.Node, controllerConfig *mcfgv1.ControllerConfig, mcpPools []*mcfgv1.MachineConfigPool, apiServer *osev1.APIServer) ([]*mcfgv1.MachineConfig, error) { machineConfigs := []*mcfgv1.MachineConfig{} - featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) + // TODO FIXME: do we need rendered versions here? + featureGates, _, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) if err != nil { return nil, fmt.Errorf("could not generate features map: %w", err) } diff --git a/pkg/controller/kubelet-config/kubelet_config_features_test.go b/pkg/controller/kubelet-config/kubelet_config_features_test.go index c095477d9d..b0e515090c 100644 --- a/pkg/controller/kubelet-config/kubelet_config_features_test.go +++ b/pkg/controller/kubelet-config/kubelet_config_features_test.go @@ -44,7 +44,7 @@ func TestFeatureGateDrift(t *testing.T) { fgAccess := featuregates.NewHardcodedFeatureGateAccess(features.Spec.FeatureGateSelection.CustomNoUpgrade.Enabled, features.Spec.FeatureGateSelection.CustomNoUpgrade.Disabled) ctrl := f.newController(fgAccess) - featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + featureGates, _, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) require.NoError(t, err) // Generate kubelet config with feature gates applied @@ -222,7 +222,7 @@ func TestBootstrapFeaturesCustomNoUpgrade(t *testing.T) { } fgAccess := featuregates.NewHardcodedFeatureGateAccess(features.Spec.FeatureGateSelection.CustomNoUpgrade.Enabled, features.Spec.FeatureGateSelection.CustomNoUpgrade.Disabled) - defaultFeatureGates, err := generateFeatureMap(fgAccess) + defaultFeatureGates, _, err := generateFeatureMap(fgAccess) if err != nil { t.Errorf("could not generate defaultFeatureGates: %v", err) } diff --git a/pkg/controller/kubelet-config/kubelet_config_nodes.go b/pkg/controller/kubelet-config/kubelet_config_nodes.go index e4bd86ee0f..cb14c53154 100644 --- a/pkg/controller/kubelet-config/kubelet_config_nodes.go +++ b/pkg/controller/kubelet-config/kubelet_config_nodes.go @@ -94,7 +94,8 @@ func (ctrl *Controller) syncNodeConfigHandler(key string) error { return fmt.Errorf("could not get the TLSSecurityProfile from %v: %v", ctrlcommon.APIServerInstanceName, err) } - featureGates, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) + // renderedVersions will be handled in syncFeatureHandler below + featureGates, _, err := generateFeatureMap(ctrl.featureGateAccess, openshiftOnlyFeatureGates...) if err != nil { return fmt.Errorf("could not generate features map: %w", err) } @@ -284,7 +285,8 @@ func RunNodeConfigBootstrap(templateDir string, featureGateAccess featuregates.F configs := []*mcfgv1.MachineConfig{} - featureGates, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) + // Ignoring rendered versions here. + featureGates, _, err := generateFeatureMap(featureGateAccess, openshiftOnlyFeatureGates...) if err != nil { return nil, fmt.Errorf("could not generate features map: %w", err) } diff --git a/test/e2e-bootstrap/bootstrap_test.go b/test/e2e-bootstrap/bootstrap_test.go index 95422e6c59..e53dd0ef94 100644 --- a/test/e2e-bootstrap/bootstrap_test.go +++ b/test/e2e-bootstrap/bootstrap_test.go @@ -590,7 +590,7 @@ func ensureFeatureGate(t *testing.T, clientSet *framework.ClientSet, objs ...run featureGateStatus, err := features.FeatureSets(features.ClusterProfileName(SelfManaged), currentFeatureSet) require.NoError(t, err) - currentDetails := featuregatescontroller.FeaturesGateDetailsFromFeatureSets(featureGateStatus, controllerConfig.Spec.ReleaseImage) + currentDetails := featuregatescontroller.FeaturesGateDetailsFromFeatureSets(featureGateStatus, controllerConfig.Spec.ReleaseImage, nil, currentFeatureSet) rawDetails := *currentDetails rawDetails.Version = version.ReleaseVersion