Skip to content

Commit fd3bb60

Browse files
committed
Add API docs
Also clean up some of the api spec for better documentation, and fix tests. Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
1 parent 8811709 commit fd3bb60

File tree

10 files changed

+280
-54
lines changed

10 files changed

+280
-54
lines changed

Dockerfile.dapper

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ RUN if [ "${ARCH:-$(go env GOARCH)}" = "amd64" ]; then \
1919
RUN mkdir -p /usr/local/lib/docker/cli-plugins; \
2020
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"; \
2121
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
22-
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.17.3
22+
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.17.3 && \
23+
go install github.com/elastic/crd-ref-docs@v0.1.0
2324
ENV DAPPER_ENV REPO TAG DRONE_TAG
2425
ENV DAPPER_SOURCE /go/src/github.com/rancher/system-upgrade-controller/
2526
ENV DAPPER_OUTPUT ./bin ./dist

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ But in the time-honored tradition of `curl ${script} | sudo sh -` here is a nice
5252
kubectl apply -k github.com/rancher/system-upgrade-controller
5353
```
5454

55+
## API Documentation
56+
57+
Autogenerated API docs for `upgrade.cattle.io/v1 Plan` are available at [doc/plan.md](doc/plan.md#Plan)
58+
5559
### Example Plans
5660

5761
- [examples/k3s-upgrade.yaml](examples/k3s-upgrade.yaml)

crd-ref-docs.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
processor:
2+
ignoreFields:
3+
- "TypeMeta$"
4+
render:
5+
kubernetesVersion: 1.32

doc/plan.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# API Reference
2+
3+
## Packages
4+
- [upgrade.cattle.io/v1](#upgradecattleiov1)
5+
6+
7+
## upgrade.cattle.io/v1
8+
9+
10+
11+
12+
13+
14+
#### ContainerSpec
15+
16+
17+
18+
ContainerSpec is a simplified container template spec, used to configure the prepare and upgrade
19+
containers of the Job Pod.
20+
21+
22+
23+
_Appears in:_
24+
- [PlanSpec](#planspec)
25+
26+
| Field | Description | Default | Validation |
27+
| --- | --- | --- | --- |
28+
| `image` _string_ | Image name. If the tag is omitted, the value from .status.latestVersion will be used. | | Required: \{\} <br /> |
29+
| `command` _string array_ | | | |
30+
| `args` _string array_ | | | |
31+
| `envs` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#envvar-v1-core) array_ | | | |
32+
| `envFrom` _[EnvFromSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#envfromsource-v1-core) array_ | | | |
33+
| `volumes` _[VolumeSpec](#volumespec) array_ | | | |
34+
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#securitycontext-v1-core)_ | | | |
35+
36+
37+
#### Day
38+
39+
_Underlying type:_ _string_
40+
41+
42+
43+
_Validation:_
44+
- 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]
45+
46+
_Appears in:_
47+
- [TimeWindowSpec](#timewindowspec)
48+
49+
50+
51+
#### DrainSpec
52+
53+
54+
55+
DrainSpec encapsulates kubectl drain parameters minus node/pod selectors. See:
56+
- https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/
57+
- https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#drain
58+
59+
60+
61+
_Appears in:_
62+
- [PlanSpec](#planspec)
63+
64+
| Field | Description | Default | Validation |
65+
| --- | --- | --- | --- |
66+
| `timeout` _[Duration](#duration)_ | | | |
67+
| `gracePeriod` _integer_ | | | |
68+
| `deleteLocalData` _boolean_ | | | |
69+
| `deleteEmptydirData` _boolean_ | | | |
70+
| `ignoreDaemonSets` _boolean_ | | | |
71+
| `force` _boolean_ | | | |
72+
| `disableEviction` _boolean_ | | | |
73+
| `skipWaitForDeleteTimeout` _integer_ | | | |
74+
| `podSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#labelselector-v1-meta)_ | | | |
75+
76+
77+
#### Plan
78+
79+
80+
81+
Plan represents a set of Jobs to apply an upgrade (or other operation) to set of Nodes.
82+
83+
84+
85+
_Appears in:_
86+
- [PlanList](#planlist)
87+
88+
| Field | Description | Default | Validation |
89+
| --- | --- | --- | --- |
90+
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
91+
| `spec` _[PlanSpec](#planspec)_ | | | |
92+
| `status` _[PlanStatus](#planstatus)_ | | | |
93+
94+
95+
96+
97+
#### PlanSpec
98+
99+
100+
101+
PlanSpec represents the user-configurable details of a Plan.
102+
103+
104+
105+
_Appears in:_
106+
- [Plan](#plan)
107+
108+
| Field | Description | Default | Validation |
109+
| --- | --- | --- | --- |
110+
| `concurrency` _integer_ | The maximum number of concurrent nodes to apply this update on. | | |
111+
| `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. | | |
112+
| `nodeSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#labelselector-v1-meta)_ | Select which nodes this plan can be applied to. | | |
113+
| `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. | | |
114+
| `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 "-"). | | |
115+
| `version` _string_ | Providing a value for version will prevent polling/resolution of the channel if specified. | | |
116+
| `secrets` _[SecretSpec](#secretspec) array_ | Secrets to be mounted into the Job Pod. | | |
117+
| `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\}` | | |
118+
| `exclusive` _boolean_ | Jobs for exclusive plans cannot be run alongside any other exclusive plan. | | |
119+
| `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. | | |
120+
| `prepare` _[ContainerSpec](#containerspec)_ | The prepare init container, if specified, is run before cordon/drain which is run before the upgrade container. | | |
121+
| `upgrade` _[ContainerSpec](#containerspec)_ | The upgrade container; must be specified. | | |
122+
| `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. | | |
123+
| `drain` _[DrainSpec](#drainspec)_ | Configuration for draining nodes prior to upgrade. If left unspecified, no drain will be performed. | | |
124+
| `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. | | |
125+
| `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. | | |
126+
127+
128+
#### PlanStatus
129+
130+
131+
132+
PlanStatus represents the resulting state from processing Plan events.
133+
134+
135+
136+
_Appears in:_
137+
- [Plan](#plan)
138+
139+
| Field | Description | Default | Validation |
140+
| --- | --- | --- | --- |
141+
| `conditions` _GenericCondition array_ | | | |
142+
| `latestVersion` _string_ | The latest version, as resolved from .spec.version, or the channel server. | | |
143+
| `latestHash` _string_ | The hash of the most recently applied plan .spec. | | |
144+
| `applying` _string array_ | List of Node names that the Plan is currently being applied on. | | |
145+
146+
147+
#### SecretSpec
148+
149+
150+
151+
SecretSpec describes a Secret to be mounted for prepare/upgrade containers.
152+
153+
154+
155+
_Appears in:_
156+
- [PlanSpec](#planspec)
157+
158+
| Field | Description | Default | Validation |
159+
| --- | --- | --- | --- |
160+
| `name` _string_ | Secret name | | Required: \{\} <br /> |
161+
| `path` _string_ | Path to mount the Secret volume within the Pod. | | Required: \{\} <br /> |
162+
| `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. | | |
163+
164+
165+
#### TimeWindowSpec
166+
167+
168+
169+
TimeWindowSpec describes a time window in which a Plan should be processed.
170+
171+
172+
173+
_Appears in:_
174+
- [PlanSpec](#planspec)
175+
176+
| Field | Description | Default | Validation |
177+
| --- | --- | --- | --- |
178+
| `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 /> |
179+
| `startTime` _string_ | Start of the time window. | | |
180+
| `endTime` _string_ | End of the time window. | | |
181+
| `timeZone` _string_ | Time zone for the time window; if not specified UTC will be used. | | |
182+
183+
184+
#### VolumeSpec
185+
186+
187+
188+
HostPath volume to mount into the pod
189+
190+
191+
192+
_Appears in:_
193+
- [ContainerSpec](#containerspec)
194+
195+
| Field | Description | Default | Validation |
196+
| --- | --- | --- | --- |
197+
| `name` _string_ | Name of the Volume as it will appear within the Pod spec. | | Required: \{\} <br /> |
198+
| `source` _string_ | Path on the host to mount. | | Required: \{\} <br /> |
199+
| `destination` _string_ | Path to mount the Volume at within the Pod. | | Required: \{\} <br /> |
200+
201+

e2e/suite/job_generate_test.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,11 @@ var _ = Describe("Job Generation", func() {
185185
Operator: metav1.LabelSelectorOpDoesNotExist,
186186
}},
187187
}
188-
plan, err = e2e.CreatePlan(plan)
189-
Expect(err).ToNot(HaveOccurred())
190-
191-
plan, err = e2e.WaitForPlanCondition(plan.Name, upgradeapiv1.PlanSpecValidated, 30*time.Second)
192-
Expect(err).ToNot(HaveOccurred())
193-
Expect(upgradeapiv1.PlanSpecValidated.IsTrue(plan)).To(BeFalse())
194-
Expect(upgradeapiv1.PlanSpecValidated.GetMessage(plan)).To(ContainSubstring("spec.window is invalid"))
188+
_, err = e2e.CreatePlan(plan)
189+
Expect(err).To(MatchError(ContainSubstring("invalid: spec.window.days")))
195190

196191
plan.Spec.Window.Days = []upgradeapiv1.Day{"su", "mo", "tu", "we", "th", "fr", "sa"}
197-
plan, err = e2e.UpdatePlan(plan)
192+
plan, err = e2e.CreatePlan(plan)
198193
Expect(err).ToNot(HaveOccurred())
199194

200195
plan, err = e2e.WaitForPlanCondition(plan.Name, upgradeapiv1.PlanSpecValidated, 30*time.Second)
@@ -205,7 +200,7 @@ var _ = Describe("Job Generation", func() {
205200
Expect(err).ToNot(HaveOccurred())
206201
Expect(jobs).To(HaveLen(1))
207202
})
208-
It("should apply successfully after edit", func() {
203+
It("should apply successfully when valid", func() {
209204
Expect(jobs).To(HaveLen(1))
210205
Expect(jobs[0].Status.Succeeded).To(BeNumerically("==", 1))
211206
Expect(jobs[0].Status.Active).To(BeNumerically("==", 0))

e2e/suite/plan_create_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var _ = Describe("Plan Creation", func() {
2020
plan, err = e2e.CreatePlan(plan)
2121
})
2222
It("should return an error if upgrade in nil", func() {
23-
Expect(err).Should(HaveOccurred())
23+
Expect(err).To(HaveOccurred())
2424
})
2525
})
2626
})

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//go:generate rm -rf pkg/generated pkg/crds/yaml/generated
33
//go:generate go run pkg/codegen/codegen.go
44
//go:generate controller-gen crd:generateEmbeddedObjectMeta=true paths=./pkg/apis/... output:crd:dir=./pkg/crds/yaml/generated
5+
//go:generate crd-ref-docs --config=crd-ref-docs.yaml --renderer=markdown --output-path=doc/plan.md
56

67
package main
78

pkg/apis/upgrade.cattle.io/v1/types.go

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,35 +50,31 @@ type PlanSpec struct {
5050
NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty"`
5151
// 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.
5252
ServiceAccountName string `json:"serviceAccountName,omitempty"`
53-
// 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 "-").
53+
// 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 "-").
5454
Channel string `json:"channel,omitempty"`
5555
// Providing a value for version will prevent polling/resolution of the channel if specified.
5656
Version string `json:"version,omitempty"`
5757
// Secrets to be mounted into the Job Pod.
5858
Secrets []SecretSpec `json:"secrets,omitempty"`
5959
// Specify which node taints should be tolerated by pods applying the upgrade.
6060
// Anything specified here is appended to the default of:
61-
// - {key: node.kubernetes.io/unschedulable, effect: NoSchedule, operator: Exists}
61+
// - `{key: node.kubernetes.io/unschedulable, effect: NoSchedule, operator: Exists}`
6262
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
6363
// Jobs for exclusive plans cannot be run alongside any other exclusive plan.
6464
Exclusive bool `json:"exclusive,omitempty"`
6565
// A time window in which to execute Jobs for this Plan.
6666
// Jobs will not be generated outside this time window, but may continue executing into the window once started.
6767
Window *TimeWindowSpec `json:"window,omitempty"`
6868
// The prepare init container, if specified, is run before cordon/drain which is run before the upgrade container.
69-
// Shares the same format as the upgrade container.
70-
// If no tag is included in the image name, the tag portion of the image will be the value from .status.latestVersion a.k.a. the resolved version for this plan.
7169
Prepare *ContainerSpec `json:"prepare,omitempty"`
72-
// If drain is specified, the value for cordon is ignored.
70+
// The upgrade container; must be specified.
71+
Upgrade *ContainerSpec `json:"upgrade"`
72+
// If Cordon is true, the node is cordoned before the upgrade container is run.
73+
// If drain is specified, the value for cordon is ignored, and the node is cordoned.
7374
// 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.
7475
Cordon bool `json:"cordon,omitempty"`
75-
// If left unspecified, no drain will be performed. See:
76-
// - https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/
77-
// - https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#drain
76+
// Configuration for draining nodes prior to upgrade. If left unspecified, no drain will be performed.
7877
Drain *DrainSpec `json:"drain,omitempty"`
79-
// The upgrade container.
80-
// If no tag is included in the image name, the tag portion of the image will be the value from .status.latestVersion a.k.a. the resolved version for this plan.
81-
Upgrade *ContainerSpec `json:"upgrade,omitempty"`
8278
// Image Pull Secrets, used to pull images for the Job.
8379
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
8480
// Time after a Job for one Node is complete before a new Job will be created for the next Node.
@@ -102,10 +98,12 @@ type PlanStatus struct {
10298
Applying []string `json:"applying,omitempty"`
10399
}
104100

105-
// ContainerSpec is a simplified container template.
101+
// ContainerSpec is a simplified container template spec, used to configure the prepare and upgrade
102+
// containers of the Job Pod.
106103
type ContainerSpec struct {
107104
// Image name. If the tag is omitted, the value from .status.latestVersion will be used.
108-
Image string `json:"image,omitempty"`
105+
// +kubebuilder:validation:Required
106+
Image string `json:"image"`
109107
Command []string `json:"command,omitempty"`
110108
Args []string `json:"args,omitempty"`
111109
Env []corev1.EnvVar `json:"envs,omitempty"`
@@ -117,14 +115,19 @@ type ContainerSpec struct {
117115
// HostPath volume to mount into the pod
118116
type VolumeSpec struct {
119117
// Name of the Volume as it will appear within the Pod spec.
120-
Name string `json:"name,omitempty"`
118+
// +kubebuilder:validation:Required
119+
Name string `json:"name"`
121120
// Path on the host to mount.
122-
Source string `json:"source,omitempty"`
121+
// +kubebuilder:validation:Required
122+
Source string `json:"source"`
123123
// Path to mount the Volume at within the Pod.
124-
Destination string `json:"destination,omitempty"`
124+
// +kubebuilder:validation:Required
125+
Destination string `json:"destination"`
125126
}
126127

127-
// DrainSpec encapsulates kubectl drain parameters minus node/pod selectors.
128+
// DrainSpec encapsulates kubectl drain parameters minus node/pod selectors. See:
129+
// - https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/
130+
// - https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#drain
128131
type DrainSpec struct {
129132
Timeout *time.Duration `json:"timeout,omitempty"`
130133
GracePeriod *int32 `json:"gracePeriod,omitempty"`
@@ -137,19 +140,25 @@ type DrainSpec struct {
137140
PodSelector *metav1.LabelSelector `json:"podSelector,omitempty"`
138141
}
139142

140-
// SecretSpec describes a secret to be mounted for prepare/upgrade containers.
143+
// SecretSpec describes a Secret to be mounted for prepare/upgrade containers.
141144
type SecretSpec struct {
142145
// Secret name
143-
Name string `json:"name,omitempty"`
146+
// +kubebuilder:validation:Required
147+
Name string `json:"name"`
144148
// Path to mount the Secret volume within the Pod.
145-
Path string `json:"path,omitempty"`
149+
// +kubebuilder:validation:Required
150+
Path string `json:"path"`
146151
// If set to true, the Secret contents will not be hashed, and changes to the Secret will not trigger new application of the Plan.
147152
IgnoreUpdates bool `json:"ignoreUpdates,omitempty"`
148153
}
149154

155+
// +kubebuilder: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"}
156+
type Day string
157+
150158
// TimeWindowSpec describes a time window in which a Plan should be processed.
151159
type TimeWindowSpec struct {
152160
// Days that this time window is valid for
161+
// +kubebuilder:validation:MinItems=1
153162
Days []Day `json:"days,omitempty"`
154163
// Start of the time window.
155164
StartTime string `json:"startTime,omitempty"`
@@ -159,9 +168,6 @@ type TimeWindowSpec struct {
159168
TimeZone string `json:"timeZone,omitempty"`
160169
}
161170

162-
// +kubebuilder: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"}
163-
type Day string
164-
165171
func (tws *TimeWindowSpec) Contains(t time.Time) bool {
166172
days := make([]string, len(tws.Days))
167173
for i, day := range tws.Days {

0 commit comments

Comments
 (0)