Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
89021c1
Implement indexing for ReplicatedVolumeReplica by replicatedVolumeName
Dec 31, 2025
2f9f672
[controller] Introduce rv-controller: RV metadata + deviceMinor alloc…
Jan 1, 2026
e6d77ce
refactor(api): rename status.conditions constants and add Cursor nami…
Jan 2, 2026
1e8dfa1
[dev] Add Cursor Go coding/testing rules
Jan 2, 2026
0e31413
[api] Reorganize v1alpha1 types and conditions
Jan 2, 2026
67e1072
[tooling] Add direnv caches and migrate Cursor rules to .mdc
Jan 2, 2026
87fff30
[controller] Type-safe device minor allocation
Jan 2, 2026
9069534
[api] Add objutilv1 helpers and migrate usages from v1alpha1
Jan 2, 2026
a985a6e
[controller] Introduce reconciliation flow and refactor RV controller
Jan 3, 2026
f74112d
[internal] Encapsulate flow.Outcome and extend objutilv1 helpers
Jan 4, 2026
1335e25
[dev] Clarify controller.go wiring rules and commit sign-off policy
Jan 4, 2026
afb3842
[controller] Refine ReplicatedVolume update predicate
Jan 4, 2026
73373c3
[reconciliation/flow] Track changes and optimistic-lock requirement i…
Jan 4, 2026
0c382f1
[rules] Require commit messages to be output in a code block
Jan 4, 2026
2137cbd
[dev] Document controller reconcile helper contracts; add flow.Outcom…
Jan 4, 2026
598ec32
[docs] Expand controller ReconcileHelper guidelines
Jan 5, 2026
223b150
[rules] Refine controller reconciliation guide
Jan 5, 2026
fe0a70c
[dev] Refine controller reconciliation rules for error context
Jan 5, 2026
712aa45
[flow] Add phase context helpers and Outcome.OnErrorf
Jan 5, 2026
e61f9fa
[docs] Clarify flow.Outcome usage in reconcile helpers
Jan 5, 2026
ae6be19
[rules] Add controller terminology and flow usage rules
Jan 5, 2026
c4f2967
[rules] Refine controller rule docs structure and terminology
Jan 6, 2026
de8dfb0
[flow] Validate phase kv pairs and stabilize error context
Jan 6, 2026
68f535e
[flow] Log phase errors once; remove ContinueErr
Jan 6, 2026
da43af7
[rules] Normalize controller docs terminology and formatting
Jan 6, 2026
54a6d16
[controller] Refactor RV reconciler patching and error propagation
Jan 7, 2026
5fc978d
[controller] Inline storageClass label sync for RV and drop API helpers
Jan 7, 2026
e7fa7f8
[controller] Refactor RV device-minor allocation and idpool API
Jan 8, 2026
4ba7daa
[controller] Rename IsUpToDate helpers to IsInSync
Jan 8, 2026
e60a40b
[controller] RV reconciler: treat NotFound as deleted and normalize n…
Jan 8, 2026
05946b9
[cursor] Extend controller rules globs to rv_attach_controller
Jan 9, 2026
f40c804
[cursor] Add RFC-style writing rules for .mdc documents
Jan 12, 2026
7fede95
[rules] Split predicate rules into predicate.go and add GetReconcileH…
Jan 12, 2026
7cebad9
[rules] Normalize .mdc frontmatter and centralize RFC-style conventions
Jan 12, 2026
92ca3d2
[rules] Align controller rule docs with RFC keyword formatting
Jan 12, 2026
5660f63
[rules] Define API short kind names for controller helper/predicate n…
Jan 12, 2026
7e9ca2c
[rules] Document `reconciler.go` layout and helper ordering conventions
Jan 12, 2026
66ef1e3
[rules] Add controller reconciliation rules for optional scalars and …
Jan 12, 2026
5882b5c
[rules] Document optional scalar fields as `*T` across API and reconc…
Jan 12, 2026
3c7cb0c
[rules] Add split-client determinism guidance to reconciliation docs
Jan 12, 2026
8a77d79
[flow] Introduce typed flow scopes for reconcile/ensure/steps
Jan 16, 2026
7c9f8db
Merge branch 'astef-prototype' into astef-prototype-rv-controller
Jan 16, 2026
2f2262e
[controller] Preserve deviceMinor on pool errors
Jan 16, 2026
d999da2
[rules] Refactor flow API: split Outcome into ReconcileOutcome and En…
Jan 16, 2026
77d3b5e
[cursor-rules] Improve controller reconcile helper documentation
Jan 16, 2026
e76bc15
[ci] Add all image modules to go.work and fix internal dependency
Jan 16, 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
19 changes: 0 additions & 19 deletions .cursor/rules.mdc

This file was deleted.

17 changes: 17 additions & 0 deletions .cursor/rules/api-codegen.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
description: API codegen rules for kubebuilder/controller-gen and generated files hygiene. Apply when adding/modifying API types or kubebuilder markers under api/v*/, and when deciding whether regeneration is required. Apply when editing relevant files, and when reasoning/planning/answering questions where this rule could influence code decisions (even if matching files are not currently open).
globs: api/v*/**/*.go
alwaysApply: false
---

- Kubebuilder markers & API changes (MUST):
- If I add a new API object/type or modify an existing one in `api/` (especially changes to `// +kubebuilder:*` markers, validation markers, printcolumns, subresources, etc.), I MUST run code generation and include the regenerated outputs in the same change.
- In this repo, run generation from the repository root:
- `bash hack/generate_code.sh`
- If I am intentionally doing an **API-only refactor stage** where changes outside `api/` are temporarily forbidden/undesired (e.g. the rest of the repo is not yet refactored and will not compile), then:
- It is acceptable to **defer CRD regeneration** (outputs under `crds/`) until the stage when cross-repo refactor is allowed.
- I MUST still keep `api/v1alpha1` internally consistent and compilable; prefer running **object/deepcopy generation only** when possible, instead of editing generated files by hand.

- Generated files (MUST NOT edit by hand):
- Do NOT edit `zz_generated*` files (e.g. `api/v1alpha1/zz_generated.deepcopy.go`) manually.
- If a generated file needs to change, update the source types/markers and re-run generation instead.
56 changes: 56 additions & 0 deletions .cursor/rules/api-conditions.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
description: API condition Type/Reason constants naming, ordering, comments, and stability rules. Apply when editing api/v*/**/*_conditions.go, and when deciding how to name/add conditions for API objects. Apply when editing relevant files, and when reasoning/planning/answering questions where this rule could influence code decisions (even if matching files are not currently open).
globs: api/v*/**/*_conditions.go
alwaysApply: false
---

- Condition constants naming:
- Every API object `Status` MUST expose `.status.conditions` (`[]metav1.Condition`) (see `types_rules.mdc`).
- Any API object that has at least one standardized/used condition MUST have its own condition type/reason constants scoped by object name.
- If the API type exposes `.status.conditions` but there are **no** standardized/used conditions yet:
- The `Conditions` field MUST remain in the API (it is part of the contract).
- The `<objprefix>_conditions.go` file MAY be absent.
- Do NOT create placeholder/empty condition constants “just in case”.
- Current API types that expose `.status.conditions` in this repo:
- `ReplicatedVolume`
- `ReplicatedVolumeReplica`
- `ReplicatedVolumeAttachment`
- `ReplicatedStorageClass`
- `ReplicatedStoragePool`

- Condition Type constants MUST be named:
- `<ObjName>Cond<CondTypeName>Type`
- `CondTypeName` MUST match the string value of `.Type`.
- Examples:
- `ReplicatedVolumeCondIOReadyType = "IOReady"`
- `ReplicatedVolumeReplicaCondDataInitializedType = "DataInitialized"`
- `ReplicatedVolumeAttachmentCondReplicaIOReadyType = "ReplicaIOReady"`

- Condition Reason constants MUST be named:
- `<ObjName>Cond<CondTypeName>Reason<ReasonName>`
- `CondTypeName` MUST match the string value of the condition type (the `.Type` string).
- `ReasonName` MUST match the string value of `.Reason`.
- Examples:
- `ReplicatedVolumeReplicaCondScheduledReasonReplicaScheduled = "ReplicaScheduled"`
- `ReplicatedVolumeCondQuorumReasonQuorumLost = "QuorumLost"`
- `ReplicatedVolumeAttachmentCondAttachedReasonSettingPrimary = "SettingPrimary"`

- Conditions grouping (MUST):
- Keep each condition type and **all of its reasons in a single `const (...)` block**.
- Conditions MUST be ordered alphabetically by condition type name within the file/package.
- Reasons within a condition MUST be ordered alphabetically by reason constant name.

- Conditions comments (MUST):
- Avoid controller-specific comments like “managed by X” in API packages.
- Add short English docs: what the condition represents and what the reasons mean.

- Value stability (MUST):
- Do NOT change string values of `.Type` and `.Reason` constants.
- Only rename Go identifiers when reorganizing/clarifying.

- Scoping & duplication (MUST):
- Do NOT use generic `ConditionType*` / `Reason*` constants.
- If the same reason string is used by multiple conditions, create separate constants per condition type, even if the string is identical.
- Example: `"NodeNotReady"`:
- `ReplicatedVolumeReplicaCondOnlineReasonNodeNotReady = "NodeNotReady"`
- `ReplicatedVolumeReplicaCondIOReadyReasonNodeNotReady = "NodeNotReady"`
21 changes: 21 additions & 0 deletions .cursor/rules/api-file-structure.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
description: API package conventions: object prefixes and per-object/common file naming rules under api/. Apply when creating/renaming/editing Go files under api/v*/, and when deciding where API code should live. Apply when editing relevant files, and when reasoning/planning/answering questions where this rule could influence code decisions (even if matching files are not currently open).
globs: api/v*/**/*.go
alwaysApply: false
---

- Object prefixes (MUST):
- Use short prefixes: `rv`, `rvr`, `rva`, `rsc`, `rsp`.

- File naming per object (MUST):
- `<objprefix>_types.go`: API types (kubebuilder tags), object/spec/status structs, adapters for interfaces (e.g. GetConditions/SetConditions) and tightly coupled constants/types and pure set/get/has helpers (no I/O, no external context).
- `<objprefix>_conditions.go`: condition Type/Reason constants for the object.
- MAY be absent if the API object exposes `.status.conditions` but there are no standardized/used conditions yet (do not create empty placeholder constants).
- `<objprefix>_custom_logic_that_should_not_be_here.go`: non-trivial/domain logic helpers (everything that does not fit `*_types.go`).

- Common file naming (MUST):
- `common_types.go`: shared types/enums/constants for the API package.
- `common_helpers.go`: shared pure helpers used across API types.
- `labels.go`: well-known label keys (constants).
- `finalizers.go`: module finalizer constants.
- `register.go`: scheme registration.
42 changes: 42 additions & 0 deletions .cursor/rules/api-labels-and-finalizers.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
description: API naming rules for label keys (labels.go) and finalizer constants (finalizers.go): naming, value formats, and stability. Apply when editing api/v*/**/labels.go or api/v*/**/finalizers.go, and when deciding label/finalizer names/values. Apply when editing relevant files, and when reasoning/planning/answering questions where this rule could influence code decisions (even if matching files are not currently open).
globs: api/v*/**/finalizers.go,api/v*/**/labels.go
alwaysApply: false
---

## Label keys (`labels.go`)

- **Constant naming (MUST)**:
- Label key constants MUST end with `LabelKey`.
- Good: `ReplicatedVolumeLabelKey`, `NodeNameLabelKey`
- Bad: `LabelReplicatedVolume`, `NodeLabel`, `LabelNodeName`

- **Prefix constant (MUST)**:
- The label prefix constant MUST be private and named `labelPrefix` (unless there is a proven need to export it).
- The prefix value MUST be the module-scoped prefix:
- `sds-replicated-volume.deckhouse.io/`

- **Value format (MUST)**:
- Label key values MUST be built as `labelPrefix + "<suffix>"`.
- The `<suffix>` part MUST be lowercase-kebab-case, without repeating the module name.
- Good: `labelPrefix + "replicated-volume"`
- Bad: `labelPrefix + "sds-replicated-volume-replicated-volume"`

- **Layout (MUST)**:
- Keep all exported `...LabelKey` constants in a single `const (...)` block.
- Avoid commented-out placeholder constants; prefer adding constants only when actually needed.

## Finalizers (`finalizers.go`)

- **Constant naming (MUST)**:
- Finalizer constants MUST end with `Finalizer`.
- Good: `ControllerFinalizer`, `AgentFinalizer`
- Bad: `FinalizerController`, `ControllerFinalizerName`

- **Value format (MUST)**:
- Finalizer values MUST be module-scoped and stable:
- `sds-replicated-volume.deckhouse.io/<component>`
- `<component>` MUST be lowercase and short (e.g. `controller`, `agent`).

- **Stability (MUST)**:
- Do NOT change existing finalizer string values (this would break cleanup semantics).
157 changes: 157 additions & 0 deletions .cursor/rules/api-types.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
description: API type rules: type-centric layout, enums/constants, status/conditions requirements, naming, and what helpers may live in *_types.go vs custom-logic files. Apply when editing api/v*/**/*_types.go or api/v*/**/common_types.go, and when deciding API type layout or helper placement. Apply when editing relevant files, and when reasoning/planning/answering questions where this rule could influence code decisions (even if matching files are not currently open).
globs: api/v*/**/*_types.go,api/v*/**/common_types.go
alwaysApply: false
---

## Code layout: type-centric blocks (MUST)

- **Type-centric blocks** MUST be used to organize code:
- Each type MUST be readable without scrolling across the file (keep related declarations together).
- Code from different types MUST NOT be interleaved.

- **API object file layout** (MUST):
- This applies to typical files containing one API root object (`type <Obj> struct`) plus its `Spec`/`Status`/`List`.
- The main flow MUST read top-to-bottom without jumping:
- Root object: `type <Obj> struct { ... }`
- `type <Obj>List struct { ... }` (see List rule below)
- `type <Obj>Spec struct { ... }`
- Spec-local types/enums/constants/interfaces/helpers used by `Spec`
- `type <Obj>Status struct { ... }`
- Status-local types/enums/constants/interfaces/helpers used by `Status`
- Secondary/helper types referenced by the above (pseudo-DFS), keeping each type block contiguous
- Shared helpers (if any) at the very end

- **Block structure** for each type MUST follow this strict order:
- `type <TypeName> struct { ... }`
- Enums and constants belonging to this type (incl. tightly-coupled sub-enums)
- Interfaces tightly coupled to the type
- Public methods of the type
- Private helpers of the type

- **Block ordering in a file** MUST be a human-oriented dependency order (pseudo-DFS), not alphabetical:
- Main (primary) type of the file
- Types directly referenced by the main type
- Secondary/helper types

- **List types** (MUST):
- `<Obj>List` SHOULD be placed immediately after `<Obj>` (right under the root object), to make navigation consistent and fast.
- `<Obj>List` MUST NOT split the `Spec`/`Status` flow (i.e. do not put it between `Spec` and spec-local enums/helpers, or between `Status` and status-local enums/helpers).
- If there is a strong reason (rare), `<Obj>List` MAY be placed after `Status`/secondary types, but keep it as a single contiguous block (no interleaving).

- **Locality rule for enums/constants/helpers** (MUST):
- If an enum/const/helper is primarily used by `Spec`, it MUST be placed in the Spec-local section (right after `type <Obj>Spec ...` and its methods).
- If an enum/const/helper is primarily used by `Status`, it MUST be placed in the Status-local section (right after `type <Obj>Status ...` and its methods).
- If an enum/const/helper is used by both `Spec` and `Status`, it SHOULD be placed with the `Spec` section (earlier) unless that hurts readability; do NOT duplicate it.

- **Shared helpers**:
- Avoid generic helpers without a clear owning type.
- If a helper is used by multiple types, it MUST be placed after all type blocks (or moved to `common_helpers.go` if shared broadly).

- Enums (MUST):
- If a field has a finite set of constant values, model it as an enum:
- `type EnumType string`
- `const ( EnumTypeValue1 EnumType = "Value1" ... )`
- Enum declaration order MUST be contiguous:
- `type EnumType string`
- `const (...)` with all enum values
- enum helpers (if any) — right after the const block
- Enums MUST provide `String()` method:
- `func (e EnumType) String() string { return string(e) }`
- Keep enum values documented (short English comment per value or a short block comment).
- Do NOT create separate wrapper types for arbitrary string/number/bool fields unless there is a strong, confirmed need.
- Common enums (MUST):
- If the same enum is used by multiple API objects, it MUST be moved to `common_types.go`.
- Do NOT move enums to `common_types.go` if they are only used by a single API object.

- Status (MUST):
- `Spec` and `Status` structs MUST be embedded as values on the root object (e.g. `Spec TSpec`, `Status TStatus`), not `*TStatus`.
- Every API object `Status` MUST expose `.conditions` as `[]metav1.Condition`:
- Field name MUST be `Conditions []metav1.Condition`.
- Use the standard kubebuilder/patch markers for mergeable conditions list:
- `// +patchMergeKey=type`
- `// +patchStrategy=merge`
- `// +listType=map`
- `// +listMapKey=type`
- `// +optional`
- JSON tag: ``json:"conditions,omitempty"`` and patch tags consistent with the above.
- Condition Type/Reason constants are defined in `<objprefix>_conditions.go` only when they become standardized/used (see `conditions_rules.mdc`).
- Every API **root object** that exposes `.status.conditions` MUST provide adapter methods to satisfy `api/objutilv1.StatusConditionObject`:
- `GetStatusConditions() []metav1.Condition` (returns `o.Status.Conditions`)
- `SetStatusConditions([]metav1.Condition)` (sets `o.Status.Conditions`)

- Type naming (MUST):
- This section applies to ALL API types (including enums).
- Names MUST be unique within the API package.
- Names MUST NOT start with short object prefixes like `RV`, `RVR`, `RVA`, `RSC`, `RSP`.
- Usually, names MUST NOT start with the full object name if the type is not generic and is unlikely to clash:
- Good: `ReplicaType`, `DiskState`
- Prefer full object name only for generic/repeated concepts (below).
- If the type name is generic and likely to be repeated across objects (e.g. `Phase`, `Type`), it MUST start with the full object name:
- Examples: `ReplicatedStoragePoolPhase`, `ReplicatedStoragePoolType`, `ReplicatedVolumeAttachmentPhase`
- Structural type name (e.g. `Spec`, `Status`) MUST be prefixed by the full object name:
- Examples: `ReplicatedVolumeSpec`, `ReplicatedVolumeStatus`, `ReplicatedStorageClassSpec`, `ReplicatedStorageClassStatus`

- Optional scalar fields (optional `*T`) (MUST):
- This section applies to Kubernetes API fields that are semantically optional (tagged `json:",omitempty"`), but whose underlying value type is a scalar `T` (non-nil-able, e.g. `bool`, numbers, `string`, structs).
- To preserve the distinction between "unset" and "set to the zero value", such API fields MUST be represented as pointers (`*T`) in Go API types.
- Example (illustrative): if `TimeoutSeconds` is optional, use `*int32` (not `int32`) and tag it with `json:"timeoutSeconds,omitempty"`.

## Helpers vs custom_logic_that_should_not_be_here (MUST)

Write helpers in `*_types.go`. If a function does **not** fit the rules below, it MUST go to `*_custom_logic_that_should_not_be_here.go`.

## What belongs in `*_types.go` (MUST)

Helpers are **pure**, **local**, **context-free** building blocks.

- **Pure / deterministic**:
- Same input → same output.
- No reads of current time, random, env vars, filesystem, network, Kubernetes API, shell commands.
- No goroutines, channels, retries, backoff, sleeping, polling.

- **No external context**:
- Do not require `context.Context`, `*runtime.Scheme`, `client.Client`, informers, listers, recorders, loggers.
- Do not require controller-runtime utilities (e.g. `controllerutil.*`).

- **Allowed operations**:
- Field reads/writes on in-memory structs and maps/slices.
- Simple validation and parsing/formatting that is deterministic.
- Nil-guards and trivial branching.
- Returning `(value, ok)` / `(changed bool)` patterns.

- **Typical helper shapes (examples)**:
- `HasX() bool`, `GetX() (T, bool)`, `SetX(v T) (changed bool)`, `ClearX() (changed bool)`
- `IsXEqual(...) bool`, `XEquals(...) bool`
- `ParseX(string) X` / `FormatX(...) string` (no I/O, no time, no external lookups)

## What MUST NOT be in `*_types.go` (MUST NOT)

If any of these are present, the code belongs in `*_custom_logic_that_should_not_be_here.go`.

- **Business / orchestration logic**:
- Decisions that interpret cluster state, desired/actual reconciliation, phase machines, progress tracking.
- Anything that “synchronizes” different parts of an object (spec ↔ status, spec ↔ labels/annotations, cross-object references).

- **Conditions/status mutation logic**:
- Creating/updating `metav1.Condition` / using `meta.SetStatusCondition` / computing reason/message based on multi-step state.
- Anything that sets `.status.phase`, `.status.reason`, counters, aggregates, etc. based on logic.

- **Controller/Kubernetes integration**:
- `controllerutil.SetControllerReference`, finalizer management with external expectations, scheme usage.
- Any reads/writes via API clients (even if “simple”).

- **I/O and side effects**:
- File/network access, exec/shell, OS calls, time-based logic (`time.Now`, `time.Since`), randomness.

- **Non-trivial control flow**:
- Complex `if/switch` trees, multi-branch logic tied to domain semantics.
- Loops that encode placement/selection/scheduling decisions.

## Kubebuilder generation hygiene for non-API types (MUST)

- **Non-Kubernetes API types** (MUST):
- Avoid placing non-API types (e.g. `error` implementations, internal helper structs) in `api/` packages.
- If a non-API type must live in `api/` (for locality/type-safety), it MUST be explicitly excluded from kubebuilder object/deepcopy generation:
- Add `// +kubebuilder:object:generate=false` on the type.
- Rationale: `controller-gen object` may generate DeepCopy methods for any struct type in the API package, which pollutes `zz_generated.deepcopy.go` with irrelevant helpers/errors.
Loading
Loading