Skip to content

enhance metrics part for resources - #3

Merged
NitinKumar004 merged 1 commit into
developmentfrom
fix/extend_metrics
Mar 1, 2026
Merged

enhance metrics part for resources#3
NitinKumar004 merged 1 commit into
developmentfrom
fix/extend_metrics

Conversation

@NitinKumar004

Copy link
Copy Markdown
Collaborator

No description provided.

@NitinKumar004
NitinKumar004 merged commit 9a3449e into development Mar 1, 2026
@NitinKumar004
NitinKumar004 deleted the fix/extend_metrics branch April 30, 2026 18:17
thzgajendra added a commit to thzgajendra/cloudemu that referenced this pull request Jul 29, 2026
…nforcement

Addresses the remaining LOW review items:

- Read-side slice aliasing (LOW stackshy#1): Describe paths now copy their slice/map
  fields so a returned value never aliases the store — DescribeDBProxies
  (Targets/Auth/subnets/SGs), DescribeGlobalClusters (Members),
  DescribeDBClusterEndpoints (Static/Excluded), DescribeEventSubscriptions
  (SourceIDs/EventCategories), DescribeOptionGroups (Options), and the
  parameter-group Parameters maps. Adds a generic cloneSlice helper; consistent
  with the tags copy-on-read.
- Parameter/option-group in-use enforcement (LOW stackshy#2): instances now carry
  DBParameterGroupName/OptionGroupName and clusters DBClusterParameterGroupName
  (parsed from the wire). Delete{,Cluster}ParameterGroup and DeleteOptionGroup
  refuse an in-use group (FailedPrecondition) and refuse the reserved
  default.* / default:* names.

Not changed: conformance guards for ClusterEndpoints/ClusterFailover/
GlobalClusters/Metadata/Tagging already exist (var _ blocks in aurora.go /
metadata.go) — the review's stackshy#3 was a false alarm. Remaining LOW fidelity nits
(proxy RoleArn/Auth validation, global secondary attach, metric backfill, etc.)
stay as documented follow-ups.

New tests: parameter/option-group delete guards (in-use + default), copy-on-read
regression. build/vet/gofmt/full test + -race green; golangci-lint clean.
thzgajendra added a commit that referenced this pull request Jul 29, 2026
* feat(rds): DB and DB cluster parameter groups

Add parameter-group support to the RDS emulation as an optional
ParameterGroups capability (mirroring the SubnetGroups pattern): create,
describe, modify, delete, describe-parameters, reset, and copy — for both
DB parameter groups and DB cluster parameter groups (14 actions).

Only user-set parameters are modeled; the emulator does not fabricate the
hundreds of engine defaults real AWS returns. Real AWS reuses the
DBParameterGroup fault codes for the cluster variants, so error mapping is
shared via a 'parameter group' message keyword.

Covered by provider unit tests and aws-sdk-go-v2 SDK round-trip tests.

* feat(rds): option groups

Add option-group support as an optional OptionGroups capability: create,
describe (with engine-name filter), modify (include/remove options), delete,
copy, and describe-option-group-options (6 actions).

DescribeOptionGroupOptions returns a small, representative per-engine catalog
of well-known option names rather than fabricating AWS's exhaustive
version-specific list. Covered by provider unit tests and SDK round-trip
tests.

* feat(rds): read replicas

Add CreateDBInstanceReadReplica and PromoteReadReplica as an optional
ReadReplicas capability. A replica inherits its source's engine, version and
storage; the source tracks its replica identifiers and the replica records its
source. Promotion detaches the replica (clears its source, removes it from the
source's list). Instance XML now carries ReadReplicaSourceDBInstanceIdentifier
and ReadReplicaDBInstanceIdentifiers.

Covered by provider unit tests and SDK round-trip tests.

* feat(rds): copy snapshot and point-in-time restore

Add an optional AdvancedRestore capability: CopyDBSnapshot,
CopyDBClusterSnapshot, RestoreDBInstanceToPointInTime, and
RestoreDBClusterToPointInTime (4 actions). Copies clone the source
snapshot's engine/version/storage under a new identifier; PITR clones the
source instance/cluster's current spec into a new resource.

The emulator has no historical timeline, so a point-in-time restore reflects
the source as it is now; RestoreTime/UseLatestRestorableTime are accepted but
not replayed. Covered by provider unit tests and SDK round-trip tests.

* feat(rds): RDS Proxy

Add RDS Proxy as an optional DBProxies capability: create, describe, modify,
delete proxies; register/deregister targets; describe targets and target
groups (8 actions). A proxy has a single implicit 'default' target group;
targets may be RDS instances (RDS_INSTANCE) or clusters (TRACKED_CLUSTER),
validated against existing resources on registration.

Covered by provider unit tests and SDK round-trip tests.

* feat(rds): event subscriptions, events, event categories

Add an optional EventSubscriptions capability: create/describe/modify/delete
event subscriptions, DescribeEvents, and DescribeEventCategories (6 actions).
Enabled defaults to true on create (matching AWS). DescribeEventCategories
returns AWS's published per-source-type categories.

DescribeEvents returns an empty list by design: the emulator retains no event
timeline, so there are truthfully no events for any window. Covered by
provider unit tests and SDK round-trip tests.

* feat(rds): Aurora custom endpoints, failover, and global clusters

Add three optional Aurora capabilities (10 actions):
- ClusterEndpoints: create/describe/modify/delete custom cluster endpoints.
- ClusterFailover: FailoverDBCluster promotes the target member to writer
  (or rotates the first reader when no target is given).
- GlobalClusters: create (optionally adopting a source cluster as writer),
  describe, modify (rename / engine version), delete, and remove-from.

Covered by provider unit tests and SDK round-trip tests.

* feat(rds): engine-version/orderable-option metadata and resource tagging

Add two optional capabilities (5 actions):
- Metadata: DescribeDBEngineVersions and DescribeOrderableDBInstanceOptions,
  backed by representative per-engine version and instance-class catalogs.
- Tagging: AddTagsToResource, RemoveTagsFromResource, ListTagsForResource,
  addressed by resource ARN over the tag-bearing stores (instances, clusters,
  and instance/cluster snapshots).

Covered by provider unit tests and SDK round-trip tests.

* feat(discovery): surface RDS/Aurora in Resource Explorer (AWS)

Issue #295 workstream A: RDS instances, Aurora clusters, and snapshots are
emulated but were never enumerable via Resource Explorer. Add a
RelationalDatabases discovery capability + neutral DiscoveredDatabase
projection, a walkRelationalDB walker, and an rdsDiscovery adapter in the AWS
provider (mirroring the Kubernetes eksDiscovery pattern, keeping services/
free of provider imports).

Map rds<->relationaldb in the Resource Explorer 2 filter/handler so
'service:rds' narrows to these resources and their ResourceType/Service render
correctly. Covered by an SDK indexing round-trip test.

GCP Cloud SQL / Azure SQL discovery are deliberately out of scope here.

* feat(rds): cost-tracker rates and enriched CloudWatch metrics

Add relationaldb operation rates to the cost Tracker's rate catalog
(instances and read replicas per instance-hour, RDS Proxy per hour; snapshots
and Aurora cluster grouping free), consistent with how the other services
populate the catalog.

Enrich instance metric emission with FreeStorageSpace, ReadLatency,
WriteLatency, and Network{Receive,Transmit}Throughput alongside the existing
CPU/connections/memory/IOPS series; latency and throughput read zero when the
instance is stopped. Covered by cost and metrics tests.

* chore(rds): lint sweep + discovery cleanup

Drop the write-only DiscoveredDatabase.Engine field; refactor the RDS
error-code switches into ordered keyword->fault tables (keeps them under the
gocyclo gate); wrap long signatures, fix cuddling/var-naming/receiver/goconst,
and annotate the intentional per-resource duplication. Full build/vet/gofmt
and the whole test suite pass; golangci-lint clean on the touched packages.

* docs(rds): document new RDS capabilities and discovery surfacing

Update services.md section 17 with the 11 new optional capability interfaces
and their operations (parameter/option groups, read replicas, snapshot
copy/PITR, RDS Proxy, event subscriptions, Aurora endpoints/failover/global
clusters, metadata, tagging), refresh the totals, and note AWS RDS discovery
through Resource Explorer 2 in section 19 (and features.md).

* fix(rds): review — concurrency, delete guards, slice aliasing

Address PR review (both HIGH + the MEDIUM aliasing set):

HIGH
- Concurrent-map-write panic on Tags/Parameters: copy-on-read in the Describe
  paths (instances/clusters/snapshots tags; parameter groups) and
  replace-on-write in the mutators (AddTags/RemoveTags build a fresh map;
  parameter Modify/Reset build a fresh map), mirroring ModifyInstance. Add a
  go test -race concurrency test (Describe + caller iteration vs tag/param
  writes).
- DeleteInstance now refuses (FailedPrecondition) while the instance still has
  read replicas.

MEDIUM
- DeleteInstance strips a deleted replica from its source's target list; make
  removeString non-mutating so it never corrupts a slice a Describe handed out.
- DeleteGlobalCluster refuses while members remain.
- Fresh-slice rebuilds (no in-place [:0]/append into aliased backing arrays) in
  DeregisterDBProxyTargets, RegisterDBProxyTargets, RemoveFromGlobalCluster,
  ModifyOptionGroup.
- DeleteDBSubnetGroup takes m.mu across the in-use scan + delete.
- Preserve per-parameter ApplyMethod (store map[string]Parameter).

LOW
- Deterministic tag XML ordering; DescribeEventCategories/PITR return copied
  slices; PITR clears ClusterID; SubnetGroups conformance guard; subnet-group
  ARN via idgen.

New tests: -race concurrency; delete-blocked-by-replica; delete-global-with-
members; ApplyMethod round-trip.

* fix(rds): review LOW — read-side slice copies + param/option in-use enforcement

Addresses the remaining LOW review items:

- Read-side slice aliasing (LOW #1): Describe paths now copy their slice/map
  fields so a returned value never aliases the store — DescribeDBProxies
  (Targets/Auth/subnets/SGs), DescribeGlobalClusters (Members),
  DescribeDBClusterEndpoints (Static/Excluded), DescribeEventSubscriptions
  (SourceIDs/EventCategories), DescribeOptionGroups (Options), and the
  parameter-group Parameters maps. Adds a generic cloneSlice helper; consistent
  with the tags copy-on-read.
- Parameter/option-group in-use enforcement (LOW #2): instances now carry
  DBParameterGroupName/OptionGroupName and clusters DBClusterParameterGroupName
  (parsed from the wire). Delete{,Cluster}ParameterGroup and DeleteOptionGroup
  refuse an in-use group (FailedPrecondition) and refuse the reserved
  default.* / default:* names.

Not changed: conformance guards for ClusterEndpoints/ClusterFailover/
GlobalClusters/Metadata/Tagging already exist (var _ blocks in aurora.go /
metadata.go) — the review's #3 was a false alarm. Remaining LOW fidelity nits
(proxy RoleArn/Auth validation, global secondary attach, metric backfill, etc.)
stay as documented follow-ups.

New tests: parameter/option-group delete guards (in-use + default), copy-on-read
regression. build/vet/gofmt/full test + -race green; golangci-lint clean.

* fix(rds): review — Modify can re-point/release param & option groups

Addresses the re-review of the LOW-fix commit.

MEDIUM — the new in-use enforcement could strand a group: a group attached
at Create could only be released by deleting the instance/cluster. Add
DBParameterGroupName/OptionGroupName (instance) and DBClusterParameterGroupName
(cluster) to ModifyInstanceInput and wire the modify handlers, so re-pointing
an instance/cluster to a new group releases the old one (which then deletes).

LOW:
- Finish read-side copies: DescribeInstances (VPCSecurityGroups,
  ReadReplicaTargets), DescribeClusters (Members, VPCSecurityGroups), and
  DescribeDBSubnetGroups (SubnetIDs) now return independent copies too, so the
  'every Describe path copies its slice/map fields' contract actually holds.
- Create{,Cluster}ParameterGroup / CreateOptionGroup reject the reserved
  default. / default: prefixes so a user can't self-inflict an undeletable group.
- DescribeOptionGroups deep-copies Option.Settings (cloneSlice was shallow).

Tests: Modify re-point/release for instance param, cluster param, and option
groups; reserved-name rejection on create; copy-on-read across the list-all and
named branches for proxies and instances.
thzgajendra added a commit to thzgajendra/cloudemu that referenced this pull request Jul 29, 2026
Address review MEDIUM stackshy#2/stackshy#3/stackshy#4 (Azure update paths) and stackshy#7 (MI discovery):

- PUT on an existing Azure SQL server / database / managed instance now applies
  the request body (upsert) instead of returning the stale record.
- PATCH is a genuine merge — elastic pools, failover groups and managed
  instances gain Update* capability methods that overlay only the fields the
  request supplied, so a partial PATCH no longer wipes unspecified fields; MI
  PATCH now decodes and applies its body instead of being a no-op.
- Managed instances are projected into cross-service discovery
  (microsoft.sql/managedinstances) via sqlDiscovery + the Resource Graph type
  map, so a created MI appears in inventory.

Covered by SDK PATCH-merge round-trip tests (elastic pool keeps its SKU when
only maxSizeBytes is patched; MI keeps administratorLogin when only vCores is
patched) and a managed-instance type-map test.
thzgajendra added a commit that referenced this pull request Jul 30, 2026
…xible Server, Cloud SQL) (#303)

* feat(azure): full parity for Azure MySQL Flexible Server sub-resources

Add databases, firewall rules and server configurations plus the server
failover action to Azure Database for MySQL Flexible Server, bringing it to
native parity with the ARM surface real armmysqlflexibleservers clients use.

Introduce Databases, FirewallRules, Configurations and Failover as optional
relationaldb driver capabilities (mirroring SubnetGroups), so the same
interfaces are reusable by the other managed-SQL services. The mock stores each
family per server and cascade-deletes children on server delete; the ARM handler
routes databases/firewallRules/configurations, updateConfigurations (batch) and
the failover action. Covered by real-SDK round-trip tests and mock-level
error-path/cascade tests.

* feat(azure): full parity for Azure PostgreSQL Flexible Server sub-resources

Add databases, firewall rules and server configurations to Azure Database for
PostgreSQL Flexible Server, reusing the Databases/FirewallRules/Configurations
optional relationaldb capabilities introduced for MySQL Flex. Postgres Flex has
no failover action and no batch-configuration endpoint, and its configuration
resource accepts both PUT and PATCH; the handler and mock reflect that. The mock
cascade-deletes children on server delete. Covered by real-SDK round-trip tests
(the SDK has no ClientFactory, so each client is built from shared options) plus
mock-level default/error/cascade tests.

* feat(azure): full parity for Azure SQL server sub-resources

Add firewall rules, virtual-network rules, elastic pools, failover groups and
the Azure AD administrator to Azure SQL (Microsoft.Sql). Firewall rules reuse
the shared FirewallRules capability; the other four are added as optional
relationaldb capabilities (VNetRules, ElasticPools, FailoverGroups, AADAdmins)
alongside the existing SubnetGroups pattern. Failover-group failover flips the
local replication role between Primary and Secondary. The mock cascade-deletes
all child resources on server delete and returns isolated copies of the
slice-bearing failover-group state. Covered by real-SDK (armsql) round-trip
tests across all five families plus mock-level error/cascade/aliasing tests.

* feat(gcp): full parity for Cloud SQL databases, users, certs and instance ops

Add databases (via the shared Databases capability), users and client SSL certs
as instance child resources, plus the clone, failover, promote-replica and
start/stop-replica instance actions to GCP Cloud SQL. Users and SSL certs are
new optional relationaldb capabilities (Users, SslCerts); clone and replica
promotion are Clonable and ReplicaPromotion; failover reuses the shared Failover
capability. The REST path parser now recognizes the databases/users/sslCerts
sub-collections, and the users route honors Cloud SQL's ?name= query quirk for
delete and update. The mock cascade-deletes children on instance delete. Tiers
and flags catalogs are intentionally out of scope (separate path shapes, static
data). Covered by real sqladmin SDK round-trip tests plus mock-level
clone/cascade/error tests.

* feat(discovery): surface managed SQL servers in Resource Graph and Cloud Asset

Add a RelationalDatabases discovery capability to the resource-discovery engine
and a walkRelationalDB walker, mirroring the Kubernetes adapter pattern. Azure
wires an adapter that projects Azure SQL logical servers plus MySQL/PostgreSQL
Flexible Servers, and GCP projects Cloud SQL instances, so managed relational
databases appear in cross-service inventory. Resource Graph maps the portable
types to microsoft.sql/servers, microsoft.dbformysql/flexibleservers and
microsoft.dbforpostgresql/flexibleservers; Cloud Asset maps Cloud SQL to
sqladmin.googleapis.com/Instance. Both type-map switches become lookup tables to
stay under the cyclomatic-complexity gate. Covered by walker and type-map tests.

* feat(cost): add managed relational-database rates

Add relationaldb:* entries to the cost rate catalog so provisioning a managed
database server/instance (RDS, Azure SQL, Azure MySQL/PostgreSQL Flexible
Server, Cloud SQL) is billed per instance-hour, clusters per cluster-hour, and
restores reuse the instance-hour, while snapshots and lifecycle actions are
free. The portable "relationaldb" service name means one catalog covers every
cloud. Covered by a cost-tracker test.

* docs: document full managed-SQL parity (sub-resources, discovery, cost)

Document the native sub-resource capabilities added to Azure SQL, the Azure
MySQL/PostgreSQL Flexible Servers and Cloud SQL — databases, users, firewall/
vnet rules, configurations, elastic pools, failover groups, AAD admins, SSL
certs, clone/failover/replica actions — along with their discovery surfacing and
cost rates. Refresh the relational-database operation totals and the discovery
driver list.

* feat(sql): Cloud SQL tiers/flags catalogs + elastic-pool metrics

Close the remaining managed-SQL parity gaps: serve the Cloud SQL machine-tier
catalog (GET /v1/projects/{p}/tiers) and the database-flag catalog
(GET /v1/flags, which is project-less) as static reference data, and emit
Microsoft.Sql/servers/elasticpools metrics (cpu/storage/workers percent) when an
Azure SQL elastic pool is created. Also annotate the ModifyInstance/ModifyCluster
methods across the four SQL mocks with the driver-interface hugeParam nolint now
that the shared ModifyInstanceInput grew. Covered by SDK tiers/flags round-trip
and an elastic-pool metric-emission test.

* feat(azure): add SQL Managed Instance family to Azure SQL

Add the Microsoft.Sql/managedInstances resource type and its managed databases
as a ManagedInstances optional relationaldb capability: managed-instance CRUD +
list + start/stop/failover actions, and managed-database CRUD + list. The
handler now matches the managedInstances resource type alongside servers and
routes both, and the mock cascade-deletes managed databases when their instance
is removed. Covered by an armsql managed-instance/database SDK round-trip test
(create → get → list → failover → cascade delete) and a mock-level lifecycle
test.

* docs: document managed instances, tiers/flags and elastic-pool metrics

Update the relational-database section for the now-complete managed-SQL parity:
add the ManagedInstances capability row, note Cloud SQL's tiers/flags reference
catalogs and Azure SQL's Managed Instance family, and record the elastic-pool
metric namespace. Refresh the optional-operation totals (25 capability
interfaces, +109 relational / +118 grand-total optional).

* fix(sql): clone ManagedInstance tags on read; deterministic list ordering

Address review MEDIUM #1 and the list-ordering LOW: GetManagedInstance /
ListManagedInstances now clone the stored Tags map so a caller mutating the
returned map can't corrupt the store (the copy-on-read hole flagged as the
concurrent-map panic class), and every List* mock method iterates
memstore.SortedValues() instead of All() for deterministic SDK list ordering,
matching the documented convention. Large-value list loops use index iteration
to avoid per-element copies.

* fix(azure): real update semantics + discoverable managed instances

Address review MEDIUM #2/#3/#4 (Azure update paths) and #7 (MI discovery):

- PUT on an existing Azure SQL server / database / managed instance now applies
  the request body (upsert) instead of returning the stale record.
- PATCH is a genuine merge — elastic pools, failover groups and managed
  instances gain Update* capability methods that overlay only the fields the
  request supplied, so a partial PATCH no longer wipes unspecified fields; MI
  PATCH now decodes and applies its body instead of being a no-op.
- Managed instances are projected into cross-service discovery
  (microsoft.sql/managedinstances) via sqlDiscovery + the Resource Graph type
  map, so a created MI appears in inventory.

Covered by SDK PATCH-merge round-trip tests (elastic pool keeps its SKU when
only maxSizeBytes is patched; MI keeps administratorLogin when only vCores is
patched) and a managed-instance type-map test.

* fix(azure): model Azure SQL database elastic-pool membership

Address review MEDIUM #5. Databases now carry an ElasticPoolID (added to the
shared InstanceConfig/Instance/ModifyInstanceInput and surfaced as the
elasticPoolId ARM database property), so an SDK client placing a database into a
pool round-trips instead of silently dropping it. DeleteElasticPool now returns
a precondition error while the pool still contains databases, matching real
Azure's 409. Covered by a membership/delete-guard test.

* fix(gcp): real Cloud SQL read-replica and failover semantics

Address review MEDIUM #6. A Cloud SQL insert with masterInstanceName now creates
an actual read replica: the replica records its master (ReadReplicaSource) and
the primary lists it (replicaNames), both surfaced in the instance body. Replica
lifecycle is faithful — start/stopReplica require the target to be a replica and
leave it RUNNABLE (no SUSPENDED state change); promoteReplica detaches it from
the primary (and rejects a non-replica); failover is a primary-only operation
and rejects a replica. Covered by SDK and mock replica-lifecycle tests.

* fix(sql): review LOW items — determinism, validation, replica fidelity tests

- Cloud SQL backup-run IDs are generated by the mock from the clock + a
  monotonic counter (was time.Now().UnixNano(), violating the Clock determinism
  rule and collision-prone); CloneInstance now clones the source's databases and
  resets replica linkage; UpdateUser doc corrected.
- Firewall rules validate IPv4 start/end (Azure SQL + both Flexible Servers);
  Azure SQL Managed Instance requires subnetId, as real Azure does.
- Added a real-SDK Resource Graph indexing test that drives sqlDiscovery
  end-to-end (logical server + managed instance appear and filter), and a
  -race concurrency test that mutates a returned managed-instance Tags map to
  pin the copy-on-read fix.

* fix(sql): address second review — MI lifecycle, in-place restore, validation

- Cloud SQL DeleteInstance now unlinks replica<->master before cascading
  children, so no dangling ReadReplicaSource/ReadReplicaTargets remain.
- Managed Instance lifecycle gains a state guard (transitionManagedInstance):
  Start/Stop respect current state, Failover requires Ready; MI create emits
  representative metrics and clones returned Tags; adds CreateManagedInstance
  cost rate.
- Cloud SQL RestoreBackup restores in place onto the existing instance via a
  new optional BackupRestorer capability (was create-new -> 409).
- Failover-group failover requires a partner server; firewall rules validate
  Start <= End; Azure Flex SetConfiguration rejects unknown params and empty
  values; ARM parser captures the action verb so forced vs planned failover
  and unknown POST verbs are distinguished; Cloud SQL selfLink/targetLink use
  the served /v1 prefix.
- Broaden new-package test coverage (sub-resource CRUD, MI lifecycle, Users
  update, backup get, error paths, server PATCH, raw MI start/stop).

* fix(sql): address third review — output aliasing, config catalog, validation

- Deep-copy Tags/slice fields on every Instance/Cluster/Snapshot return path in
  azuresql and cloudsql (Describe/Create/Modify/Restore/Clone), so a returned
  value never aliases the memstore — fixes a potential concurrent-map crash and
  matches the managedinstance/FailoverGroup discipline.
- Azure Flex GetConfiguration/ListConfigurations return catalog defaults for a
  known-but-unset parameter (real Azure behavior) instead of NotFound/empty; the
  catalog now maps names to defaults.
- MySQL Flex batch config update is atomic: all entries are validated before any
  is applied, via a new optional BatchConfigurations capability.
- Azure SQL database create/modify validates the referenced elastic pool exists
  (symmetry with the pool-delete member guard).
- Cloud SQL rejects child (database/user) names containing '/' that would orphan
  a row; get-paths add length guards on single-ID Describe lookups.
- Flex firewall create validates start <= end (parity with Azure SQL).
- Tests: aliasing, config defaults, batch atomicity, elastic-pool validation,
  child-name rejection, FG update/list, managed-database delete, and Azure
  wire-level error-mapping (404/400) across all three Azure SQL services.
NitinKumar004 added a commit that referenced this pull request Jul 30, 2026
…ocs)

From thzgajendra's review of PR #299:
- Lint (#1): replace the version-sensitive //nolint:prealloc directives with
  real preallocation (coreResources/appsResources/registryAPIResources,
  openapi kinds, endpoint-address slice), so golangci-lint is clean regardless
  of prealloc's version-dependent placement — no dangling directives.
- Docs (#2): drop the 'pagination' claim from the k8s data-plane sentence in
  sdk-server.md; data-plane lists are unpaginated, matching services.md.
- Watch load-shedding (#3): a slow watcher that overflows its buffer now
  receives a 410 Gone (ERROR) event and the stream ends, so client-go relists
  instead of running with a permanently-divergent cache. Regression test added.
- GC comment (#4): correct the 'never mutate while ranging' wording — deleting
  the current key mid-range is legal; the BFS is what makes the cascade
  order-independent.
- Provider package headers (#8): describe the now-wired data plane instead of
  'out of scope / Wave 2'.

Deferred as documented follow-ups (all Low): clamp/silent-signal, Job shrink
reconcile, committed kubectl smoke test, provider CA-vs-sentinel misconfig
window.
NitinKumar004 added a commit that referenced this pull request Jul 30, 2026
…upport (#299)

* feat(k8s): connect parity across EKS/AKS/GKE via a shared CA (Phase A)

The data-plane serving cert and every provider's advertised CA must be the
same authority or client-go's TLS handshake fails. Extract the CA into a new
internal/k8spki package used by both the serving TLS config and all three
control planes:

- EKS: tls.go now delegates to k8spki (serve + EKS call sites unchanged).
- GKE: advertise the real CA in masterAuth.clusterCaCertificate; drop the
  unparseable dummy blob that broke the handshake outright.
- AKS: embed the real CA in the rendered kubeconfig and drop
  insecure-skip-tls-verify — parity with EKS/GKE.

Tests: AKS data-plane test now serves with the k8spki cert and validates
end-to-end (no skip-verify); new GKE real-TLS connect-parity test proves the
advertised CA certifies the endpoint (create cluster -> validate CA ->
client-go ConfigMap round-trip). RenderKubeconfig test updated to the real-CA
behavior.

First phase of the k8s runtime/parity work; registry refactor + reconcile
engine + workload kinds follow on this branch.

* feat(k8s): parse resource subresources in the router (Phase B foundation)

Add Route.Subresource and parse the /{name}/{subresource} tail for both
cluster-scoped (/api/v1/nodes/n/status) and namespaced
(/apis/apps/v1/namespaces/ns/deployments/d/scale) shapes. ServeHTTP routes
subresource requests to a dedicated dispatcher (stubbed to 404 until the
reconcile phase wires /status and /scale) so a subresource path is never
mis-parsed as a write against the parent object. Updated the parseRoute unit
test to the new (correct) cluster-subresource semantics.

* feat(k8s): generic resource registry + reconcile engine (Phases B+C)

Turn the k8s data plane from a CRUD store into a minikube-like runtime.

Registry (registry.go, registry_ops.go, registry_defs.go): a generic
unstructured-backed store + one handler serving CRUD, list (label & field
selectors), watch, patch, delete (ownerReference garbage collection), and the
/status + /scale subresources for any registered kind. New kinds are a
registration + optional reconcile hook. Registers apps/v1 ReplicaSet,
StatefulSet, DaemonSet and core/v1 PersistentVolumeClaim; discovery is derived
from the registry so it can't drift.

Reconcile engine (reconcile.go), run synchronously on every write (no
controller goroutines, so it stays deterministic):
- Pods are driven Running with a synthetic Pod IP and ready containers.
- Deployment materializes its Pods and reports real status; ReplicaSet and
  DaemonSet do likewise; StatefulSet creates stable-ordinal Pods (name-0..N-1)
  plus a Bound PVC per volumeClaimTemplate.
- The endpoints controller fills a Service's Endpoints from the Running Pods
  matching its selector, and drains them when Pods are deleted/GC'd.
- Deleting a controller cascades to its Pods; scaling (spec.replicas or the
  /scale subresource) adjusts the Pod count.

Typed handlers: Deployment now reconciles + serves /scale and /status; direct
Pod creates come up Running; Pod list honors label/field selectors; Service
create populates endpoints.

Tests: new client-go WorkloadRuntime E2E (Deployment+Service -> Running pods +
endpoints -> scale to 4 -> StatefulSet with 3 stable pods + 3 Bound PVCs ->
DaemonSet -> cascade teardown). Existing pod/cascade/provider tests updated to
the new Running/materialized behavior. Deployment /scale + /status advertised
in discovery.

Deferred to later phases: the intermediate ReplicaSet object for Deployments
(pods are owned by the Deployment directly); Job/CronJob, Ingress, RBAC, HPA,
Node, Event, NetworkPolicy, EndpointSlice; strategic-merge / server-side-apply.

* k8s: register batch/networking/rbac/storage/autoscaling/discovery + core supporting kinds; registry-driven discovery

Adds registry entries for Job/CronJob, Ingress/IngressClass/NetworkPolicy,
RBAC (Role/RoleBinding/ClusterRole/ClusterRoleBinding), StorageClass,
HorizontalPodAutoscaler, EndpointSlice, and core PVC/PV/Node/Event/
ResourceQuota/LimitRange. Reconcile hooks drive Job pods to Succeeded,
Ingress to a load-balancer IP, and PV to Available/Bound.

serveDiscovery now derives the /apis group list and every
/apis/<group>/<version> resource list from registeredResources() (seeded
with the typed apps/policy groups) instead of a hardcoded switch, so new
groups and their subresources are discoverable by kubectl and client-go
without drifting from what the server serves.

* test(k8s): e2e coverage for supporting kinds via client-go

Drives Jobs (complete to Succeeded with materialized pods), Ingresses
(get a load-balancer IP), PVCs (bind), StorageClass/RBAC/HPA/Node
round-trips, and asserts the new API groups are discoverable — the
negotiation kubectl and client-go do before any typed request.

* k8s: rolling updates replace Pods on pod-template change; advertise endpoints

- Controllers stamp a pod-template-hash label on Pods; reconcile treats a
  changed template hash as a rolling update and replaces stale-hash Pods
  (Deployment/ReplicaSet via syncScaledPods, StatefulSet via syncStablePods).
  Convergence is instant — no surge/unavailable pacing.
- buildControllerPod now copies the template label map before stamping, so it
  can't mutate the controller's shared template.
- Discovery advertises core/v1 endpoints (get/list/watch only, matching the
  read-only handler) so kubectl/client-go can resolve them.

E2E: runtime test now exercises a rolling update (image change replaces all
Pods, endpoints re-point); supporting-kinds test asserts endpoints discovery.

* docs(k8s): document the minikube-like data plane and its non-goals

Update services.md §18, sdk-server.md, and the package doc to reflect the
reconcile engine (Running Pods, Endpoints, binding PVCs, completing Jobs),
validated TLS via the shared CA, the full multi-group resource surface with
/scale and /status subresources, rolling updates, and the deliberate emulation
boundaries (no exec/logs/portforward, no scheduling, no quota/RBAC/policy
enforcement, no HPA/CronJob actuation).

* fix(k8s): merge-patch to /scale no longer silently scales to zero

applyUnstructuredPatch decoded the merged JSON with plain json.Unmarshal
into map[string]any, which turns whole-number JSON into float64.
unstructured.NestedInt64 accepts only int64, so spec.replicas read back as
0 — a 'kubectl scale --replicas=N' (a merge-patch to the /scale subresource,
or any merge-patch touching replicas) silently scaled the workload to zero.

Decode via unstructured.Unstructured.UnmarshalJSON instead, which preserves
integers as int64. This fixes every merge-patch path (object and /scale) at
the root. Regression test drives a merge-patch scale-up and asserts both the
returned Scale and the stored object carry replicas=4.

* fix(k8s): address review findings across reconcile, GC, endpoints, PKI

- Endpoints: only bump ResourceVersion / publish MODIFIED when the address set
  actually changes. resyncEndpointsForNamespaceLocked runs for every Service on
  any Pod change, so an unchanged Service was emitting a spurious watch event
  (with a climbing RV) on unrelated Pod churn. Regression test added.
- Pod field selector: support spec.nodeName. Every materialized Pod is scheduled
  to the synthetic node, so 'kubectl get pods --field-selector spec.nodeName=...'
  (node-drain/kubelet tooling) previously returned an empty list. E2E covers it.
- Garbage collection: walk the owned set breadth-first and collect UIDs before
  deleting, instead of mutating each store's map while ranging it and recursing.
  Pods owned by an intermediate controller (not just the root) are now reaped.
- Scale subresource: only bump generation when spec.replicas actually changes,
  matching registryUpdate/registryPatch (no spurious generation != observed).
- Job: ignore a non-positive spec.completions (default to 1) so a Job can't
  report Complete having run zero Pods.
- StatefulSet PVCs: deep-copy the volumeClaimTemplate spec per ordinal instead
  of aliasing one map across every PVC.
- PKI: give each serving leaf a random 128-bit serial (was fixed '2') and assert
  BasicConstraintsValid (cA=FALSE) so strict non-Go verifiers accept the leaf.
- docs: correct the data-plane list to say it is unpaginated (limit/continue are
  not honored) and scope field-selector support accurately.

* k8s: real-user kubectl parity — protobuf writes, OpenAPI v2/v3, strategic & JSON patch

Driving a running cloudemu server with real kubectl (cluster created via the
EKS/GKE/AKS SDK, then kubectl against the advertised endpoint) surfaced gaps
the JSON-forcing client-go tests masked. kubectl now works end-to-end.

- Protobuf request bodies: kubectl sends built-in kinds as protobuf on writes
  and does NOT retry as JSON on 415, so every 'kubectl create/apply/scale'
  write failed. Decode protobuf via the client-go scheme's recognizing
  deserializer (typed handlers decode in place; registry handlers convert to
  unstructured). Responses stay JSON — clients' Accept allows it.
- OpenAPI: serve a v3 discovery root + per-group docs that carry each served
  GVK (with a permissive schema) so kubectl resolves the kind and stays on the
  JSON v3 path; and serve the legacy v2 doc as protobuf bytes (mime-safe
  application/octet-stream content type) for the fallback. Without this
  'kubectl apply' died at 'failed to download openapi'. Served
  cluster-independently in APIServer.ServeHTTP so the prefix-less v3
  serverRelativeURL follow-ups resolve.
- Patch types: typed handlers now accept strategic-merge-patch (kubectl's
  default for set/edit/label — real strategic merge, so the container list
  merges by name) and JSONPatch (RFC 6902), in addition to merge-patch;
  registry handlers gain JSONPatch too.
- Discovery: advertise kubectl short names (pvc, hpa, sts, ds, rs, ing, sc, …)
  for registry kinds so 'kubectl get pvc' resolves.

Verified with real kubectl v1.36 against a standalone server: full lifecycle
(apply → scale → rolling update → statefulset/PVCs → daemonset → job → cronjob
→ ingress → hpa → pv/pvc/storageclass → rbac → networkpolicy → node → all three
patch types → cascade teardown) across EKS, GKE, and AKS connect paths.

* docs(k8s): note full kubectl parity (protobuf, OpenAPI, all patch types)

* k8s: drop len()+1 map capacity hint (clears CodeQL allocation-overflow alert)

* k8s: filter watch streams by label/field selector (review blocker)

Watch streams ignored labelSelector/fieldSelector: typed watches (watchPods,
watchDeployments, …) filtered neither initial nor streamed events, and the
registry watch filtered only the initial snapshot. A selective watch
('kubectl get pods -l app=x -w', or any informer/controller-runtime cache
built with a selector) therefore received non-matching objects — polluting
reflector caches and firing spurious reconciles, which the reconcile engine
amplifies (one Deployment emits many Pod events).

streamWatch now takes a keep(T) predicate applied to both the initial snapshot
and every streamed event; each watch handler builds it from the request's
selectors (parseListSelectors + metaFieldsMatch/podMatchesFields/matchesFields).
Also extracts field-selector-name constants (fixes goconst) and indexes
filterPods to avoid per-item Pod copies.

* k8s: cap materialized pods, bootstrap Node, mirror EndpointSlices, resync endpoints on pod update/patch

Correctness gaps from the PR review:
- Unbounded replicas/completions: the reconciler runs synchronously under the
  cluster lock, so a huge spec value would allocate/hang the whole API. Clamp
  the materialized Pod count to maxReconciledPods (500) for Deployment,
  ReplicaSet/StatefulSet (via replicasOf), and Job. reconcileJob's top-up is
  also made O(n) instead of O(n²).
- Synthetic Node: bootstrap cloudemu-node-0 (Ready, InternalIP) in
  newClusterState so 'kubectl get nodes' is non-empty and the node every Pod is
  scheduled onto actually exists.
- EndpointSlices: mirror each Service's endpoints into a discovery.k8s.io
  EndpointSlice (labelled kubernetes.io/service-name) so EndpointSlice-mode
  consumers (kube-proxy, Gateway API) see the same backends as Endpoints.
- Pod update/patch now resync endpoints (a label change matching a Service
  selector was invisible until unrelated churn) and re-drive a spec-only PUT
  back to Running so it isn't dropped out of the endpoint set.

reconcileServiceEndpointsLocked is split into matchingEndpointAddressesLocked /
writeEndpointsLocked / syncEndpointSliceLocked (also lowers its complexity).
E2E asserts the synthetic Node and populated EndpointSlices; a new watch test
asserts label-selector stream filtering.

* k8s: dedup watch handlers + resolve golangci-lint to zero (review blocker)

- All 8 typed watch handlers now share a generic serveWatch[T] helper (removes
  the dupl the near-identical subscribe/snapshot/stream blocks triggered, and
  addresses the reuse the review flagged).
- golangci-lint (repo .golangci.yml, v2.11.4) is clean on the new non-test
  files: extracted goconst constants (api/apis path segments, status/scale
  subresources, group names), named crypto/mnd magic numbers in k8spki, gave
  parseListSelectors named results, indexed the container-status range,
  lowered ServeHTTP/serveRegistry complexity via dispatchResource /
  serveRegistryItem, fixed the govet shadow, and added reasoned //nolint for
  the legitimately-global lookup tables and hugeParam k8s structs.

No behavior change; build, vet, tests, and -race remain green.

* k8s: bump Deployment generation on spec change; unify /scale patch types

- Typed Deployment now sets metadata.generation=1 on create and advances it
  only on a spec change (update/patch), matching apiserver semantics and the
  registry path so observedGeneration comparisons are meaningful.
- deploymentScale PATCH routes through the shared applyPatchBytes dispatcher,
  so the typed /scale honors merge / strategic-merge / JSONPatch like the
  registry /scale (the two paths no longer diverge).
- Tidy a stale AKS kubeconfig comment (Phase 3 -> the normal path).

* docs(k8s): note watch selector filtering, synthetic node, EndpointSlice mirroring

* k8s: address second-review findings (lint robustness, watch relist, docs)

From thzgajendra's review of PR #299:
- Lint (#1): replace the version-sensitive //nolint:prealloc directives with
  real preallocation (coreResources/appsResources/registryAPIResources,
  openapi kinds, endpoint-address slice), so golangci-lint is clean regardless
  of prealloc's version-dependent placement — no dangling directives.
- Docs (#2): drop the 'pagination' claim from the k8s data-plane sentence in
  sdk-server.md; data-plane lists are unpaginated, matching services.md.
- Watch load-shedding (#3): a slow watcher that overflows its buffer now
  receives a 410 Gone (ERROR) event and the stream ends, so client-go relists
  instead of running with a permanently-divergent cache. Regression test added.
- GC comment (#4): correct the 'never mutate while ranging' wording — deleting
  the current key mid-range is legal; the BFS is what makes the cascade
  order-independent.
- Provider package headers (#8): describe the now-wired data plane instead of
  'out of scope / Wave 2'.

Deferred as documented follow-ups (all Low): clamp/silent-signal, Job shrink
reconcile, committed kubectl smoke test, provider CA-vs-sentinel misconfig
window.
thzgajendra added a commit that referenced this pull request Jul 31, 2026
* feat(azure): full parity for Azure MySQL Flexible Server sub-resources

Add databases, firewall rules and server configurations plus the server
failover action to Azure Database for MySQL Flexible Server, bringing it to
native parity with the ARM surface real armmysqlflexibleservers clients use.

Introduce Databases, FirewallRules, Configurations and Failover as optional
relationaldb driver capabilities (mirroring SubnetGroups), so the same
interfaces are reusable by the other managed-SQL services. The mock stores each
family per server and cascade-deletes children on server delete; the ARM handler
routes databases/firewallRules/configurations, updateConfigurations (batch) and
the failover action. Covered by real-SDK round-trip tests and mock-level
error-path/cascade tests.

* feat(azure): full parity for Azure PostgreSQL Flexible Server sub-resources

Add databases, firewall rules and server configurations to Azure Database for
PostgreSQL Flexible Server, reusing the Databases/FirewallRules/Configurations
optional relationaldb capabilities introduced for MySQL Flex. Postgres Flex has
no failover action and no batch-configuration endpoint, and its configuration
resource accepts both PUT and PATCH; the handler and mock reflect that. The mock
cascade-deletes children on server delete. Covered by real-SDK round-trip tests
(the SDK has no ClientFactory, so each client is built from shared options) plus
mock-level default/error/cascade tests.

* feat(azure): full parity for Azure SQL server sub-resources

Add firewall rules, virtual-network rules, elastic pools, failover groups and
the Azure AD administrator to Azure SQL (Microsoft.Sql). Firewall rules reuse
the shared FirewallRules capability; the other four are added as optional
relationaldb capabilities (VNetRules, ElasticPools, FailoverGroups, AADAdmins)
alongside the existing SubnetGroups pattern. Failover-group failover flips the
local replication role between Primary and Secondary. The mock cascade-deletes
all child resources on server delete and returns isolated copies of the
slice-bearing failover-group state. Covered by real-SDK (armsql) round-trip
tests across all five families plus mock-level error/cascade/aliasing tests.

* feat(gcp): full parity for Cloud SQL databases, users, certs and instance ops

Add databases (via the shared Databases capability), users and client SSL certs
as instance child resources, plus the clone, failover, promote-replica and
start/stop-replica instance actions to GCP Cloud SQL. Users and SSL certs are
new optional relationaldb capabilities (Users, SslCerts); clone and replica
promotion are Clonable and ReplicaPromotion; failover reuses the shared Failover
capability. The REST path parser now recognizes the databases/users/sslCerts
sub-collections, and the users route honors Cloud SQL's ?name= query quirk for
delete and update. The mock cascade-deletes children on instance delete. Tiers
and flags catalogs are intentionally out of scope (separate path shapes, static
data). Covered by real sqladmin SDK round-trip tests plus mock-level
clone/cascade/error tests.

* feat(discovery): surface managed SQL servers in Resource Graph and Cloud Asset

Add a RelationalDatabases discovery capability to the resource-discovery engine
and a walkRelationalDB walker, mirroring the Kubernetes adapter pattern. Azure
wires an adapter that projects Azure SQL logical servers plus MySQL/PostgreSQL
Flexible Servers, and GCP projects Cloud SQL instances, so managed relational
databases appear in cross-service inventory. Resource Graph maps the portable
types to microsoft.sql/servers, microsoft.dbformysql/flexibleservers and
microsoft.dbforpostgresql/flexibleservers; Cloud Asset maps Cloud SQL to
sqladmin.googleapis.com/Instance. Both type-map switches become lookup tables to
stay under the cyclomatic-complexity gate. Covered by walker and type-map tests.

* feat(cost): add managed relational-database rates

Add relationaldb:* entries to the cost rate catalog so provisioning a managed
database server/instance (RDS, Azure SQL, Azure MySQL/PostgreSQL Flexible
Server, Cloud SQL) is billed per instance-hour, clusters per cluster-hour, and
restores reuse the instance-hour, while snapshots and lifecycle actions are
free. The portable "relationaldb" service name means one catalog covers every
cloud. Covered by a cost-tracker test.

* docs: document full managed-SQL parity (sub-resources, discovery, cost)

Document the native sub-resource capabilities added to Azure SQL, the Azure
MySQL/PostgreSQL Flexible Servers and Cloud SQL — databases, users, firewall/
vnet rules, configurations, elastic pools, failover groups, AAD admins, SSL
certs, clone/failover/replica actions — along with their discovery surfacing and
cost rates. Refresh the relational-database operation totals and the discovery
driver list.

* feat(sql): Cloud SQL tiers/flags catalogs + elastic-pool metrics

Close the remaining managed-SQL parity gaps: serve the Cloud SQL machine-tier
catalog (GET /v1/projects/{p}/tiers) and the database-flag catalog
(GET /v1/flags, which is project-less) as static reference data, and emit
Microsoft.Sql/servers/elasticpools metrics (cpu/storage/workers percent) when an
Azure SQL elastic pool is created. Also annotate the ModifyInstance/ModifyCluster
methods across the four SQL mocks with the driver-interface hugeParam nolint now
that the shared ModifyInstanceInput grew. Covered by SDK tiers/flags round-trip
and an elastic-pool metric-emission test.

* feat(azure): add SQL Managed Instance family to Azure SQL

Add the Microsoft.Sql/managedInstances resource type and its managed databases
as a ManagedInstances optional relationaldb capability: managed-instance CRUD +
list + start/stop/failover actions, and managed-database CRUD + list. The
handler now matches the managedInstances resource type alongside servers and
routes both, and the mock cascade-deletes managed databases when their instance
is removed. Covered by an armsql managed-instance/database SDK round-trip test
(create → get → list → failover → cascade delete) and a mock-level lifecycle
test.

* docs: document managed instances, tiers/flags and elastic-pool metrics

Update the relational-database section for the now-complete managed-SQL parity:
add the ManagedInstances capability row, note Cloud SQL's tiers/flags reference
catalogs and Azure SQL's Managed Instance family, and record the elastic-pool
metric namespace. Refresh the optional-operation totals (25 capability
interfaces, +109 relational / +118 grand-total optional).

* fix(sql): clone ManagedInstance tags on read; deterministic list ordering

Address review MEDIUM #1 and the list-ordering LOW: GetManagedInstance /
ListManagedInstances now clone the stored Tags map so a caller mutating the
returned map can't corrupt the store (the copy-on-read hole flagged as the
concurrent-map panic class), and every List* mock method iterates
memstore.SortedValues() instead of All() for deterministic SDK list ordering,
matching the documented convention. Large-value list loops use index iteration
to avoid per-element copies.

* fix(azure): real update semantics + discoverable managed instances

Address review MEDIUM #2/#3/#4 (Azure update paths) and #7 (MI discovery):

- PUT on an existing Azure SQL server / database / managed instance now applies
  the request body (upsert) instead of returning the stale record.
- PATCH is a genuine merge — elastic pools, failover groups and managed
  instances gain Update* capability methods that overlay only the fields the
  request supplied, so a partial PATCH no longer wipes unspecified fields; MI
  PATCH now decodes and applies its body instead of being a no-op.
- Managed instances are projected into cross-service discovery
  (microsoft.sql/managedinstances) via sqlDiscovery + the Resource Graph type
  map, so a created MI appears in inventory.

Covered by SDK PATCH-merge round-trip tests (elastic pool keeps its SKU when
only maxSizeBytes is patched; MI keeps administratorLogin when only vCores is
patched) and a managed-instance type-map test.

* fix(azure): model Azure SQL database elastic-pool membership

Address review MEDIUM #5. Databases now carry an ElasticPoolID (added to the
shared InstanceConfig/Instance/ModifyInstanceInput and surfaced as the
elasticPoolId ARM database property), so an SDK client placing a database into a
pool round-trips instead of silently dropping it. DeleteElasticPool now returns
a precondition error while the pool still contains databases, matching real
Azure's 409. Covered by a membership/delete-guard test.

* fix(gcp): real Cloud SQL read-replica and failover semantics

Address review MEDIUM #6. A Cloud SQL insert with masterInstanceName now creates
an actual read replica: the replica records its master (ReadReplicaSource) and
the primary lists it (replicaNames), both surfaced in the instance body. Replica
lifecycle is faithful — start/stopReplica require the target to be a replica and
leave it RUNNABLE (no SUSPENDED state change); promoteReplica detaches it from
the primary (and rejects a non-replica); failover is a primary-only operation
and rejects a replica. Covered by SDK and mock replica-lifecycle tests.

* fix(sql): review LOW items — determinism, validation, replica fidelity tests

- Cloud SQL backup-run IDs are generated by the mock from the clock + a
  monotonic counter (was time.Now().UnixNano(), violating the Clock determinism
  rule and collision-prone); CloneInstance now clones the source's databases and
  resets replica linkage; UpdateUser doc corrected.
- Firewall rules validate IPv4 start/end (Azure SQL + both Flexible Servers);
  Azure SQL Managed Instance requires subnetId, as real Azure does.
- Added a real-SDK Resource Graph indexing test that drives sqlDiscovery
  end-to-end (logical server + managed instance appear and filter), and a
  -race concurrency test that mutates a returned managed-instance Tags map to
  pin the copy-on-read fix.

* fix(sql): address second review — MI lifecycle, in-place restore, validation

- Cloud SQL DeleteInstance now unlinks replica<->master before cascading
  children, so no dangling ReadReplicaSource/ReadReplicaTargets remain.
- Managed Instance lifecycle gains a state guard (transitionManagedInstance):
  Start/Stop respect current state, Failover requires Ready; MI create emits
  representative metrics and clones returned Tags; adds CreateManagedInstance
  cost rate.
- Cloud SQL RestoreBackup restores in place onto the existing instance via a
  new optional BackupRestorer capability (was create-new -> 409).
- Failover-group failover requires a partner server; firewall rules validate
  Start <= End; Azure Flex SetConfiguration rejects unknown params and empty
  values; ARM parser captures the action verb so forced vs planned failover
  and unknown POST verbs are distinguished; Cloud SQL selfLink/targetLink use
  the served /v1 prefix.
- Broaden new-package test coverage (sub-resource CRUD, MI lifecycle, Users
  update, backup get, error paths, server PATCH, raw MI start/stop).

* fix(sql): address third review — output aliasing, config catalog, validation

- Deep-copy Tags/slice fields on every Instance/Cluster/Snapshot return path in
  azuresql and cloudsql (Describe/Create/Modify/Restore/Clone), so a returned
  value never aliases the memstore — fixes a potential concurrent-map crash and
  matches the managedinstance/FailoverGroup discipline.
- Azure Flex GetConfiguration/ListConfigurations return catalog defaults for a
  known-but-unset parameter (real Azure behavior) instead of NotFound/empty; the
  catalog now maps names to defaults.
- MySQL Flex batch config update is atomic: all entries are validated before any
  is applied, via a new optional BatchConfigurations capability.
- Azure SQL database create/modify validates the referenced elastic pool exists
  (symmetry with the pool-delete member guard).
- Cloud SQL rejects child (database/user) names containing '/' that would orphan
  a row; get-paths add length guards on single-ID Describe lookups.
- Flex firewall create validates start <= end (parity with Azure SQL).
- Tests: aliasing, config defaults, batch atomicity, elastic-pool validation,
  child-name rejection, FG update/list, managed-database delete, and Azure
  wire-level error-mapping (404/400) across all three Azure SQL services.

* feat(gcp): add AlloyDB full-parity support

Adds GCP AlloyDB as a first-class managed database server, reusing the
relationaldb driver.

- Provider providers/gcp/alloydb: implements RelationalDB (clusters,
  instances, cluster backups→ClusterSnapshot, restore) + Users + Databases,
  plus a new optional rdsdriver.AlloyDB capability for AlloyDB-specific
  behavior — rich cluster/instance create, cross-region secondary + promote,
  instance failover/restart, continuous/automated-backup + maintenance config,
  and *Info accessors. Cloud Monitoring metrics on instance create.
  Copy-on-read (clone Tags/slices), '/'-name and instance-type validation,
  cascade delete, and lifecycle state guards throughout.
- Server server/gcp/alloydb: alloydb.googleapis.com/v1 REST handler
  (clusters[/instances|/users], backups, LRO operations, custom methods
  :promote/:createsecondary/:restore/:failover/:restart) using the SDK types
  for wire fidelity; SDK round-trip + wire-error (404/409/400) tests.
- Wiring: providers/gcp/gcp.go (field, monitoring, combined CloudSQL+AlloyDB
  relational discovery adapter, TypeAlloyDBCluster); server/gcp Drivers gains
  an opt-in AlloyDB field (left nil in DriversFrom — its paths collide with
  GKE's, so the two are mutually exclusive on one server).
- Dedicated AlloyDB cost rates; docs/services.md updated (capabilities, GCP
  column, operation counts).

* fix(gcp): address AlloyDB review comments

- One PRIMARY per cluster enforced (base + native create); SECONDARY instance
  requires a SECONDARY cluster; READ_POOL requires nodeCount > 0.
- Detach dangling SECONDARY links when their PRIMARY cluster is deleted (the
  replica-linkage class from #303).
- FailoverInstance requires a PRIMARY target; RestartInstance stays valid on
  any type.
- UpdateUser is now reachable via Users.Patch (was 405).
- Custom methods (:promote / :failover / :restart) are POST-only and unknown
  verbs 404 instead of misrouting to CRUD; GET on :promote no longer promotes.
- Deterministic list order: DescribeClusters/DescribeInstances use SortedValues.
- patchCluster/patchInstance handle the capability assertion; toWireUser returns
  the full resource path; removed banner comments.
- Wiring: guard New against AlloyDB+GKE both enabled (they share paths) and add
  DriversFromWithAlloyDB helper (enables AlloyDB in place of GKE).
- Tests for every guard + user PATCH + GET-:promote rejection + 400 wire error +
  instance output aliasing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant