Skip to content

Commit f094803

Browse files
authored
fix(psql): preserve false durability status (#81)
* fix(psql): preserve false status durability * test(psql): cover false status patch persistence
1 parent 8e76eec commit f094803

16 files changed

Lines changed: 387 additions & 33 deletions

File tree

api/psql/v1beta1/dbsystem_types.go

Lines changed: 21 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/psql/v1beta1/zz_generated.deepcopy.go

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/psql.oracle.com_dbsystems.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,8 @@ spec:
661661
type: string
662662
type: object
663663
storageDetails:
664-
description: DbSystemStorageDetails defines nested fields for DbSystem.StorageDetails.
664+
description: DbSystemStorageDetailsObservedState defines nested fields
665+
for DbSystem.StorageDetails.
665666
properties:
666667
availabilityDomain:
667668
description: |-

docs/api-generator-contract.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Each service record defines:
3131
| `formalSpec` | Optional controller slug from `formal/controller_manifest.tsv` when one formal row covers the service-level runtime contract. |
3232
| `observedState.sdkAliases` | Optional observed-state SDK struct aliases keyed by the discovered SDK resource family when status synthesis must read a differently named response model. |
3333
| `observedState.excludedFieldPaths` | Optional dot-separated observed-state field paths keyed by the discovered SDK resource family when sensitive or unsupported SDK fields must be omitted from generated status surfaces. |
34+
| `observedState.requiredPointerFieldPaths` | Optional dot-separated observed-state field paths keyed by the discovered SDK resource family that must retain value presence in generated status while remaining required in the CRD schema. |
3435
| `generation.controller.strategy` | Service-wide controller rollout: `none`, `manual`, or `generated`. |
3536
| `generation.serviceManager.strategy` | Service-wide service-manager rollout: `none`, `manual`, or `generated`. |
3637
| `generation.registration.strategy` | Group-level runtime registration rollout: `none`, `manual`, or `generated`. |

docs/guides/psql/dbsystem.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ This summary shows the top-level `status` fields. Use [the full API reference](.
8383
| `shape` | The name of the shape for the database instance. Example: `VM.Standard.E4.Flex` | `string` | No |
8484
| [`source`](../../reference/api/psql/v1beta1/index.md#kind-dbsystem-status-source) | DbSystemSource defines nested fields for DbSystem.Source. | `object` | No |
8585
| [`status`](../../reference/api/psql/v1beta1/index.md#kind-dbsystem-status-status) | - | `object` | Yes |
86-
| [`storageDetails`](../../reference/api/psql/v1beta1/index.md#kind-dbsystem-status-storagedetails) | DbSystemStorageDetails defines nested fields for DbSystem.StorageDetails. | `object` | No |
86+
| [`storageDetails`](../../reference/api/psql/v1beta1/index.md#kind-dbsystem-status-storagedetails) | DbSystemStorageDetailsObservedState defines nested fields for DbSystem.StorageDetails. | `object` | No |
8787
| `systemTags` | System tags for this resource. Each key is predefined and scoped to a namespace. Example: `{"orcl-cloud": {"free-tier-retained": "true"}}` | `map[string, map[string, string]]` | No |
8888
| `systemType` | Type of the database system. | `string` | No |
8989
| `timeCreated` | The date and time that the database system was created, expressed in RFC 3339 (https://tools.ietf.org/rfc/rfc3339) timestamp format. Example: `2016-08-25T21:10:29.600Z` | `string` | No |

docs/reference/api/psql/v1beta1/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ DbSystemStatus defines the observed state of DbSystem.
268268
| `shape` | The name of the shape for the database instance. Example: `VM.Standard.E4.Flex` | `string` | No | - | - |
269269
| [`source`](#kind-dbsystem-status-source) | DbSystemSource defines nested fields for DbSystem.Source. | `object` | No | - | - |
270270
| [`status`](#kind-dbsystem-status-status) | - | `object` | Yes | - | - |
271-
| [`storageDetails`](#kind-dbsystem-status-storagedetails) | DbSystemStorageDetails defines nested fields for DbSystem.StorageDetails. | `object` | No | - | - |
271+
| [`storageDetails`](#kind-dbsystem-status-storagedetails) | DbSystemStorageDetailsObservedState defines nested fields for DbSystem.StorageDetails. | `object` | No | - | - |
272272
| `systemTags` | System tags for this resource. Each key is predefined and scoped to a namespace. Example: `{"orcl-cloud": {"free-tier-retained": "true"}}` | `map[string, map[string, string]]` | No | - | - |
273273
| `systemType` | Type of the database system. | `string` | No | - | - |
274274
| `timeCreated` | The date and time that the database system was created, expressed in RFC 3339 (https://tools.ietf.org/rfc/rfc3339) timestamp format. Example: `2016-08-25T21:10:29.600Z` | `string` | No | - | - |
@@ -466,7 +466,7 @@ Async is the canonical controller-owned async contract. Resource-local legacy wo
466466

467467
[Back to DbSystem status](#kind-dbsystem-status)
468468

469-
DbSystemStorageDetails defines nested fields for DbSystem.StorageDetails.
469+
DbSystemStorageDetailsObservedState defines nested fields for DbSystem.StorageDetails.
470470

471471
| Field | Description | Type | Required | Default | Enum |
472472
| --- | --- | --- | --- | --- | --- |

internal/generator/config.go

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,9 @@ type ServiceConfig struct {
181181

182182
// ObservedStateConfig tunes how read-model fields are synthesized into status types.
183183
type ObservedStateConfig struct {
184-
SDKAliases map[string][]string `yaml:"sdkAliases,omitempty"`
185-
ExcludedFieldPaths map[string][]string `yaml:"excludedFieldPaths,omitempty"`
184+
SDKAliases map[string][]string `yaml:"sdkAliases,omitempty"`
185+
ExcludedFieldPaths map[string][]string `yaml:"excludedFieldPaths,omitempty"`
186+
RequiredPointerFieldPaths map[string][]string `yaml:"requiredPointerFieldPaths,omitempty"`
186187
}
187188

188189
// LoadConfig reads and validates the generator config file.
@@ -315,7 +316,10 @@ func validateObservedStateConfig(service ServiceConfig) error {
315316
if err := validateObservedStateAliases(service); err != nil {
316317
return err
317318
}
318-
return validateObservedStateExcludedFieldPaths(service)
319+
if err := validateObservedStateExcludedFieldPaths(service); err != nil {
320+
return err
321+
}
322+
return validateObservedStateRequiredPointerFieldPaths(service)
319323
}
320324

321325
func validateObservedStateAliases(service ServiceConfig) error {
@@ -351,6 +355,25 @@ func validateObservedStateExcludedFieldPaths(service ServiceConfig) error {
351355
return nil
352356
}
353357

358+
func validateObservedStateRequiredPointerFieldPaths(service ServiceConfig) error {
359+
for rawName, paths := range service.ObservedState.RequiredPointerFieldPaths {
360+
if strings.TrimSpace(rawName) == "" {
361+
return fmt.Errorf("service %q observedState requiredPointerFieldPaths contains a blank resource name", service.Service)
362+
}
363+
for _, fieldPath := range paths {
364+
if _, err := normalizeObservedStateFieldPath(fieldPath); err != nil {
365+
return fmt.Errorf(
366+
"service %q observedState requiredPointerFieldPaths[%q] %w",
367+
service.Service,
368+
rawName,
369+
err,
370+
)
371+
}
372+
}
373+
}
374+
return nil
375+
}
376+
354377
func validateUniqueServiceKeys(
355378
service ServiceConfig,
356379
servicesByName map[string]struct{},
@@ -1413,6 +1436,33 @@ func (s ServiceConfig) ObservedStateExcludedFieldPaths(rawName string) map[strin
14131436
return paths
14141437
}
14151438

1439+
// ObservedStateRequiredPointerFieldPaths returns observed-state fields that must retain
1440+
// presence information while remaining required in the generated status schema.
1441+
func (s ServiceConfig) ObservedStateRequiredPointerFieldPaths(rawName string) map[string]struct{} {
1442+
rawName = strings.TrimSpace(rawName)
1443+
if rawName == "" {
1444+
return nil
1445+
}
1446+
1447+
configured := s.ObservedState.RequiredPointerFieldPaths[rawName]
1448+
if len(configured) == 0 {
1449+
return nil
1450+
}
1451+
1452+
paths := make(map[string]struct{}, len(configured))
1453+
for _, path := range configured {
1454+
normalized, err := normalizeObservedStateFieldPath(path)
1455+
if err != nil {
1456+
continue
1457+
}
1458+
paths[normalized] = struct{}{}
1459+
}
1460+
if len(paths) == 0 {
1461+
return nil
1462+
}
1463+
return paths
1464+
}
1465+
14161466
func normalizeObservedStateFieldPath(path string) (string, error) {
14171467
path = strings.TrimSpace(path)
14181468
if path == "" {

internal/generator/config/services.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6814,6 +6814,9 @@ services:
68146814
- PrimaryDbInstanceDetails
68156815
WorkRequestLog:
68166816
- WorkRequestLogEntry
6817+
requiredPointerFieldPaths:
6818+
DbSystem:
6819+
- StorageDetails.IsRegionallyDurable
68176820

68186821
- service: queue
68196822
sdkPackage: github.com/oracle/oci-go-sdk/v65/queue

internal/generator/config_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3627,6 +3627,30 @@ func TestObservedStateExcludedFieldPaths(t *testing.T) {
36273627
}
36283628
}
36293629

3630+
func TestObservedStateRequiredPointerFieldPaths(t *testing.T) {
3631+
t.Parallel()
3632+
3633+
service := ServiceConfig{
3634+
ObservedState: ObservedStateConfig{
3635+
RequiredPointerFieldPaths: map[string][]string{
3636+
"DbSystem": {"StorageDetails.IsRegionallyDurable", " storageDetails.isRegionallyDurable "},
3637+
},
3638+
},
3639+
}
3640+
3641+
got := service.ObservedStateRequiredPointerFieldPaths("DbSystem")
3642+
wantKey, err := normalizeObservedStateFieldPath("StorageDetails.IsRegionallyDurable")
3643+
if err != nil {
3644+
t.Fatalf("normalizeObservedStateFieldPath() error = %v", err)
3645+
}
3646+
if len(got) != 1 {
3647+
t.Fatalf("ObservedStateRequiredPointerFieldPaths() returned %d entries, want 1", len(got))
3648+
}
3649+
if _, ok := got[wantKey]; !ok {
3650+
t.Fatalf("ObservedStateRequiredPointerFieldPaths() = %v, want %q", got, wantKey)
3651+
}
3652+
}
3653+
36303654
func TestCheckedInConfigExcludesMySQLDbSystemSourceURLFromObservedState(t *testing.T) {
36313655
t.Parallel()
36323656

internal/generator/discovery.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ type fieldRenderingOptions struct {
722722
scope fieldScope
723723
escapeStatusJSONCollision bool
724724
excludedFieldPaths map[string]struct{}
725+
requiredPointerFieldPaths map[string]struct{}
725726
}
726727

727728
func buildFieldModel(field ocisdk.Field, jsonName string, options fieldRenderingOptions) FieldModel {

0 commit comments

Comments
 (0)