Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
236 commits
Select commit Hold shift + click to select a range
d338053
feat(operator): StorageNode moves to v1alpha2, and its operations are…
noctarius Sep 15, 2026
0f9dec7
feat(operator): the ClusterDeploymentConfig controller, which is what…
noctarius Sep 15, 2026
452d393
fix(operator): a discovery run that plans nothing says why
noctarius Sep 15, 2026
6774327
feat(discovery): report the bound driver and whether anything is usin…
noctarius Sep 15, 2026
762f5f9
feat(discovery): claim idle userspace controllers, and waive a partit…
noctarius Sep 15, 2026
fe80933
fix(api): a deployment config could never be approved
noctarius Sep 15, 2026
3bd8891
fix(operator): the workload enrolls the workers its nodes run on
noctarius Sep 15, 2026
69e9f3f
fix(discovery): name a management interface, and retry an add that ga…
noctarius Sep 15, 2026
95e3fb7
fix(cluster): a task that gave up is not reported as a completion
noctarius Sep 15, 2026
80f1490
fix(operator): a discovery run's status write retries instead of repe…
noctarius Sep 15, 2026
1132909
fix(operator): the device mirror's labels fit the limit that binds them
noctarius Sep 15, 2026
989cc3e
fix(deployment): a document does not refuse the cluster it created
noctarius Sep 15, 2026
881f3f9
Added minimal prose
noctarius Sep 15, 2026
9c4b0f9
fix(operator): the daemon set write retries a conflict it cannot avoid
noctarius Sep 15, 2026
e10f2ce
fix(operator): restore the partitions-per-device count to 0 and 1
noctarius Sep 15, 2026
d497457
fix(operator): a removal does not wait for the cluster to be active
noctarius Sep 15, 2026
2300bf6
fix(operator): close a node's device stream without needing its cluster
noctarius Sep 16, 2026
3c6979b
fix(operator): a removal finishes when its node is already gone
noctarius Sep 16, 2026
2895275
feat(deployment): the draft states that the drives are formatted
noctarius Sep 16, 2026
05dc2fb
fix(operator): the node-add cap holds after the first slot is freed
noctarius Sep 16, 2026
5063e2b
feat(deployment): a finished deployment activates the cluster it built
noctarius Sep 16, 2026
dd83d40
fix(cluster): the lock release retries rather than failing the reconcile
noctarius Sep 16, 2026
bc02ba4
feat(cluster): a cluster being built says so rather than reporting a …
noctarius Sep 16, 2026
849788b
feat(operator): ControlPlane moves to v1alpha2, and the operator inst…
noctarius Sep 16, 2026
bf91e8c
added design doc design-csi-addons-replication.md
geoffrey1330 Sep 16, 2026
57458a9
feat(webhook): approving a deployment config is answered against the …
noctarius Sep 17, 2026
2ade4ae
feat(webhook): a node or cluster operation mid-flight refuses to be w…
noctarius Sep 17, 2026
b0c7e3a
refactor(statemachine): the graph declares which states an abort can …
noctarius Sep 17, 2026
a3ea857
fix(operator): the installer carries the three new validating webhooks
noctarius Sep 17, 2026
01b64c8
chore(fleet): regenerate the CRDs that embed the operator's API
noctarius Sep 17, 2026
d2c68c7
feat(chart): the profiles that run a CSI driver render one
noctarius Sep 17, 2026
ab9429d
feat(controlplane): a created migration carries the paths to validate
noctarius Sep 17, 2026
7be277f
feat(api): PersistentVolumeOps, and the graph its one action runs
noctarius Sep 17, 2026
35b021c
refactor(operator): the rebalancer Job builder moves where both calle…
noctarius Sep 17, 2026
aeafcfa
chore(operator): regenerate after the PersistentVolumeOps comment fix
noctarius Sep 17, 2026
bc8bc6a
feat(controlplane): the volumes one subsystem publishes, across every…
noctarius Sep 17, 2026
42a6b80
feat(volume): the PersistentVolumeOps reconciler, in a band of its own
noctarius Sep 17, 2026
87d7e08
feat(webhook): the PersistentVolumeOps guard, at create and at delete
noctarius Sep 17, 2026
aaa90f2
feat(volume): PersistentVolumeOps is what raises a move, and VolumeMi…
noctarius Sep 17, 2026
b423551
docs(design): PersistentVolumeOps records what was built and what was…
noctarius Sep 17, 2026
035d70c
docs: rework csi-addons design §3 architecture — uniform promote/demo…
geoffrey1330 Sep 17, 2026
8ab10af
refactor(volume): the VolumeMigration controller joins the band it be…
noctarius Sep 17, 2026
cf24603
feat(node): the operator holds its own eviction while it arranges a d…
noctarius Sep 17, 2026
ec6037a
feat(api): a name a label carries is bounded at what a label holds
noctarius Sep 17, 2026
f03f644
Merge origin/main into develop
noctarius Sep 17, 2026
a4bd121
feat(upgrade): a legacy volume handle resolves its pool and records t…
noctarius Sep 17, 2026
c14938a
feat(driver): the driver asks whether the cluster has snapshots befor…
noctarius Sep 17, 2026
c9961af
refactor(deployment): a discovery run walks a declared graph rather t…
noctarius Sep 17, 2026
0fcb5e6
fix(api): the two rebalancing enums are spelled the way every other o…
noctarius Sep 17, 2026
1ce801f
feat(atlas-lib): a key is read under every spelling and written under…
noctarius Sep 17, 2026
fc5a470
feat(device): one device can be restarted without restarting its node
noctarius Sep 17, 2026
bfed606
refactor(device): the blocked actions are a TODO rather than a type
noctarius Sep 17, 2026
6ff5667
feat(node): a node whose pod cannot be placed says so
noctarius Sep 17, 2026
cb0e051
Vendor csi-addons v0.15.0 CRDs and controller-manager into the chart …
geoffrey1330 Sep 17, 2026
00b78d2
feat(metrics): the three unmeasured subsystems publish what they do
noctarius Sep 17, 2026
6f23852
refactor(nodeprobe): the reference formula is the shared one
noctarius Sep 17, 2026
acd948f
refactor(chart): the kubelet toggle belongs to the operator
noctarius Sep 17, 2026
e44a26e
refactor(chart): the event-log alert rules leave the chart
noctarius Sep 17, 2026
0110176
Resolve drtest- clone visibility: internal volumes, same as landing v…
geoffrey1330 Sep 17, 2026
1ba0807
Resolve drtest- clone visibility: internal volumes, same as landing v…
geoffrey1330 Sep 17, 2026
343f4f9
docs(crd-redesign): the designs describe the system that shipped
noctarius Sep 17, 2026
c3b879f
fix(cluster): the two lock waits are different waits, and the comment…
noctarius Sep 17, 2026
f0ffd19
Implement Phase 1 of csi-addons volume replication: driver Replicatio…
geoffrey1330 Sep 17, 2026
b0098f3
Implement Phase 2 lifecycle verbs (Promote/Demote/Resync) with P0-3 d…
geoffrey1330 Sep 18, 2026
bdab53f
support pattern quay.io/csiaddons
geoffrey1330 Sep 18, 2026
8c79840
updated simplyblockdriver_controller roles
geoffrey1330 Sep 18, 2026
0e62ef6
added node-id env field to csi-addons container
geoffrey1330 Sep 18, 2026
3a8dbbe
fixed csiaddon endpoint
geoffrey1330 Sep 18, 2026
989a49b
fixed merge conflict in design doc
geoffrey1330 Sep 18, 2026
7d5d663
added rbac verb TokenReview
geoffrey1330 Sep 18, 2026
0057b47
modified helm-charts/charts/simplyblock-operator/templates/rbac-csi-a…
geoffrey1330 Sep 18, 2026
3c44d9d
feat(discovery): the probe reads what the rules need, and the rules r…
noctarius Sep 18, 2026
79140e1
feat(webhook): a discovery run whose size range cannot be read is ref…
noctarius Sep 18, 2026
f17b2fb
test(discovery): 179 fleets the generator is run over, and two harnesses
noctarius Sep 18, 2026
3c32597
docs(discovery): the rules the generator applies, and the cases that …
noctarius Sep 18, 2026
2c348f8
fix(storagenode): a teardown reads the drain's phase, not the node's …
noctarius Sep 18, 2026
4ed1ca3
resolve volume ID via a shared volumeIDFrom(req) helper that checks R…
geoffrey1330 Sep 18, 2026
04e271d
read role via GetVolumeReplicationInfo before calling the backend's f…
geoffrey1330 Sep 18, 2026
3a831fd
reverted read role via GetVolumeReplicationInfo before calling the ba…
geoffrey1330 Sep 18, 2026
c13021b
feat(erasurecoding): the schemes, and how many nodes each one needs
noctarius Sep 18, 2026
9c52668
feat(api): the erasure-coding scheme is checked where it is written
noctarius Sep 18, 2026
606936c
feat(cluster): an activation waits until the fleet can carry its stripe
noctarius Sep 18, 2026
032d58c
feat(deployment): a draft is told its fleet is too small for its stri…
noctarius Sep 18, 2026
aa99753
feat(discovery): a draft proposes a scheme its fleet can carry
noctarius Sep 18, 2026
0b801a9
docs(crd-redesign): the designs carry the erasure-coding rules
noctarius Sep 18, 2026
20a8bf8
chore(repo): the loose files at the repository root leave it
noctarius Sep 18, 2026
04b2f17
feat(deployment): a draft is told its fleet is too small for its stri…
noctarius Sep 18, 2026
4337197
fix(operator): the two gates develop has been failing unseen
noctarius Sep 19, 2026
80ed261
fix(atlas-lib): a captured tree is read without the host it is read on
noctarius Sep 19, 2026
f2f2dd3
chore(operator): the fifteen lint findings the discovery work left
noctarius Sep 19, 2026
92625ac
fix(helm): the hostpath class is rendered only where its provisioner is
noctarius Sep 19, 2026
ce9436f
test(operator): the metrics group is covered at every kind it serves
noctarius Sep 19, 2026
4df8e88
fix(operator): the driver the chart writes is admitted before the ope…
noctarius Sep 20, 2026
07d62f7
fix(operator): the initial discovery run outlasts the webhook it depe…
noctarius Sep 20, 2026
d39bc1e
fix(operator): a refusal nobody can read is a refusal that was not de…
noctarius Sep 20, 2026
1afe517
feat(atlas-lib): the one on-disk signature this product writes and co…
noctarius Sep 20, 2026
346fdfc
fix(operator): a PCI address reaches the allow list, not the namespac…
noctarius Sep 20, 2026
bce0f52
fix(operator): a node survives its worker's reboot, and is recognized…
noctarius Sep 20, 2026
01a57c8
fix(operator): the step that asks for the add again can reach the one…
noctarius Sep 20, 2026
2bf5a03
feat(atlas-lib): a machine's own sysfs, and the reading that tells a …
noctarius Sep 20, 2026
1cd0693
fix(operator): the management interface is the one the node is reache…
noctarius Sep 20, 2026
cffa401
fix(rbac): the document that owns the activate can be named as its owner
noctarius Sep 20, 2026
0cc90a6
test(atlas-lib): a second host, captured with its NVMe controllers un…
noctarius Sep 20, 2026
57f0dac
fix(operator): a controller nothing owns is a disk, not an absence
noctarius Sep 20, 2026
0a749ca
fix(operator): the node-add cap holds when the nodes cannot see each …
noctarius Sep 20, 2026
5b1cf4c
feat(operator): the installed control plane serves TLS, and does by d…
noctarius Sep 21, 2026
3554e6a
fix(ci): the chart's renders state the capability its TLS guard reads
noctarius Sep 21, 2026
e73262b
updated doc design-csi-addons-replication.md
geoffrey1330 Sep 21, 2026
6591a5f
fix(operator): the probe of a TLS control plane verifies it
noctarius Sep 21, 2026
9322afc
fix(operator): the exporter was given the cluster file and no keys
noctarius Sep 21, 2026
657afc0
style(operator): the brand spelling the gate asked for
noctarius Sep 21, 2026
3feaf61
fix(operator): a control plane that answers does not hold an expansion
noctarius Sep 21, 2026
8eb989d
updated doc design-csi-addons-replication.md
geoffrey1330 Sep 21, 2026
5896a2e
fix(operator): a node-add slot is held for the add, not for the UUID
noctarius Sep 21, 2026
0879b0a
fix(operator): a node with no configuration says so
noctarius Sep 21, 2026
818a6de
fix(operator): a node with no subsystem count stops rather than askin…
noctarius Sep 21, 2026
3ac9796
rebased branch with main
geoffrey1330 Sep 21, 2026
fe82d5b
fix(operator): the workers enrolled and the workers configured are on…
noctarius Sep 21, 2026
435c8f0
Merge branch 'main' into integrate_csi_addons
geoffrey1330 Sep 21, 2026
0e614de
fixed manifest error
geoffrey1330 Sep 21, 2026
d9ca691
fix(operator): the journal-manager count is the control plane's to de…
noctarius Sep 21, 2026
ae6809b
updated doc design-csi-addons-replication.md
geoffrey1330 Sep 21, 2026
0b7f629
fix(operator): the spdk-proxy names are published again
noctarius Sep 21, 2026
4afa3ca
added design document design-ramen-integration.md
geoffrey1330 Sep 21, 2026
1fff099
docs(operator): recovering a namespace that will not finish deleting
noctarius Sep 21, 2026
d989374
added support for volumegroupreplication
geoffrey1330 Sep 21, 2026
c40f418
modified operator/dist/install.yaml
geoffrey1330 Sep 21, 2026
f49a326
fix(operator): a pushed node change wakes the node controller again
noctarius Sep 21, 2026
15563dc
fix Repo: Lint error
geoffrey1330 Sep 21, 2026
01b7e0d
feat(operator): a discovery run can name the workers it inspects
noctarius Sep 21, 2026
ba82118
Authenticate cluster-scoped control-plane calls with the cluster's ow…
geoffrey1330 Sep 22, 2026
7032d8f
Revert "Authenticate cluster-scoped control-plane calls with the clus…
geoffrey1330 Sep 22, 2026
f0322ac
rebased branch with branch develop
geoffrey1330 Sep 22, 2026
3810068
fixed boolean flag csiLinkEnabled
geoffrey1330 Sep 22, 2026
b979577
Extend cross-cluster auth to StorageNode and StorageNodeOps control-p…
geoffrey1330 Sep 22, 2026
2aac571
moved csiAddons into sidecarImages
geoffrey1330 Sep 22, 2026
742fbf2
Thread a managed control plane's admin credential into CreateCluster/…
geoffrey1330 Sep 22, 2026
9dd1143
ran make operator-build-installer
geoffrey1330 Sep 22, 2026
8a7c585
pool reach hub cluster endpoint
geoffrey1330 Sep 22, 2026
72a5832
fix cluster naming
geoffrey1330 Sep 22, 2026
b3bb56c
Fix cross-cluster managed control plane support: admin auth, endpoint…
geoffrey1330 Sep 22, 2026
6adbc0a
fixed linter issue
geoffrey1330 Sep 22, 2026
a7e0ace
Pass raw cluster UUIDs through ResolveClusterUUID for cross-cluster R…
geoffrey1330 Sep 22, 2026
5902d8b
Resolve the control-plane endpoint for ReplicationPair/ReplicationPol…
geoffrey1330 Sep 23, 2026
6038575
Authenticate ReplicationPair/ReplicationPolicy as their own cluster, …
geoffrey1330 Sep 23, 2026
45c9630
rebased branch with main
geoffrey1330 Sep 23, 2026
7aa02ab
Resolve foreign source-side volume handles to the local replica befor…
geoffrey1330 Sep 23, 2026
a6bddd2
fixed linter issue
geoffrey1330 Sep 23, 2026
345dd83
Enable-volume-replication no-ops when the destination volume doesn't …
geoffrey1330 Sep 23, 2026
eab20fa
fix(csi-driver): resolve foreign volumeHandle to local replica in Dem…
geoffrey1330 Sep 24, 2026
b529b86
fix(atlas-lib): resolve replication relationships via the cluster-sco…
geoffrey1330 Sep 24, 2026
5a01bb1
csi-driver: resolve resync and info reads to the local replica
geoffrey1330 Sep 24, 2026
0976957
csi-driver: clean up retired replica chain on DeleteVolume, never the…
geoffrey1330 Sep 24, 2026
dba955a
fixed unparsable
geoffrey1330 Sep 24, 2026
7438eb4
csi-driver: walk chained replication pairings to the active volume in…
geoffrey1330 Sep 24, 2026
ad47cab
fixed helm linter issue
geoffrey1330 Sep 24, 2026
71d75f2
removed storage-node manifest
geoffrey1330 Sep 24, 2026
43523f9
fixed manifest numa-resource-plugin.yaml
geoffrey1330 Sep 24, 2026
414f0b3
csi-driver: attach the class policy to the newly created primary afte…
geoffrey1330 Sep 24, 2026
c9bce76
Revert post-promote policy attach
geoffrey1330 Sep 24, 2026
fab913d
docs(csi-addons): document VolumeGroupReplication in the csi-addons d…
geoffrey1330 Sep 25, 2026
0a59a97
refactor(operator): remove offloaded VolumeGroupReplication reconcile…
geoffrey1330 Sep 25, 2026
a1bc487
feat(csi-addons): drive VolumeGroupReplication through the stock cont…
geoffrey1330 Sep 26, 2026
31ddf0e
csi-driver: route group Replication verbs from the volumegroup source…
geoffrey1330 Sep 26, 2026
6652adb
csi-driver: treat an empty replicationPolicyID as a no-op enable
geoffrey1330 Sep 27, 2026
c6fc146
csi-driver: fix golangci-lint lll and unparam in group replication tests
geoffrey1330 Sep 29, 2026
6af0d52
Merge remote-tracking branch 'origin/main' into integrate_csi_addons
geoffrey1330 Sep 29, 2026
ac97261
docs(operator): design non-disruptive test failover (TestFailover CRD…
geoffrey1330 Oct 1, 2026
f8f6a32
Merge branch 'main' into integrate_csi_addons
geoffrey1330 Oct 1, 2026
663764f
fixed merge linter issue
geoffrey1330 Oct 1, 2026
df26de2
fix(operator): skip hub-only TestFailover controller where OCM work A…
geoffrey1330 Oct 1, 2026
a18f13a
fix(operator): gate TestFailover on the ManifestWork resource, not it…
geoffrey1330 Oct 1, 2026
5bb7084
fix(operator): point tasks-runner-backup-merge at its real module
geoffrey1330 Oct 1, 2026
280662f
csi-driver: replication RPCs act on the chain's last LOCAL member, no…
michixs Oct 2, 2026
5106e18
csi-driver: lint (gofmt, goconst) for the local-replica resolver
michixs Oct 2, 2026
18c0824
csi-driver: demoting or detaching a reaped chain member succeeds
michixs Oct 2, 2026
9ee0e79
csi-driver: Resync and the status read of a reaped local member go to…
michixs Oct 2, 2026
65279a1
operator: register every cluster of the control plane with the CSI dr…
michixs Oct 2, 2026
bede3dd
csi-driver: PromoteVolume addresses the chain's active end, not the l…
michixs Oct 2, 2026
2b6e428
csi-driver: Resync and the status read address the chain's active end
michixs Oct 2, 2026
8988179
volstack/csi-driver: a plan that names no filesystem mounts what the …
michixs Oct 3, 2026
599a741
operator: a test fail-over's bubble PV and PVC carry the source's vol…
michixs Oct 3, 2026
7d5f38b
chart: the Control Center on the integrate_csi_addons line
michixs Oct 3, 2026
e356b56
csi-driver: a replication-chain walk is bounded by a cycle guard, not…
michixs Oct 3, 2026
f8760ac
operator: TestFailover CRD as controller-gen renders it
michixs Oct 3, 2026
ad4bad5
Merge fix/csi-local-cluster-resolution: chain-walk cycle guard, regen…
michixs Oct 3, 2026
8233d4b
operator: StorageSiteDeployment, a managed site's storage deployed fr…
michixs Oct 3, 2026
2ab649a
csi-driver: wrap lines over 120 characters; operator: regenerate dist…
michixs Oct 3, 2026
6050f17
Merge fix/csi-local-cluster-resolution (lint, installer)
michixs Oct 3, 2026
cce7357
operator: lint — a list-kind suffix constant; wrap the hub-only log line
michixs Oct 3, 2026
16f9713
operator: regenerate dist/install.yaml with the StorageSiteDeployment…
michixs Oct 3, 2026
81cdbf5
operator: the CSV owns StorageSiteDeployment
michixs Oct 3, 2026
54904c7
Merge pull request #618 from simplyblock/fix/csi-local-cluster-resolu…
schmidt-scaled Oct 3, 2026
bcfa439
Merge pull request #620 from simplyblock/feat/storage-site-deployment
schmidt-scaled Oct 3, 2026
ebd9a3b
Merge branch 'integrate_csi_addons' of https://github.com/simplyblock…
michixs Oct 3, 2026
287cd39
Merge pull request #619 from simplyblock/feat/csi-auto-cross-registra…
schmidt-scaled Oct 3, 2026
c6579ab
chart: the console's operator-API upstream is empty when the release …
michixs Oct 3, 2026
b71f0fa
csi-driver: a late consistency-group join live-migrates the volume to…
michixs Oct 3, 2026
161dad7
operator: the rebalancer skips consistency-group members; the CSI con…
michixs Oct 3, 2026
bed4b73
volstack: a dm-linear indirection under raw block and plain volumes (…
michixs Oct 3, 2026
7545be9
docs(design): consistency groups point at the co-location design
michixs Oct 3, 2026
b18cab7
test(node): the record-governed shape case uses a second volume handle
michixs Oct 3, 2026
1d7008c
chart: the Control Center may update site profiles
michixs Oct 3, 2026
94ca3d9
csi-driver: GetReplicationDestinationInfo, so Ramen can restore a con…
michixs Oct 3, 2026
6de1995
Merge pull request #626 from simplyblock/feat/replication-destination…
schmidt-scaled Oct 4, 2026
7ba0300
Merge pull request #622 from simplyblock/fix/control-center-absent-op…
schmidt-scaled Oct 4, 2026
c1c2c56
Merge pull request #625 from simplyblock/fix/console-siteprofile-rbac
schmidt-scaled Oct 4, 2026
0f6383c
Merge pull request #623 from simplyblock/feat/cg-colocation
schmidt-scaled Oct 4, 2026
1f94d8e
csi-driver: a group handle resolves to where the group's data lives now
michixs Oct 4, 2026
981ea4b
operator: start the hub-only OCM controllers when ManifestWork appear…
michixs Oct 4, 2026
582cdde
operator: a test fail-over places its PV and PVC CreateOnly; the bubb…
michixs Oct 4, 2026
7e0f931
operator: tests name the bubble namespace once (goconst)
michixs Oct 4, 2026
db3e364
Merge pull request #629 from simplyblock/fix/cg-handle-resolution
schmidt-scaled Oct 4, 2026
7e2c257
Merge pull request #631 from simplyblock/fix/testfailover-pv-binding
schmidt-scaled Oct 4, 2026
22efd7e
operator: build the manager from its package, not from main.go alone
michixs Oct 4, 2026
05b9f99
Merge pull request #630 from simplyblock/fix/ocm-controllers-late-start
schmidt-scaled Oct 4, 2026
cbeaf34
fix(testfailover): pair group generation snapshots with PVCs by volum…
michixs Oct 4, 2026
212f534
Merge pull request #633 from simplyblock/fix/testfailover-group-membe…
schmidt-scaled Oct 4, 2026
7d31da0
chart: the Control Center may create the console's S3 and health prob…
michixs Oct 4, 2026
93dd3a5
Merge pull request #634 from simplyblock/feat/control-center-chart
schmidt-scaled Oct 4, 2026
e831853
chart: the Control Center reads the dr-agent views, creates DHCP prob…
michixs Oct 5, 2026
439b434
Merge main into integrate_csi_addons
michixs Oct 5, 2026
a10f266
chart+operator: the Control Center reads storage through the control …
michixs Oct 5, 2026
2941110
test(node): main's provisioner fixture carries a Workload
michixs Oct 5, 2026
d47e2a0
operator: regenerate dist/install.yaml after the main merge
michixs Oct 5, 2026
c3f46fe
Merge pull request #653 from simplyblock/merge/main-into-integrate-cs…
schmidt-scaled Oct 5, 2026
bb08b1e
Merge pull request #652 from simplyblock/feat/console-discovery-rbac
schmidt-scaled Oct 5, 2026
42af35a
Merge pull request #655 from simplyblock/feat/console-controlplane-up…
schmidt-scaled Oct 5, 2026
a841327
fix(operator): tasks-runner-backup-merge runs sbcli main's backup_mer…
michixs Oct 5, 2026
da540a4
chart: the Control Center's log store (Graylog search, read-only)
michixs Oct 5, 2026
8822a5c
Merge pull request #656 from simplyblock/fix/backup-merge-module-sbcl…
schmidt-scaled Oct 6, 2026
a042e69
Merge pull request #658 from simplyblock/feat/console-logstore-chart
schmidt-scaled Oct 6, 2026
175bd7a
fixed merge conflict
geoffrey1330 Oct 6, 2026
c92cd52
Merge branch 'main' into integrate_csi_addons
geoffrey1330 Oct 6, 2026
6e25822
fix(operator): the admin service account tests are declared once
noctarius Oct 6, 2026
39af1c2
chore(fleet): regenerate the DriverDeployment CRD for the csi-addons …
noctarius Oct 6, 2026
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
1 change: 1 addition & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"worktree": {"bgIsolation": "none"}}
159 changes: 159 additions & 0 deletions .cspell-crd-redesign.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Spell-check terms for operator/docs/designs/crd-redesign and its test plans.
#
# Produced by running cspell with the repository's .cspell.json over the ten design
# documents, their assets, and the nine test plans. Every entry below is a word that
# run reported and the dictionary does not carry.
#
# This file is deliberately untracked and is a staging list, not a dictionary the
# build reads. Nothing consumes it yet: MegaLinter reads .cspell.json's `words`, so
# the groups below are the candidates for that list once each has been decided.
#
# Four groups, and only the last one is a judgment call.
#
# kinds Kind names, short names, and generated file names. Add as they are.
# code Go, kubebuilder, and package identifiers appearing in prose. Add as they are.
# product Product, protocol, and platform names not this repository's to spell.
# Add as they are, and check the casing variants are the ones actually used.
# prose Words the design prose coins. Each is either added here or the prose is
# reworded; that decision has not been taken.

# --- kinds (35) -----------------------------------------------
autoplacement
backupops
backuppolicy
backuprestore
clusterdeploymentconfig
controlplane
controlplaneops
cpops
nodeset
operatorops
persistentvolume
persistentvolumeclaims
persistentvolumeops
persistentvolumes
pvops
rollingrestart
sbops
sdops
simplyblockdriver
Snode
snode
spops
storagebackup
storagebackupops
storagebackuppolicy
storagebackups
storageclass
storageclasses
storagecluster
storageclusters
storagedevice
storagedeviceops
storagepool
storagepoolops
storagepools

# --- code (26) ------------------------------------------------
corev
cpinformer
customresources
envtest
foundationdb
kubebuilder
livenessprobe
metav
metricsapi
mongodbcommunity
omitempty
pernodeconfig
printcolumn
resizer
sbcli
SBTLS
simplybk
statemachine
subresource
subtest
# the two below are British spellings, and they are shipped Go test function
# names the test plans quote verbatim, not prose this corpus can reword.
# operator/internal/controller: TestSanitiseDNSLabel_*, *_NodeRollingRestart_Initialises
Initialises
Sanitise
WEBAPI
webapi
webapimock
webappapi

# --- product (42) ---------------------------------------------
AXYZ
dhchap
DHCHAP
elon
finalizers
HCLS
hostnames
hostpath
hugepages
Ifname
kubelet
Kubelet
lvol
Lvol
Lvols
mbps
Mbytes
mbytes
mgmt
Mgmt
MZQL
NDCS
ndcs
npcs
NPCS
nvme
NVME
Nvme
nvmeof
Nvmf
nvmf
schedulable
smartctl
spdk
Spdk
SPDK
subsys
SUBSYS
tolerations
Tolerations
VCPU
vcpu

# --- prose (26) -----------------------------------------------
alertable
antipattern
catchable
cutover
deadlineless
graphable
metacharacter
parameterizes
provisionable
Recasing
regroupings
Repointing
sourceable
streamability
streamable
unaddressable
unasserted
unbuilt
undrainable
unexempted
unpartitioned
Unprovisioned
unreworked
upserted
upserts
waivable

152 changes: 152 additions & 0 deletions atlas-lib/controlplane/consistencygroups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Consistency-group reads the csi-addons VolumeGroup service needs: resolving the
// backend consistency group a set of member volumes already belongs to (design
// design-csi-addons-replication.md §14.3). A group is formed at provisioning by
// the storage.simplyblock.io/consistency-group label; this only reads it back.
package controlplane

import (
"context"
"errors"
"fmt"

"github.com/google/uuid"

"github.com/simplyblock/atlas/errs"
"github.com/simplyblock/atlas/internal/cpapi"
"github.com/simplyblock/atlas/lvol"
)

// ConsistencyGroupForLvols returns the id of the backend consistency group in
// clusterID whose current (open-epoch) membership is exactly lvolIDs.
//
// The members provisioned under one storage.simplyblock.io/consistency-group
// label share one backend group, so the VolumeGroup service resolves the group
// by its members rather than by the name it is handed (which is the caller's own
// generated name, not the group's). Returns an error when no group's membership
// matches exactly, so a partial or mixed selection is never silently grouped.
func (c *Client) ConsistencyGroupForLvols(ctx context.Context, clusterID string, lvolIDs []string) (string, error) {
cluster, err := parseUUID("cluster id", clusterID)
if err != nil {
return "", err
}
if len(lvolIDs) == 0 {
return "", fmt.Errorf("no volumes given to resolve a consistency group")
}
want := make(map[string]bool, len(lvolIDs))
for _, id := range lvolIDs {
want[id] = true
}

listResp, err := c.api.ClustersConsistencyGroupsListApiV2ClustersClusterIdConsistencyGroupsGetWithResponse(
ctx, cluster, &cpapi.ClustersConsistencyGroupsListApiV2ClustersClusterIdConsistencyGroupsGetParams{})
if err != nil {
return "", fmt.Errorf("list consistency groups in cluster %s: %w", clusterID, err)
}
groups, err := payload("consistency groups in cluster "+clusterID,
listResp.JSON200, listResp.StatusCode(), listResp.Body)
if err != nil {
return "", err
}

for _, g := range *groups {
members, err := c.consistencyGroupMembers(ctx, cluster, g.Id)
if err != nil {
return "", err
}
if sameStringSet(members, want) {
return g.Id.String(), nil
}
}
return "", fmt.Errorf("no consistency group in cluster %s has exactly the %d requested member(s)",
clusterID, len(lvolIDs))
}

// consistencyGroupMembers returns a group's current open-epoch member lvol ids.
func (c *Client) consistencyGroupMembers(ctx context.Context, cluster, group uuid.UUID) ([]string, error) {
resp, err := c.api.ClustersConsistencyGroupsMembersApiV2ClustersClusterIdConsistencyGroupsGroupIdMembersGetWithResponse(
ctx, cluster, group)
if err != nil {
return nil, fmt.Errorf("members of consistency group %s: %w", group, err)
}
dtos, err := payload("members of consistency group "+group.String(),
resp.JSON200, resp.StatusCode(), resp.Body)
if err != nil {
return nil, err
}
open := make([]string, 0, len(*dtos))
for _, m := range *dtos {
if m.RemovedSeq == 0 {
open = append(open, m.LvolId)
}
}
return open, nil
}

// sameStringSet reports whether ids is exactly the set want (same length, same
// elements), so a resolved group is neither a superset nor a subset of the
// requested members.
func sameStringSet(ids []string, want map[string]bool) bool {
if len(ids) != len(want) {
return false
}
for _, id := range ids {
if !want[id] {
return false
}
}
return true
}

// ConsistencyGroupMemberHandles returns the volume handles
// ("<cluster>:<pool>:<lvol>") of a consistency group's current (open-epoch)
// members, in the order the control plane lists them.
//
// The member listing carries bare lvol ids. Every member of one group lives in
// one storage pool (the backend refuses a cross-pool join), so the pool is
// resolved once, from the first member, by probing the cluster's pools. An
// empty group is an error: a caller mapping members (csi-addons destination
// info) must never return an empty map as if it were complete.
func (c *Client) ConsistencyGroupMemberHandles(
ctx context.Context, gh lvol.GroupHandle,
) ([]lvol.VolumeHandle, error) {
cluster, err := parseUUID("cluster id", gh.ClusterID)
if err != nil {
return nil, err
}
group, err := parseUUID("consistency group id", gh.GroupID)
if err != nil {
return nil, err
}
members, err := c.consistencyGroupMembers(ctx, cluster, group)
if err != nil {
return nil, err
}
if len(members) == 0 {
return nil, fmt.Errorf("consistency group %s has no current members", gh)
}
pools, err := c.ListStoragePools(ctx, gh.ClusterID)
if err != nil {
return nil, err
}
poolID := ""
for _, p := range pools {
h := lvol.Handle{ClusterID: gh.ClusterID, PoolRef: p.ID, VolumeID: members[0]}
_, err := c.Volume(ctx, h.Handle())
if err == nil {
poolID = p.ID
break
}
if !errors.Is(err, errs.ErrNotFound) {
return nil, err
}
}
if poolID == "" {
return nil, fmt.Errorf("member %s of consistency group %s is in none of the %d pools of cluster %s: %w",
members[0], gh, len(pools), gh.ClusterID, errs.ErrNotFound)
}
out := make([]lvol.VolumeHandle, 0, len(members))
for _, m := range members {
out = append(out, lvol.Handle{ClusterID: gh.ClusterID, PoolRef: poolID, VolumeID: m}.Handle())
}
return out, nil
}
72 changes: 72 additions & 0 deletions atlas-lib/controlplane/consistencygroups_members_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package controlplane

import (
"context"
"net/http"
"strings"
"testing"

"github.com/simplyblock/atlas/lvol"
)

// The member listing carries bare lvol ids; the handles need the pool, which
// the group's first member is probed for across the cluster's pools. Here it
// lives in the SECOND pool, and a removed member is left out.
func TestConsistencyGroupMemberHandlesResolvesThePool(t *testing.T) {
const (
group = "c9c9c9c9-c9c9-4c9c-8c9c-c9c9c9c9c9c9"
m1 = "a1111111-1111-4111-8111-111111111111"
m2 = "b2222222-2222-4222-8222-222222222222"
gone = "d4444444-4444-4444-8444-444444444444"
otherPool = "55555555-5555-5555-5555-555555555555"
)
pool := func(id, name string) string {
return `{"id":"` + id + `","cluster_id":"` + testCluster + `","name":"` + name + `",` +
`"max_size":1000,"capacity":{},"max_r_mbytes":0,"max_rw_iops":0,"max_rw_mbytes":0,` +
`"max_w_mbytes":0,"volume_max_size":0,"status":"active"}`
}
member := func(id string, removed int) string {
return `{"lvol_id":"` + id + `","joined_seq":1,"removed_seq":` + string(rune('0'+removed)) +
`,"node_id":"n","lvs_name":"l","online":true}`
}
c := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch {
case strings.HasSuffix(r.URL.Path, "/consistency-groups/"+group+"/members"):
_, _ = w.Write([]byte("[" + member(m1, 0) + "," + member(gone, 3) + "," + member(m2, 0) + "]"))
case strings.HasSuffix(r.URL.Path, "/storage-pools/"):
_, _ = w.Write([]byte("[" + pool(otherPool, "other") + "," + pool(testPool, "pool1") + "]"))
case strings.Contains(r.URL.Path, "/storage-pools/"+testPool+"/volumes/"+m1):
_, _ = w.Write([]byte(`{"id":"` + m1 + `","name":"pvc-1","pool_name":"pool1",` +
`"size":20971520,"ns_id":1,"nqn":"nqn.2023-02.io.simplyblock:c:lvol:v"}`))
default:
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(`{"detail":"not found"}`))
}
})

got, err := c.ConsistencyGroupMemberHandles(context.Background(),
lvol.GroupHandle{ClusterID: testCluster, GroupID: group})
if err != nil {
t.Fatal(err)
}
want := []lvol.VolumeHandle{
lvol.VolumeHandle(testCluster + ":" + testPool + ":" + m1),
lvol.VolumeHandle(testCluster + ":" + testPool + ":" + m2),
}
if len(got) != len(want) || got[0] != want[0] || got[1] != want[1] {
t.Fatalf("handles = %v, want %v", got, want)
}
}

func TestConsistencyGroupMemberHandlesOfAnEmptyGroupIsAnError(t *testing.T) {
c := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`[]`))
})
_, err := c.ConsistencyGroupMemberHandles(context.Background(),
lvol.GroupHandle{ClusterID: testCluster, GroupID: "c9c9c9c9-c9c9-4c9c-8c9c-c9c9c9c9c9c9"})
if err == nil {
t.Fatal("an empty group answered without an error")
}
}
Loading
Loading