ERA-60185 : Add ConfigMap defaults support for Database CR#208
ERA-60185 : Add ConfigMap defaults support for Database CR#208sasikanthmasini wants to merge 6 commits intomainfrom
Conversation
Allow developers to specify minimal inputs in Database CR with admin-provided defaults via ConfigMap. Values in CR take precedence over ConfigMap defaults.
…ecified This commit adds the critical logic to skip validation for fields that can be provided via ConfigMap defaults (cluster, size, profiles, timeMachine). Key changes: - Webhook detects when defaultsConfigMapRef is set - Passes hasDefaultsConfigMap flag to validation handlers - Validation handlers skip cluster/size/TM checks when ConfigMap ref is present - Allows minimal Database CRs to pass validation successfully Tested: Successfully provisioned databases using minimal CRs with ConfigMap defaults.
…iles - Add postgres.profiles.dbParam.name for PostgreSQL-specific defaults - Add mysql.profiles.dbParam.name for MySQL-specific defaults - Add MySQL-specific example section in ConfigMap - Clarify that dbParam profiles should be database-type-specific
- Updated webhook validation to allow omitting both snapshotId and snapshotName when defaultsConfigMapRef is set - Added automatic selection of latest snapshot when both snapshot fields are empty - Implemented GetLatestSnapshotForTM() in ndb_api to fetch most recent snapshot by timestamp - Updated README with documentation on auto-snapshot feature Testing: Verified with PostgreSQL and MySQL clones, backward compatibility maintained
Changes: - Removed ConfigMap requirement for auto-snapshot feature - Auto-snapshot now works when both snapshotId and snapshotName are omitted - Updated webhook validation: removed hasDefaultsConfigMap check - Updated test: changed from expecting error to expecting success - Updated documentation: clarified auto-snapshot works in any scenario This makes features orthogonal: - ConfigMap defaults = provide default configuration values - Auto-snapshot = automatically select latest snapshot Benefits: - Better UX: no need for ConfigMap just to get auto-snapshot - More flexible: supports common "clone latest" use case - Simpler mental model: omit snapshot = latest Testing: - All 7 webhook validation scenarios pass - Auto-snapshot works without ConfigMap (new behavior) - Backward compatibility maintained - ConfigMap + auto-snapshot still works
shivaprasadmb
left a comment
There was a problem hiding this comment.
few suggesions:
-
Document all supported ConfigMap keys
README already has a good example. Adding a short “Supported keys” subsection (e.g. clusterName, size, timezone, profiles., timeMachine., type-specific keys like postgres.size) would help admins. -
Validation after applying defaults
Optional: after ApplyDefaultsToDatabase, run a quick check (e.g. for provisioning: cluster set, size >= 10, required TM fields) and emit a clear event or set a condition if something required is still missing, so “ConfigMap missing required key” is easier to diagnose. -
ConfigMap namespace
Restricting the ConfigMap to the Database’s namespace is simple and consistent with RBAC. If you ever need cross-namespace defaults, you could add an optional defaultsConfigMapNamespace (or a small struct ref) later; not necessary for the current design.
ConfigMap Defaults for Database Resources
Overview
Enables administrators to pre-configure default database settings in a Kubernetes ConfigMap, allowing developers to create Database CRs with minimal required inputs. The operator automatically resolves missing values from the referenced ConfigMap.
Why?
Key Changes
API Changes (
api/v1alpha1/database_types.go)defaultsConfigMapReffield toDatabaseSpecclusterName,sourceDatabaseName,snapshotNamefields for name-based resolutionomitemptyto support both UUID and name-based workflowsConfigMap Defaults (
controller_adapters/configmap_defaults.go)postgres.profiles.dbParam.name) and generic keysAuto-Snapshot Selection (
controller_adapters/name_resolution.go&ndb_api/snapshots.go)snapshotIdandsnapshotNameare omitted during cloningGetLatestSnapshotForTM()to fetch most recent snapshot by timestampWebhook Validation (
api/v1alpha1/webhook_helpers.go)clusterId,timezone, and snapshot fields whendefaultsConfigMapRefis presentsnapshotIdandsnapshotNameempty) with ConfigMapRBAC (
config/rbac/)ConfigMap Structure Used
Example Usage
ConfigMap with Defaults
Minimal Database CR (Provisioning)
Minimal Clone CR (Auto-snapshot)
Testing
Test Coverage: 20/20 Tests Passed
Cloning with auto-snapshot, explicit name, and explicit ID
Webhook validation for non-ConfigMap CRs
Verified with size, timezone, and profile overrides
Invalid source DB, invalid snapshot, Time Machine not ready
Key Validations
Breaking Changes
None. This feature is fully backward compatible. Existing Database CRs without
defaultsConfigMapRefcontinue to work unchanged.Documentation
README.mdwith ConfigMap usage examples and auto-snapshot documentationTesting Summary and Logs
1. Functionality Testing
1.1 PostgreSQL Provisioning with ConfigMap Defaults
Test File:
test-pgsi-1.yamlMinimal CR:
ConfigMap Defaults Applied:
auto_cluster_nested_697cec1c92fce9da8fbb8668UTCPOSTGRES_14.13_OOBDEFAULT_OOB_POSTGRESQL_NETWORKDEFAULT_POSTGRES_PARAMSDEFAULT_OOB_COMPUTE10 GBDEFAULT_OOB_BRASS_SLAOperator Logs:
Result: Database
pgsi-1successfully created on NDB with all defaults properly applied.1.2 MySQL Provisioning with ConfigMap Defaults
Test File:
test-mysql-1.yamlMinimal CR:
ConfigMap Defaults Applied:
MYSQL_8.0.37_OOBDEFAULT_OOB_MYSQL_NETWORKDEFAULT_MYSQL_PARAMSOperator Logs:
Result: Database
mysql-1successfully created with database-specific MySQL profiles.1.3 Cloning with Auto-Snapshot Selection
Test File:
test-clone-pgsi-auto-snapshot.yamlMinimal Clone CR (no snapshot specified):
Operator Logs:
Result: Clone successfully created using auto-selected latest snapshot.
1.4 Cloning with Explicit Snapshot Name
Test File:
test-clone-pgsi-with-name.yamlOperator Logs:
Result: Clone created successfully using explicit snapshot name.
1.5 Cloning with Explicit Snapshot ID
Test File:
test-clone-pgsi-with-id.yamlResult: Clone created successfully using explicit snapshot UUID (no name resolution needed).
2. Backward Compatibility Testing
2.1 Provisioning WITHOUT ConfigMap (Traditional Flow)
Test File:
test-pgsi-2-backward-compat.yamlTraditional CR (no ConfigMap reference):
Result: Database
pgsi-2successfully created. Traditional provisioning flow works unchanged.Verification:
2.2 Cloning WITHOUT ConfigMap (Traditional Flow)
Test File:
test-clone-pgsi-1-backward-compat.yamlTraditional Clone CR:
Result: Clone
clone-pgsi-1-noconfigsuccessfully created. Traditional cloning flow works unchanged.2.3 Webhook Validation for Traditional Flow
Webhook Behavior:
defaultsConfigMapRefis NOT present, webhook enforces strict validationclusterId(orclusterName),timezone, profiles, size, etc.snapshotIdorsnapshotNamemust be provided for cloningTest: Created CR without ConfigMap and without required fields
Webhook Response:
Result: Webhook correctly enforces validation when ConfigMap is not used.
3. Override Behavior Testing
3.1 Provisioning with Overrides
Test File:
test-pgsi-3-override.yamlCR with Overrides:
Operator Logs (NDB API request):
{ "databaseServer": { "name": "pgsi-3", "newDbServerTimeZone": "Asia/Kolkata" }, "createDbserver": true, "nodeCount": 1, "nodes": [{ "properties": [{ "name": "listener_port", "value": "5432" }], "vmName": "pgsi-3" }], "databaseParameterProfileId": "24fb5e63-b3d3-418e-b27d-d2bc4a572be9", "dbserverId": "", "timeMachineInfo": { "name": "pgsi-3_TM", "slaId": "16f89219-a307-4470-9b79-7f7853a4edb6" }, "actionArguments": [{ "name": "vm_name", "value": "pgsi-3" }, { "name": "working_dir", "value": "/tmp" }, { "name": "dbserver_description", "value": "pgsi-3" }, { "name": "db_password", "value": "***" }, { "name": "db_size", "value": "20" # Override applied }] }Verification:
size: "10"andtimezone: "UTC"size: 20andtimezone: "Asia/Kolkata"20and"Asia/Kolkata"in NDB requestResult: Explicit CR values correctly override ConfigMap defaults.
3.2 Cloning with Overrides
Test File:
test-pgsi-3-cloning-override.yamlCR with Override:
Operator Logs (NDB API request):
{ "name": "pgsi-3-cloning", "createDbserver": true, "clustered": false, "nxClusterId": "697cec1c-92fc-e9da-8fbb-8668b54a1639", "sshPublicKey": "ssh-rsa ...", "dbserverId": "", "dbserverClusterId": "", "dbserverLogicalClusterId": "", "timeMachineId": "e9e70cbf-8a42-4059-8298-be9126004e69", "snapshotId": "db842c71-1ca3-4a5f-9ab5-c66c3644436b", "userPitrTimestamp": "", "timeZone": "Europe/London", # Override applied "latestSnapshot": false }Result: Explicit timezone in clone CR overrides ConfigMap default.
4. Edge Cases and Error Handling
4.1 Non-existent ConfigMap ❌ → Handled
Test: Reference a ConfigMap that doesn't exist
Events:
Result: Error properly detected and reported via Kubernetes event.
4.2 Empty ConfigMap → Handled
Test: ConfigMap exists but has
data: {}Events:
Result: Operator attempts to generate request, but NDB rejects due to missing required fields. Error properly reported.
4.3 Invalid Profile Names → Handled
Test: ConfigMap has
postgres.profiles.software.name: "THIS_PROFILE_DOES_NOT_EXIST"Events:
Result: Profile resolution fails with clear error message indicating which profile name is invalid.
4.4 Invalid Source Database Name → Handled
Test: Clone CR with
sourceDatabaseName: "this-database-does-not-exist"Events:
Result: Name resolution properly detects missing database with clear error.
4.5 Invalid Snapshot Name → Handled
Test: Clone CR with
snapshotName: "this-snapshot-does-not-exist"Events:
Result: Snapshot name resolution checks time machine and reports which snapshot name is invalid.
4.6 Time Machine Not Ready → Handled
Test: Clone from database whose Time Machine is in
NOT_YET_ACTIVATEDstate (no snapshots available)Events:
Result: Operator forwards detailed NDB error message explaining Time Machine state.
4.7 Webhook Relaxed Validation
Test: Create minimal CR with ConfigMap reference but missing
clusterId,timezone,snapshotIdWebhook Logs:
Result: CR passes webhook validation. Fields will be resolved from ConfigMap during reconciliation.
Key Validations
ConfigMap Integration: Operator successfully reads and applies ConfigMap defaults
Database-specific Profiles: PostgreSQL and MySQL use correct database-specific profiles
Name Resolution: Cluster, database, and snapshot names resolve to UUIDs correctly
Auto-snapshot Selection: Latest snapshot automatically selected when both ID and name omitted
Override Mechanism: Explicit CR values override ConfigMap defaults
Backward Compatibility: Traditional flows (without ConfigMap) work unchanged
Webhook Validation: Relaxes validation when ConfigMap referenced, strict otherwise
Error Handling: All errors detected and reported via Kubernetes events with clear messages
RBAC: Operator has correct permissions to read ConfigMaps