Skip to content
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
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,48 @@ jobs:
with:
version: 3.21.3

- name: Lint and render Helm chart
run: |
set -euo pipefail
helm lint deploy/rustfs-operator

# Default: cosiDriver disabled, nothing COSI-related should render.
helm template test deploy/rustfs-operator > /tmp/helm-default.yaml
! grep -q "cosi-driver" /tmp/helm-default.yaml

# cosiDriver enabled on vanilla Kubernetes.
helm template test deploy/rustfs-operator \
--set cosiDriver.enabled=true > /tmp/helm-cosi.yaml
grep -q "kind: Deployment" /tmp/helm-cosi.yaml
grep -q "rustfs-cosi-driver" /tmp/helm-cosi.yaml
grep -q "objectstorage-sidecar" /tmp/helm-cosi.yaml

# cosiDriver enabled on OpenShift: no hardcoded securityContext, hostUsers set.
helm template test deploy/rustfs-operator \
--set cosiDriver.enabled=true --set openshift.enabled=true \
--show-only templates/cosi-driver-deployment.yaml > /tmp/helm-cosi-openshift.yaml
grep -q "hostUsers: false" /tmp/helm-cosi-openshift.yaml
! grep -q "runAsUser" /tmp/helm-cosi-openshift.yaml

# Custom ServiceAccount: chart must not create its own (a disabled template
# renders nothing, so assert on the full render rather than --show-only,
# which errors on a template that produced no manifest), and the Deployment
# must reference the supplied name.
helm template test deploy/rustfs-operator \
--set cosiDriver.enabled=true \
--set cosiDriver.serviceAccount.create=false \
--set cosiDriver.serviceAccount.name=my-custom-sa \
> /tmp/helm-cosi-custom-sa.yaml
! grep -q "cosi-driver-serviceaccount.yaml" /tmp/helm-cosi-custom-sa.yaml
grep -q "serviceAccountName: my-custom-sa" /tmp/helm-cosi-custom-sa.yaml

# Custom RBAC: chart must not create its own ClusterRole/ClusterRoleBinding.
helm template test deploy/rustfs-operator \
--set cosiDriver.enabled=true \
--set cosiDriver.rbac.create=false \
> /tmp/helm-cosi-custom-rbac.yaml
! grep -q "cosi-driver-clusterrole" /tmp/helm-cosi-custom-rbac.yaml

- name: Check release metadata
run: make release-metadata-check

Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ All notable changes to RustFS Operator are documented in this file. The format i
for operator observability, STS, and Console sockets.
- Tenant `spec.hostUsers` and OpenShift `hostUsers: false` defaults for `restricted-v3`.
- Tenant bucket canned anonymous access and ConfigMap-sourced bucket policies.
- Helm chart `cosiDriver.enabled` to deploy the RustFS COSI (`rustfs.objectstorage.k8s.io`)
driver alongside the upstream provisioner sidecar, with dedicated ServiceAccount/RBAC.

### Fixed

Expand Down
11 changes: 11 additions & 0 deletions deploy/rustfs-operator/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,14 @@ Create the name of the console service account to use
{{- default "default" .Values.console.serviceAccount.name }}
{{- end }}
{{- end }}

{{/*
Create the name of the COSI driver service account to use
*/}}
{{- define "rustfs-operator.cosiDriverServiceAccountName" -}}
{{- if .Values.cosiDriver.serviceAccount.create }}
{{- default (printf "%s-cosi-driver" (include "rustfs-operator.fullname" .)) .Values.cosiDriver.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.cosiDriver.serviceAccount.name }}
{{- end }}
{{- end }}
47 changes: 47 additions & 0 deletions deploy/rustfs-operator/templates/cosi-driver-clusterrole.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{{- if and .Values.cosiDriver.enabled .Values.cosiDriver.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "rustfs-operator.fullname" . }}-cosi-driver
labels:
{{- include "rustfs-operator.labels" . | nindent 4 }}
app.kubernetes.io/component: cosi-driver
rules:
# Upstream COSI sidecar: reconciles BucketClaim/BucketAccess against BucketClass/
# BucketAccessClass by calling this driver's Identity/Provisioner gRPC service.
- apiGroups: ["objectstorage.k8s.io"]
resources:
- "buckets"
- "bucketaccesses"
- "bucketclaims"
- "bucketaccessclasses"
- "buckets/status"
- "bucketaccesses/status"
- "bucketclaims/status"
- "bucketaccessclasses/status"
verbs: ["get", "list", "watch", "update", "create", "delete"]

# Upstream COSI sidecar: leader election.
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "watch", "list", "delete", "update", "create"]

# Upstream COSI sidecar and RustFS driver: BucketAccess credential Secrets and the
# RustFS admin Secret. No `list`/`watch`: both only ever address Secrets by name.
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "update", "delete"]

# Upstream COSI sidecar: event recording. client-go's event recorder only ever
# creates new Events and PATCHes repeated/aggregated ones (no list/watch/delete).
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]

# RustFS driver: reads the RustFS admin Secret and optional TLS CA ConfigMap named by
# BucketClass/BucketAccessClass parameters, and stores compare-and-swap grant/bucket
# ownership records as ConfigMaps.
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "create", "update", "delete"]
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{- if and .Values.cosiDriver.enabled .Values.cosiDriver.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "rustfs-operator.fullname" . }}-cosi-driver
labels:
{{- include "rustfs-operator.labels" . | nindent 4 }}
app.kubernetes.io/component: cosi-driver
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "rustfs-operator.fullname" . }}-cosi-driver
subjects:
- kind: ServiceAccount
name: {{ include "rustfs-operator.cosiDriverServiceAccountName" . }}
namespace: {{ include "rustfs-operator.namespace" . }}
{{- end }}
108 changes: 108 additions & 0 deletions deploy/rustfs-operator/templates/cosi-driver-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{{- if .Values.cosiDriver.enabled -}}
{{- $openShift := default dict .Values.openshift -}}
{{- $openShiftEnabled := default false $openShift.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "rustfs-operator.fullname" . }}-cosi-driver
namespace: {{ include "rustfs-operator.namespace" . }}
labels:
{{- include "rustfs-operator.labels" . | nindent 4 }}
app.kubernetes.io/component: cosi-driver
{{- with .Values.commonAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.cosiDriver.replicas }}
selector:
matchLabels:
{{- include "rustfs-operator.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: cosi-driver
template:
metadata:
labels:
{{- include "rustfs-operator.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: cosi-driver
spec:
serviceAccountName: {{ include "rustfs-operator.cosiDriverServiceAccountName" . }}
{{- if $openShiftEnabled }}
hostUsers: false
{{- end }}
{{- with .Values.cosiDriver.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if not $openShiftEnabled }}
{{- with .Values.cosiDriver.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
containers:
# RustFS driver: implements the COSI Identity + Provisioner gRPC service on a
# Unix socket shared with the sidecar container below.
- name: rustfs-driver
image: "{{ .Values.cosiDriver.image.repository }}:{{ .Values.cosiDriver.image.tag | default .Values.operator.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.cosiDriver.image.pullPolicy }}
command: ["./rustfs-cosi-driver"]
env:
- name: RUST_LOG
value: {{ .Values.cosiDriver.logLevel | default "info" }}
- name: COSI_ENDPOINT
value: "unix:///var/lib/cosi/cosi.sock"
volumeMounts:
- name: socket
mountPath: /var/lib/cosi
{{- with .Values.cosiDriver.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if not $openShiftEnabled }}
{{- with .Values.cosiDriver.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- end }}

# Upstream COSI provisioner sidecar: watches BucketClaim/BucketAccess and calls
# the driver above over the shared Unix socket.
- name: objectstorage-provisioner-sidecar
image: "{{ .Values.cosiDriver.sidecar.image.repository }}:{{ .Values.cosiDriver.sidecar.image.tag }}"
imagePullPolicy: {{ .Values.cosiDriver.sidecar.image.pullPolicy }}
args:
- "--v={{ .Values.cosiDriver.sidecar.verbosity }}"
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
volumeMounts:
- name: socket
mountPath: /var/lib/cosi
{{- with .Values.cosiDriver.sidecar.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if not $openShiftEnabled }}
{{- with .Values.cosiDriver.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- end }}
volumes:
- name: socket
emptyDir: {}
{{- with .Values.cosiDriver.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cosiDriver.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cosiDriver.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
14 changes: 14 additions & 0 deletions deploy/rustfs-operator/templates/cosi-driver-serviceaccount.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{- if and .Values.cosiDriver.enabled .Values.cosiDriver.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "rustfs-operator.cosiDriverServiceAccountName" . }}
namespace: {{ include "rustfs-operator.namespace" . }}
labels:
{{- include "rustfs-operator.labels" . | nindent 4 }}
app.kubernetes.io/component: cosi-driver
{{- with .Values.cosiDriver.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
94 changes: 94 additions & 0 deletions deploy/rustfs-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,97 @@ console:
# - secretName: console-tls
# hosts:
# - console.example.com

# RustFS COSI (Container Object Storage Interface) v1alpha1 driver.
#
# Requires the upstream COSI CRDs and controller
# (https://github.com/kubernetes-sigs/container-object-storage-interface) to already be
# installed in the cluster; this chart only deploys the RustFS driver + provisioner sidecar
# Deployment that implements the COSI Identity/Provisioner gRPC service.
#
# Driver name for BucketClass / BucketAccessClass: rustfs.objectstorage.k8s.io
cosiDriver:
# Disabled by default because it depends on cluster-wide COSI CRDs/controller as a
# prerequisite; enable once those are installed.
enabled: false

replicas: 1

# Log level for the driver (trace, debug, info, warn, error)
logLevel: info

image:
# The COSI driver binary ships in the same image as operator.
repository: rustfs/operator
tag: "" # Defaults to operator.image.tag
pullPolicy: IfNotPresent

# Image pull secrets for private registries
imagePullSecrets: []

# Official COSI provisioner sidecar. It watches BucketClaim/BucketAccess/BucketClass/
# BucketAccessClass objects and calls the RustFS driver's Identity/Provisioner gRPC
# service over a Unix socket shared via an emptyDir volume.
sidecar:
image:
repository: gcr.io/k8s-staging-sig-storage/objectstorage-sidecar
tag: v0.2.2
pullPolicy: IfNotPresent
# klog verbosity (0-5)
verbosity: 4
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 100m
memory: 128Mi

# Resource limits and requests for the driver container
resources:
requests:
cpu: 20m
memory: 32Mi
limits:
cpu: 200m
memory: 128Mi

# Security context for the driver pod
podSecurityContext:
fsGroup: 65534

# Security context for the driver container (also applied to the sidecar container)
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 65534
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault

# Node selector for driver pod placement
nodeSelector: {}

# Tolerations for driver pod scheduling
tolerations: []

# Affinity rules for driver pod scheduling
affinity: {}

# ServiceAccount configuration
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
name: ""

# RBAC configuration. The ClusterRole covers both the RustFS driver (Secrets/ConfigMaps
# for credential and CAS-ownership records) and the upstream sidecar (objectstorage.k8s.io
# CRDs and coordination.k8s.io Leases for leader election).
rbac:
# Specifies whether RBAC resources should be created
create: true
Loading
Loading