Skip to content

Instantly share code, notes, and snippets.

@agracey
Last active April 21, 2025 16:42
Show Gist options
  • Save agracey/377d6a221d33ef4c28feef2def6e08b0 to your computer and use it in GitHub Desktop.
Save agracey/377d6a221d33ef4c28feef2def6e08b0 to your computer and use it in GitHub Desktop.
Extension to Fleet to add maintenance windows
apiVersion: batch/v1
kind: CronJob
metadata:
name: update-maint-window
namespace: fleet-default
spec:
schedule: "1,16,31,46 * * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: fleet-mw
containers:
- name: update-mw
image: registry.opensuse.org/home/atgracey/utilities/containerfile/fmw:latest
imagePullPolicy: Always
command:
- /bin/bash
- -c
- |
DOTW=`date +"%a"`
DATE=`date +"%Y%m%d"`
CURRTIME=`date +"%s"`
WINDOWS=`kubectl get maintenancewindows.fleet.cattle.io -A -ojsonpath='{.items}'`
# maintenancewindows.fleet.cattle.io/name
CLUSTERS=`kubectl get clusters.fleet.cattle.io -A -ojsonpath='{range .items[?(@.metadata.labels.maintenancewindows\.fleet\.cattle\.io/name)]}{.metadata.name}{"\t"}{.metadata.namespace}{"\t"}{.metadata.labels.maintenancewindows\.fleet\.cattle\.io/name}{"\t"}{.spec.paused}{"\n"}'`
# TODO: need to handle empty schedule label
while read -r name namespace scheduleName paused
do
[[ -z "$name" ]] && continue
printf '%s\n' "$name in $namespace is using schedule $scheduleName and paused is currently set to $paused"
declare shouldBePaused=false
# Get associated schedule and it's active windows
activeWindows=`echo $WINDOWS | jq -r ".[] | select(.metadata.name | test(\"test-window$\")) | [.spec.windows[] | select(.recurrance | test(\"^(daily|$DOTW|$DATE)\$\"))] | .[] | \"\(.startTime) \(.stopTime)\""`
while read -r start stop
do
startTS="$(date -d $start +'%s')"
stopTS="$(date -d $stop +'%s')"
if [ "${CURRTIME}" -ge "${startTS}" -a "${CURRTIME}" -lt "${stopTS}" ]
then
shouldBePaused=true
fi
done <<< "$activeWindows"
kubectl patch clusters.fleet.cattle.io -n $namespace $name --type='json' -p="[{\"op\":\"replace\",\"path\":\"/spec/paused\",\"value\":$shouldBePaused}]"
done <<< "$CLUSTERS"
restartPolicy: OnFailure
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: maintenancewindows.fleet.cattle.io
spec:
# group name to use for REST API: /apis/<group>/<version>
group: fleet.cattle.io
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1alpha1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
windows:
type: array
items:
type: object
properties:
recurrance:
# This would either be "daily", a 3 letter day of the week (Mon-Sun), or an ISO 8601 date (YYYYMMDD) for a single window
type: string
default: "daily"
startTime:
type: string
stopTime:
type: string
# timezone:
### How to handle different timezones... Should calculate with the TZ of where the cluster is located
scope: Namespaced
names:
plural: maintenancewindows
singular: maintenancewindow
kind: MaintenanceWindows
shortNames:
- mw
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fleet-mw
rules:
- apiGroups:
- fleet.cattle.io
resources:
- maintenancewindows
verbs:
- list
- get
- apiGroups:
- fleet.cattle.io
resources:
- clusters
verbs:
- list
- get
- update
- patch
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fleet-mw
namespace: fleet-default
automountServiceAccountToken: true
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: fleet-mw-sa
namespace: fleet-default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: fleet-mw
subjects:
- kind: ServiceAccount
name: fleet-mw
namespace: fleet-default
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment