Skip to content

Rework Plan CRD generation to add docs and kubectl explain support #369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
ARG KUBECTL=rancher/kubectl:v1.32.2
ARG KUBECTL=rancher/kubectl:v1.32.6
FROM ${KUBECTL} AS kubectl

FROM registry.suse.com/bci/golang:1.23
FROM registry.suse.com/bci/golang:1.24

COPY --from=kubectl /bin/kubectl /usr/local/bin/kubectl

ARG DAPPER_HOST_ARCH
ENV ARCH $DAPPER_HOST_ARCH
ARG SONOBUOY_VERSION=0.57.1
RUN zypper -n install expect git jq docker vim less file curl wget iproute2 gawk
ARG SONOBUOY_VERSION=0.57.3
RUN zypper -n install expect git jq docker vim less file curl wget iproute2 gawk
RUN if [ "${ARCH:-$(go env GOARCH)}" = "amd64" ]; then \
curl -sL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.61.0; \
curl -sL "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.4.3/kustomize_v5.4.3_linux_amd64.tar.gz" | tar -xz -C /usr/local/bin; \
curl -sL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.64.8; \
curl -sL "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.6.0/kustomize_v5.6.0_linux_amd64.tar.gz" | tar -xz -C /usr/local/bin; \
curl -sL "https://github.com/vmware-tanzu/sonobuoy/releases/download/v${SONOBUOY_VERSION}/sonobuoy_${SONOBUOY_VERSION}_linux_${ARCH}.tar.gz" | tar -xz -C /usr/local/bin; \
curl -sL "https://github.com/docker/compose/releases/download/v2.29.1/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose && \
chmod +x /usr/local/bin/docker-compose; \
fi
RUN mkdir -p /usr/local/lib/docker/cli-plugins; \
curl -o /usr/local/lib/docker/cli-plugins/docker-buildx -fsSL "https://github.com/docker/buildx/releases/download/v0.17.1/buildx-v0.17.1.linux-amd64"; \
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.17.3 && \
go install github.com/elastic/crd-ref-docs@v0.1.0
ENV DAPPER_ENV REPO TAG DRONE_TAG
ENV DAPPER_SOURCE /go/src/github.com/rancher/system-upgrade-controller/
ENV DAPPER_OUTPUT ./bin ./dist
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ But in the time-honored tradition of `curl ${script} | sudo sh -` here is a nice
kubectl apply -k github.com/rancher/system-upgrade-controller
```

## API Documentation

Autogenerated API docs for `upgrade.cattle.io/v1 Plan` are available at [doc/plan.md](doc/plan.md#Plan)

### Example Plans

- [examples/k3s-upgrade.yaml](examples/k3s-upgrade.yaml)
Expand Down
5 changes: 5 additions & 0 deletions crd-ref-docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
processor:
ignoreFields:
- "TypeMeta$"
render:
kubernetesVersion: 1.32
201 changes: 201 additions & 0 deletions doc/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# API Reference

## Packages
- [upgrade.cattle.io/v1](#upgradecattleiov1)


## upgrade.cattle.io/v1






#### ContainerSpec



ContainerSpec is a simplified container template spec, used to configure the prepare and upgrade
containers of the Job Pod.



_Appears in:_
- [PlanSpec](#planspec)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `image` _string_ | Image name. If the tag is omitted, the value from .status.latestVersion will be used. | | Required: \{\} <br /> |
| `command` _string array_ | | | |
| `args` _string array_ | | | |
| `envs` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#envvar-v1-core) array_ | | | |
| `envFrom` _[EnvFromSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#envfromsource-v1-core) array_ | | | |
| `volumes` _[VolumeSpec](#volumespec) array_ | | | |
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#securitycontext-v1-core)_ | | | |


#### Day

_Underlying type:_ _string_



_Validation:_
- Enum: [0 su sun sunday 1 mo mon monday 2 tu tue tuesday 3 we wed wednesday 4 th thu thursday 5 fr fri friday 6 sa sat saturday]

_Appears in:_
- [TimeWindowSpec](#timewindowspec)



#### DrainSpec



DrainSpec encapsulates kubectl drain parameters minus node/pod selectors. See:
- https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/
- https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#drain



_Appears in:_
- [PlanSpec](#planspec)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `timeout` _[Duration](#duration)_ | | | |
| `gracePeriod` _integer_ | | | |
| `deleteLocalData` _boolean_ | | | |
| `deleteEmptydirData` _boolean_ | | | |
| `ignoreDaemonSets` _boolean_ | | | |
| `force` _boolean_ | | | |
| `disableEviction` _boolean_ | | | |
| `skipWaitForDeleteTimeout` _integer_ | | | |
| `podSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#labelselector-v1-meta)_ | | | |


#### Plan



Plan represents a set of Jobs to apply an upgrade (or other operation) to set of Nodes.



_Appears in:_
- [PlanList](#planlist)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
| `spec` _[PlanSpec](#planspec)_ | | | |
| `status` _[PlanStatus](#planstatus)_ | | | |




#### PlanSpec



PlanSpec represents the user-configurable details of a Plan.



_Appears in:_
- [Plan](#plan)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `concurrency` _integer_ | The maximum number of concurrent nodes to apply this update on. | | |
| `jobActiveDeadlineSecs` _integer_ | Sets ActiveDeadlineSeconds on Jobs generated to apply this Plan.<br />If the Job does not complete within this time, the Plan will stop processing until it is updated to trigger a redeploy.<br />If set to 0, Jobs have no deadline. If not set, the controller default value is used. | | |
Copy link

@manuelbuil manuelbuil Jun 25, 2025

Choose a reason for hiding this comment

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

If not set, the controller default value is used

Maybe it is worth adding that is the default value (900)? Or pointing where to find it SYSTEM_UPGRADE_JOB_ACTIVE_DEADLINE_SECONDS?

Copy link
Member Author

@brandond brandond Jun 25, 2025

Choose a reason for hiding this comment

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

We could cover that elsewhere, yeah. We don't really have any docs on controller CLI flags at the moment. This text is generated automatically from the field docstring and isn't the best place to cover controller config.

| `nodeSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#labelselector-v1-meta)_ | Select which nodes this plan can be applied to. | | |
| `serviceAccountName` _string_ | The service account for the pod to use. As with normal pods, if not specified the default service account from the namespace will be assigned. | | |
| `channel` _string_ | A URL that returns HTTP 302 with the last path element of the value returned in the Location header assumed to be an image tag (after munging "+" to "-"). | | |
| `version` _string_ | Providing a value for version will prevent polling/resolution of the channel if specified. | | |
| `secrets` _[SecretSpec](#secretspec) array_ | Secrets to be mounted into the Job Pod. | | |
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#toleration-v1-core) array_ | Specify which node taints should be tolerated by pods applying the upgrade.<br />Anything specified here is appended to the default of:<br />- `\{key: node.kubernetes.io/unschedulable, effect: NoSchedule, operator: Exists\}` | | |
| `exclusive` _boolean_ | Jobs for exclusive plans cannot be run alongside any other exclusive plan. | | |
| `window` _[TimeWindowSpec](#timewindowspec)_ | A time window in which to execute Jobs for this Plan.<br />Jobs will not be generated outside this time window, but may continue executing into the window once started. | | |
| `prepare` _[ContainerSpec](#containerspec)_ | The prepare init container, if specified, is run before cordon/drain which is run before the upgrade container. | | |
| `upgrade` _[ContainerSpec](#containerspec)_ | The upgrade container; must be specified. | | |
| `cordon` _boolean_ | If Cordon is true, the node is cordoned before the upgrade container is run.<br />If drain is specified, the value for cordon is ignored, and the node is cordoned.<br />If neither drain nor cordon are specified and the node is marked as schedulable=false it will not be marked as schedulable=true when the Job completes. | | |
| `drain` _[DrainSpec](#drainspec)_ | Configuration for draining nodes prior to upgrade. If left unspecified, no drain will be performed. | | |
| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#localobjectreference-v1-core) array_ | Image Pull Secrets, used to pull images for the Job. | | |
| `postCompleteDelay` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#duration-v1-meta)_ | Time after a Job for one Node is complete before a new Job will be created for the next Node. | | |


#### PlanStatus



PlanStatus represents the resulting state from processing Plan events.



_Appears in:_
- [Plan](#plan)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `conditions` _GenericCondition array_ | `LatestResolved` indicates that the latest version as per the spec has been determined.<br />`Validated` indicates that the plan spec has been validated.<br />`Complete` indicates that the latest version of the plan has completed on all selected nodes. If any Jobs for the Plan fail to complete, this condition will remain false, and the reason and message will reflect the source of the error. | | |
| `latestVersion` _string_ | The latest version, as resolved from .spec.version, or the channel server. | | |
| `latestHash` _string_ | The hash of the most recently applied plan .spec. | | |
| `applying` _string array_ | List of Node names that the Plan is currently being applied on. | | |


#### SecretSpec



SecretSpec describes a Secret to be mounted for prepare/upgrade containers.



_Appears in:_
- [PlanSpec](#planspec)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `name` _string_ | Secret name | | Required: \{\} <br /> |
| `path` _string_ | Path to mount the Secret volume within the Pod. | | Required: \{\} <br /> |
| `ignoreUpdates` _boolean_ | If set to true, the Secret contents will not be hashed, and changes to the Secret will not trigger new application of the Plan. | | |


#### TimeWindowSpec



TimeWindowSpec describes a time window in which a Plan should be processed.



_Appears in:_
- [PlanSpec](#planspec)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `days` _[Day](#day) array_ | Days that this time window is valid for | | Enum: [0 su sun sunday 1 mo mon monday 2 tu tue tuesday 3 we wed wednesday 4 th thu thursday 5 fr fri friday 6 sa sat saturday] <br />MinItems: 1 <br /> |
| `startTime` _string_ | Start of the time window. | | |
| `endTime` _string_ | End of the time window. | | |
| `timeZone` _string_ | Time zone for the time window; if not specified UTC will be used. | | |


#### VolumeSpec



HostPath volume to mount into the pod



_Appears in:_
- [ContainerSpec](#containerspec)

| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `name` _string_ | Name of the Volume as it will appear within the Pod spec. | | Required: \{\} <br /> |
| `source` _string_ | Path on the host to mount. | | Required: \{\} <br /> |
| `destination` _string_ | Path to mount the Volume at within the Pod. | | Required: \{\} <br /> |


2 changes: 1 addition & 1 deletion e2e/cluster/local/images/k3s/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
ARG BCI="registry.suse.com/bci/bci-base:15.6"
FROM ${BCI} AS k3s
ARG ARCH
ARG K3S_VERSION="v1.30.3+k3s1"
ARG K3S_VERSION="v1.32.5+k3s1"
RUN set -x \
&& zypper -n in \
ca-certificates \
Expand Down
6 changes: 3 additions & 3 deletions e2e/cluster/local/scripts/cluster-prepare
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ set -e

: "${ARCH?required}"
: "${DIST?required}"
: "${BCI_TAG:=15.4}"
: "${KUBECTL_TAG:=v1.30.3}"
: "${SONOBUOY_TAG:=v0.57.1}"
: "${BCI_TAG:=15.6}"
: "${KUBECTL_TAG:=v1.32.6}"
: "${SONOBUOY_TAG:=v0.57.3}"

docker-image-save() {
echo "Pulling '$1:$2' ..."
Expand Down
3 changes: 3 additions & 0 deletions e2e/framework/controller/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func NewDeployment(name string, opt ...DeploymentOption) *appsv1.Deployment {
}, {
Name: "SYSTEM_UPGRADE_CONTROLLER_LEADER_ELECT",
Value: "true",
}, {
Name: "SYSTEM_UPGRADE_CONTROLLER_DEBUG",
Value: "true",
}, {
Name: "SYSTEM_UPGRADE_CONTROLLER_NAMESPACE",
ValueFrom: &corev1.EnvVarSource{
Expand Down
1 change: 1 addition & 0 deletions e2e/suite/channel_resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@ var _ = Describe("Resolve channel", func() {
Expect(err).To(HaveOccurred())
Expect(latest).To(BeEmpty())
})
AfterEach(CollectLogsOnFailure(e2e))
})
})
Loading
Loading