Skip to content

Latest commit

 

History

History
371 lines (308 loc) · 32.2 KB

File metadata and controls

371 lines (308 loc) · 32.2 KB

SDK-Compatible HTTP Server

CloudEmu includes an HTTP server that speaks the real cloud SDK wire protocols across all three providers — AWS, Azure, and GCP. Point the actual aws-sdk-go-v2, azure-sdk-for-go, or cloud.google.com/go / google.golang.org/api clients at it (via custom endpoint) and your production code runs unchanged against the in-memory backend.

Nothing to mock. No Docker. No accounts. The same SDK calls you'd run against real AWS / Azure / GCP hit a local httptest.NewServer and get back SDK-decodable responses.

Why

CloudEmu's Go API is great for new code you write for testing. But most real apps already use the official cloud SDKs directly. Rewriting those call sites just to test against an emulator is friction. The SDK-compat server removes that friction — change the endpoint, done.

Quick start (AWS)

import (
    "net/http/httptest"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/stackshy/cloudemu/v2"
    awsserver "github.com/stackshy/cloudemu/v2/server/aws"
)

cloud := cloudemu.NewAWS()
srv := awsserver.New(awsserver.Drivers{
    S3:         cloud.S3,
    DynamoDB:   cloud.DynamoDB,
    EC2:        cloud.EC2,
    VPC:        cloud.VPC,
    Lambda:     cloud.Lambda,
    SQS:        cloud.SQS,
    CloudWatch: cloud.CloudWatch,
    RDS:        cloud.RDS,
    Redshift:   cloud.Redshift,
    EKS:        cloud.EKS,
})
ts := httptest.NewServer(srv)
defer ts.Close()

client := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.BaseEndpoint = aws.String(ts.URL)
    o.UsePathStyle = true
})

// Use the real SDK exactly as you would against AWS.
client.PutObject(ctx, &s3.PutObjectInput{...})

Quick start (Azure)

import (
    "github.com/Azure/azure-sdk-for-go/sdk/azcore"
    "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
    "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
    "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    "github.com/stackshy/cloudemu/v2"
    azureserver "github.com/stackshy/cloudemu/v2/server/azure"
)

cp := cloudemu.NewAzure()
srv := azureserver.New(azureserver.Drivers{
    VirtualMachines: cp.VirtualMachines,
    BlobStorage:     cp.BlobStorage,
    CosmosDB:        cp.CosmosDB,
    Network:         cp.VNet,
    Monitor:         cp.Monitor,
    Functions:       cp.Functions,
    ServiceBus:      cp.ServiceBus,
    SQL:             cp.SQL,
    PostgresFlex:    cp.PostgresFlex,
    MySQLFlex:       cp.MySQLFlex,
    AKS:             cp.AKS,
})
ts := httptest.NewTLSServer(srv) // Azure SDK requires TLS

opts := &arm.ClientOptions{
    ClientOptions: azcore.ClientOptions{
        Cloud: cloud.Configuration{
            Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
                cloud.ResourceManager: {Endpoint: ts.URL, Audience: "https://management.azure.com"},
            },
        },
        Transport: ts.Client(),
    },
}
client, _ := armcompute.NewVirtualMachinesClient("sub-1", fakeCred{}, opts)

Quick start (GCP)

import (
    gcpcompute "cloud.google.com/go/compute/apiv1"
    "github.com/stackshy/cloudemu/v2"
    gcpserver "github.com/stackshy/cloudemu/v2/server/gcp"
    "google.golang.org/api/option"
)

cp := cloudemu.NewGCP()
srv := gcpserver.New(gcpserver.Drivers{
    Compute:        cp.GCE,
    Storage:        cp.GCS,
    Firestore:      cp.Firestore,
    Networking:     cp.VPC,
    Monitoring:     cp.CloudMonitoring,
    CloudFunctions: cp.CloudFunctions,
    PubSub:         cp.PubSub,
    CloudSQL:       cp.CloudSQL,
    GKE:            cp.GKE,
})
ts := httptest.NewServer(srv)

opts := []option.ClientOption{
    option.WithEndpoint(ts.URL),
    option.WithoutAuthentication(),
    option.WithHTTPClient(ts.Client()),
}
client, _ := gcpcompute.NewInstancesRESTClient(ctx, opts...)

Quick start (Databricks)

The Azure server also speaks the databricks-sdk-go WorkspaceClient wire protocol. Wire the same *databricks.Mock into both Databricks (ARM workspace control plane) and DatabricksDataPlane (the /api/2.x workspace data plane).

import (
    "net/http/httptest"

    databricks "github.com/databricks/databricks-sdk-go"
    "github.com/databricks/databricks-sdk-go/config"
    "github.com/databricks/databricks-sdk-go/service/compute"
    "github.com/stackshy/cloudemu/v2"
    azureserver "github.com/stackshy/cloudemu/v2/server/azure"
)

cp := cloudemu.NewAzure()
srv := azureserver.New(azureserver.Drivers{
    Databricks:          cp.Databricks, // Microsoft.Databricks/workspaces (ARM)
    DatabricksDataPlane: cp.Databricks, // /api/2.x workspace data plane
})
ts := httptest.NewServer(srv)
defer ts.Close()

w, _ := databricks.NewWorkspaceClient(&databricks.Config{
    Host:        ts.URL,
    Token:       "test-token",
    Credentials: config.PatCredentials{},
})

// Real WorkspaceClient calls round-trip against the in-memory backend.
w.InstancePools.Create(ctx, compute.CreateInstancePool{InstancePoolName: "pool-1"})

Region, credentials, and tokens can be any dummy values — the server doesn't validate signatures or AAD tokens.

Currently supported

AWS (server/aws/)

Service Operations
S3 CreateBucket, DeleteBucket, ListBuckets, PutObject, GetObject, HeadObject, DeleteObject, ListObjectsV2 (prefix, delimiter, common prefixes, continuation token), CopyObject
DynamoDB CreateTable, DeleteTable, DescribeTable, ListTables, PutItem, GetItem, DeleteItem, UpdateItem (SET/REMOVE), Query, Scan (with FilterExpression), BatchWriteItem, BatchGetItem, TransactWriteItems
EC2 RunInstances, DescribeInstances (filters: instance-id, instance-type, instance-state-name, tag:*), Start/Stop/Reboot/TerminateInstances, ModifyInstanceAttribute
EC2 — VPC + Networking VPCs, Subnets, Security Groups + ingress/egress rules, Internet Gateways, Route Tables + Routes, NAT Gateways, VPC Peering, Flow Logs, Network ACLs
EC2 — EBS + Key Pairs Volumes (Create/Delete/Describe/Attach/Detach), Key Pairs
EC2 — Snapshots + AMIs + Spot + Launch Templates Snapshots, Images, Spot instance requests, Launch Templates
Auto Scaling CreateAutoScalingGroup, Update/Delete/Describe, SetDesiredCapacity, scaling policies
Lambda (REST + JSON) CreateFunction, GetFunction, ListFunctions, DeleteFunction, Invoke (sync)
SQS (JSON-RPC AwsJson1_0) CreateQueue, GetQueueUrl, ListQueues, DeleteQueue, SendMessage, ReceiveMessage, DeleteMessage
CloudWatch (Smithy rpc-v2-cbor) PutMetricData, GetMetricStatistics, ListMetrics, PutMetricAlarm, DescribeAlarms, DeleteAlarms
RDS / Aurora (query protocol) DBInstances (Create/Describe/Modify/Delete/Start/Stop/Reboot), DBClusters (Create/Describe/Modify/Delete/Start/Stop), DBSnapshots + DBClusterSnapshots (Create/Describe/Delete/Restore). One handler also serves the Neptune and DocumentDB engines — both reuse the same aws-sdk-go-v2/service/{neptune,docdb} client surface.
Redshift (query protocol) CreateCluster, DescribeClusters, ModifyCluster, DeleteCluster, RebootCluster, CreateClusterSnapshot, DescribeClusterSnapshots, DeleteClusterSnapshot, RestoreFromClusterSnapshot
MemoryDB (JSON 1.1, AmazonMemoryDB.*) Clusters (Create/Describe/Update/Delete/FailoverShard/ListAllowedNodeTypeUpdates), ACLs & Users, Parameter Groups, Subnet Groups, Snapshots (Create/Describe/Copy/Delete + restore), tags, engine-version & event catalogs. Optional (type-asserted): Multi-Region clusters, Reserved Nodes. Server-side MaxResults/NextToken pagination on every Describe.
Keyspaces (JSON 1.0, KeyspacesService.*) Keyspaces (Create/Get/List/Update/Delete, single/multi-region replication), Tables (Create/Get/List/Update/Delete/Restore — full schema, capacity, encryption, PITR, TTL, CDC), user-defined types, tags. Optional: GetTableAutoScalingSettings. Responses use lower-camel keys so the case-sensitive SDK deserializer decodes them; pagination on every list.
EKS (REST + JSON) Clusters (Create/Describe/List/UpdateConfig/UpdateVersion/Delete), NodeGroups (Create/Describe/List/UpdateConfig/UpdateVersion/Delete), Fargate Profiles (Create/Describe/List/Delete), Addons (Create/Describe/List/Update/Delete). Stub kubeconfig only — data plane deferred to Wave 2.
IAM (query protocol) Users (Create/Get/List/Delete), Roles (Create/Get/List/Delete), Policies (Create/Get/List/Delete), Attach/Detach/ListAttached for both Users and Roles, Groups (Create/Get/List/Delete + AddUserToGroup/RemoveUserFromGroup/ListGroupsForUser), AccessKeys (Create/List/Delete), InstanceProfiles (Create/Get/List/Delete + AddRoleToInstanceProfile/RemoveRoleFromInstanceProfile). Errors surface as typed *types.NoSuchEntityException / *types.EntityAlreadyExistsException.
Resource Explorer 2 (JSON) Search — free-text plus filter expression over the cross-service inventory; results include ARN, resource type, region, owning account, and tags
Resource Groups Tagging API (JSON-RPC) GetResources (filter by ResourceTypeFilters + TagFilters, paginated), TagResources, UntagResources, GetTagKeys, GetTagValues
Bedrock (REST + JSON, bedrock + bedrock-runtime) Control plane: foundation models (List/Get), model-customization jobs (Create/Get/List), custom models (List/Get/Delete), Guardrails (Create/Get/List/Update/Delete + CreateGuardrailVersion, with topic/content/word/sensitive-info/contextual-grounding policy configs and version snapshots), Provisioned Throughput (Create/Get/List/Delete), invocation-logging config (Put/Get/Delete), resource tagging (Tag/Untag/ListTagsForResource), model import jobs, model copy jobs, evaluation jobs (Create/Get/List/Stop), inference profiles (Create/Get/List/Delete), prompt routers (Create/Get/List/Delete), marketplace model endpoints (Create/Get/List/Update/Delete/Register/Deregister), foundation-model agreements (Create/Delete/ListOffers/GetAvailability), automated-reasoning policies (Create/Get/List/Update/Delete). Runtime: InvokeModel (family-aware response envelopes), Converse, ConverseStream + InvokeModelWithResponseStream (eventstream), CountTokens, ApplyGuardrail, and async invoke (Start/Get/List).
Bedrock Agent (REST + JSON, bedrock-agent + bedrock-agent-runtime) Control plane: agents (Create/Get/List/Update/Delete/Prepare + alias), knowledge bases (CRUD), data sources (CRUD + StartIngestionJob), flows (CRUD + Prepare), prompts (CRUD). Runtime: InvokeAgent (eventstream), Retrieve, RetrieveAndGenerate. Scope: the core resource lifecycle and runtime data plane above; agent versioning/aliases beyond basic create, action groups, and agent collaborators are out of scope for this iteration.

Azure (server/azure/)

All handlers speak ARM JSON over HTTPS unless noted.

Service ARM provider / operations
Virtual Machines Microsoft.Compute/virtualMachines — CreateOrUpdate, Get, List, Delete, start, powerOff, restart
Disks / Snapshots / Images / SSH Public Keys Microsoft.Compute/{disks,snapshots,images,sshPublicKeys} — full CRUD
Blob Storage (data plane) Containers + Blobs: Create/Delete/List, PutBlob, GetBlob, DeleteBlob, CopyBlob
Cosmos DB (data plane) Databases, Containers, Documents — full CRUD with x-ms-documentdb-* headers
Virtual Network Microsoft.Network/virtualNetworks — CRUD + subnets
Azure Monitor microsoft.insights/metricAlerts and metric data ingest/read
Functions Microsoft.Web/sites (Function Apps): CreateOrUpdate, Get, List, Delete + non-ARM /api/{name} invoke
Service Bus Microsoft.ServiceBus/namespaces[/queues] ARM CRUD + raw-HTTP REST data plane (POST /{ns}/{queue}/messages, DELETE /messages/head)
SQL Database Microsoft.Sql/servers[/databases] — servers and databases, full CRUD lifecycle
Managed Cassandra Microsoft.DocumentDB/cassandraClusters[/dataCenters] — clusters (CreateOrUpdate, Get, ListByResourceGroup, ListBySubscription, Update, Delete, deallocate, start, invokeCommand, status) and datacenters (CreateOrUpdate, Get, List, Update, Delete). Real armcosmos CassandraClusters/CassandraDataCenters clients round-trip end-to-end, including the LRO pollers.
PostgreSQL Flexible Server Microsoft.DBforPostgreSQL/flexibleServers — full CRUD lifecycle
Cosmos DB for PostgreSQL Microsoft.DBforPostgreSQL/serverGroupsv2 — clusters (CreateOrUpdate, Get, ListByResourceGroup, ListBySubscription, Update, Delete, restart, start, stop, promote, checkNameAvailability), firewall rules, roles, derived servers/nodes, configurations (cluster/coordinator/node reads + updates), and private endpoint connections/links. Real armcosmosforpostgresql clients round-trip end-to-end, including the LRO pollers.
MySQL Flexible Server Microsoft.DBforMySQL/flexibleServers — full CRUD lifecycle
AKS Microsoft.ContainerService/managedClusters — ManagedClusters (CreateOrUpdate, Get, UpdateTags, Delete, List/ListByResourceGroup), AgentPools (CreateOrUpdate, Get, Delete, List), MaintenanceConfigurations (CreateOrUpdate, Get, Delete, List), ListClusterAdmin/User/MonitoringUser Credentials, RotateClusterCertificates. Stub kubeconfig only — data plane deferred to Wave 2.
IAM (armauthorization) Microsoft.Authorization — RoleDefinitions (CreateOrUpdate, Get, List, Delete) and RoleAssignments (Create, Get, ListForScope, Delete) at any scope (subscription, resource group, resource, management group). Real armauthorization SDK clients round-trip end-to-end. Microsoft Graph (users/groups) is out of scope — deferred to a future handler.
Resource Graph Microsoft.ResourceGraphPOST /providers/Microsoft.ResourceGraph/resources?api-version=2022-10-01 with a KQL-shaped query over the cross-service inventory; supports subscriptions[] scoping and $top/$skipToken pagination. Rows carry the fixed columns (id [ARM-shaped], name, type, location, resourceGroup, subscriptionId, tags) plus resource-shape columns emitted when present — sku.name, properties, managedBy, kind, zones — so SKU/tier/size-sensitive consumers (e.g. a discovery + cost engine) can read a VM's size, a managed disk's tier/diskSizeGB/owning VM, or a flexible server's compute SKU. project/summarize/join are tolerated but ignored (the full row is always returned).
Databricks (ARM control plane) Microsoft.Databricks/workspaces — CreateOrUpdate, Get, Delete, UpdateTags, List / ListByResourceGroup. Real armdatabricks SDK clients round-trip end-to-end.
Databricks (workspace data plane) (databricks-sdk-go, /api/2.x) Point the real WorkspaceClient at Config.Host. Clusters (create/edit/start/restart/resize/pin/unpin/delete + list-node-types / spark-versions / zones), instance pools, jobs + runs (submit / run-now / get / list / cancel / cancel-all / repair / output / delete), cluster policies, libraries (install / uninstall / status), and object permissions. Self-contained families: secrets (scopes / secrets / ACLs), tokens, git credentials, repos, DBFS (incl. block upload), workspace notebooks/directories, SQL warehouses, pipelines, serving endpoints, SCIM identity (users / groups / service principals), and Unity Catalog (catalogs / schemas / tables + metastores / external locations / storage credentials / volumes). Also serves GET /.well-known/databricks-config so the SDK's host-metadata resolution succeeds (workspace-host stub) instead of logging a warning.

GCP (server/gcp/)

All handlers speak REST + JSON.

Service Operations
Compute Engine Instances + Disks + Snapshots + Images: insert/get/list/delete with LRO envelopes
Networks VPCs, Subnetworks, Firewalls, Routes
Cloud Storage (GCS) Buckets + Objects: create/get/list/delete, upload, download, copy
Firestore Documents + Collections via :commit, :batchGet, :runQuery
Cloud Monitoring Time-series ingest/read, alert policies
Cloud Functions v1 Create (LRO), Get, List, Delete (LRO), :call (sync invoke)
Pub/Sub Topics + Subscriptions lifecycle, :publish, :pull, :acknowledge
Cloud SQL Instances (insert/get/list/patch/delete/start/stop/restart) + Operations (get/list) — supports the sqladmin/v1 SDK
Bigtable (bigtableadmin/v2, /v2) Instances (create/get/list/update/partialUpdate/delete), Clusters (create/get/list/update/delete + getMemoryLayer), Tables (create/get/list/delete/undelete/modifyColumnFamilies/dropRowRange/generateConsistencyToken/checkConsistency/restore/patch), App Profiles (CRUD), Backups (create/get/list/patch/delete/copy), Operations (get), and per-resource IAM (get/set/testIamPermissions on instances/tables/backups). LROs return Operation{done:true} with the resource inline.
GKE Clusters (Create/Get/List/Update/Delete + :setLogging/:setMonitoring/:setMasterAuth/:setLegacyAbac/:setNetworkPolicy/:setMaintenancePolicy/:setResourceLabels/:startIpRotation/:completeIpRotation), NodePools (Create/Get/List/Update/Delete + :setSize/:setAutoscaling/:setManagement/:rollback), Operations (Get/List/:cancel). Stub kubeconfig only — data plane deferred to Wave 2.
Cloud Asset Inventory assets.list (filter by assetTypes[]), searchAllResources (query + asset-type filter), searchAllIamPolicies (returns empty — out of scope), exportAssets (sync; inline results in the returned Operation), batchGetAssetsHistory, Feeds (create/list/get/patch/delete), operations.get. Resource names returned as GCP-shaped //service/path URNs.
IAM (iam.googleapis.com v1) ServiceAccounts (Create/Get/List/Delete/Patch), custom Roles (Create/Get/List/Delete/Patch), ServiceAccountKeys (Create/Get/List/Delete). Real google.golang.org/api/iam/v1 clients round-trip end-to-end; errors surface as typed *googleapi.Error. Resource-level getIamPolicy/setIamPolicy bindings on individual GCP resources are out of scope.

Any operation not in these lists returns 501 Not Implemented or the provider's native UnknownOperation / NotImplemented / NOT_FOUND error.

How it's wired internally

The server is a tiny core plus a plugin-per-service model. Each service is a self-contained package under server/.

server/
├── server.go                       # core: Handler interface + Server (~80 LOC)
├── wire/
│   ├── wire.go                     # shared XML/JSON helpers
│   ├── awsquery/                   # AWS query-protocol form decoder + XML envelope
│   ├── azurearm/                   # ARM URL parser + JSON helpers + error envelope
│   └── gcprest/                    # GCP REST URL parser + Operation LRO helpers
├── aws/
│   ├── aws.go                      # awsserver.New(Drivers{...})
│   ├── s3/  ec2/  dynamodb/  lambda/  sqs/  cloudwatch/
│   ├── rds/  redshift/             # query-protocol relational DB handlers
│   ├── eks/                        # REST EKS control-plane handler
│   ├── bedrock/                    # REST Bedrock control plane + bedrock-runtime
│   ├── bedrockagent/               # REST bedrock-agent control plane
│   └── bedrockagentruntime/        # REST bedrock-agent-runtime data plane
├── azure/
│   ├── azure.go                    # azureserver.New(Drivers{...})
│   ├── virtualmachines/  disks/  snapshots/  images/  sshpublickeys/
│   ├── blob/  cosmos/  network/  monitor/  functions/  servicebus/
│   ├── sql/  postgresflex/  mysqlflex/   # ARM relational DB handlers
│   ├── aks/                        # ARM AKS control-plane handler
│   └── databricks/                 # ARM workspace + workspace data-plane families
│       ├── secrets/  token/  gitcredentials/  repos/  dbfs/  wsfs/
│       ├── sqlwarehouses/  pipelines/  serving/  scim/
│       └── unitycatalog/  ucstorage/
└── gcp/
    ├── gcp.go                      # gcpserver.New(Drivers{...})
    ├── compute/  networks/  gcs/  firestore/  monitoring/
    ├── cloudfunctions/  pubsub/
    ├── cloudsql/                   # REST Cloud SQL handler
    └── gke/                        # REST GKE control-plane handler

Each handler implements a two-method interface:

type Handler interface {
    Matches(r *http.Request) bool                    // detect by header/path/form
    ServeHTTP(w http.ResponseWriter, r *http.Request)
}

server.Server iterates registered handlers and dispatches to the first that claims the request. Adding a new service is one new package + one Register call. The core never changes.

Protocol detection

Each handler uses a different signal so dispatch is unambiguous within a provider:

Handler How it's detected
AWS DynamoDB X-Amz-Target: DynamoDB_20120810.* header
AWS SQS X-Amz-Target: AmazonSQS.* header
AWS MemoryDB X-Amz-Target: AmazonMemoryDB.* header
AWS Keyspaces X-Amz-Target: KeyspacesService.* header
AWS Lambda URL prefix /2015-03-31/functions
AWS EKS URL prefix /clusters
AWS RDS Form-encoded POST whose Action= is a known RDS operation (registered before EC2)
AWS Redshift Form-encoded POST whose Action= is a known Redshift operation (registered before EC2)
AWS EC2 Action=… in URL query or Content-Type: application/x-www-form-urlencoded POST
AWS CloudWatch Smithy-Protocol: rpc-v2-cbor header
AWS Bedrock URL prefix /foundation-models, /model-customization-jobs, /custom-models, /guardrails, /provisioned-model-throughput, /logging/modelinvocations, /tagResource, /untagResource, /listTagsForResource, /model-import-jobs, /model-copy-jobs, /evaluation-jobs, /evaluation-job/, /inference-profiles, /prompt-routers, /marketplace-model/endpoints, /automated-reasoning-policies, /create-foundation-model-agreement, /delete-foundation-model-agreement, /list-foundation-model-agreement-offers/, /foundation-model-availability/, or bedrock-runtime /model/{id}/{invoke,converse,converse-stream,invoke-with-response-stream,count-tokens}, /guardrail/{id}/version/{version}/apply, and /async-invoke
AWS Bedrock Agent Control plane URL prefix /agents, /knowledgebases, /flows, /prompts; runtime (registered first, matched only on POST) /agents/{id}/agentAliases/{a}/sessions/{s}/text (InvokeAgent), /knowledgebases/{id}/retrieve (Retrieve), and /retrieveAndGenerate
AWS S3 Fallback (everything else REST-shaped)
Azure (all ARM) URL begins with /subscriptions/{sub} and matches Microsoft.<Provider>/<Type>
Azure SQL ARM provider Microsoft.Sql
Azure Managed Cassandra ARM provider Microsoft.DocumentDB/cassandraClusters
Azure PostgreSQL Flexible ARM provider Microsoft.DBforPostgreSQL/flexibleServers
Azure Cosmos DB for PostgreSQL ARM provider Microsoft.DBforPostgreSQL/serverGroupsv2
Azure MySQL Flexible ARM provider Microsoft.DBforMySQL/flexibleServers
Azure AKS ARM provider Microsoft.ContainerService/managedClusters
Azure Databricks (ARM) ARM provider Microsoft.Databricks/workspaces
Azure Databricks (data plane) Non-ARM URL prefix /api/2.0/ or /api/2.1/ (workspace data plane)
Azure Databricks (host metadata) GET /.well-known/databricks-config
Azure Cosmos URL begins with /dbs/ (data plane, non-ARM)
Azure Functions invoke URL begins with /api/ (non-ARM data plane)
Azure Service Bus data plane Non-ARM URL ending in /messages or /messages/head
Azure Blob Fallback (everything else non-ARM that's REST-shaped)
GCP Compute / Networks URL prefix /compute/v1/
GCP Cloud Functions /v1/projects/.../locations/.../functions[/...]
GCP Pub/Sub /v1/projects/.../topics[/...] or /v1/projects/.../subscriptions[/...]
GCP Firestore /v1/projects/.../databases/.../documents[/...]
GCP Cloud Monitoring /v3/projects/.../
GCP Cloud SQL /v1/projects/.../{instances,operations}[/...]
GCP GKE /v1/projects/.../locations/.../{clusters,operations}[/...]
GCP GCS Fallback (/storage/v1/ and /{bucket}/{object} direct-media)
Kubernetes data plane (shared across all 3 providers) URL prefix /k8s/{cluster-uid}/. Registered on AWS, Azure, and GCP servers; cluster UID is the one minted by the matching control-plane handler on Create.

Registration order matters when handlers share a path prefix — awsserver.New / azureserver.New / gcpserver.New register more-specific handlers ahead of catch-alls (S3, Blob, GCS) so first-match-wins resolves correctly.

Coverage status

Provider Domains shipped Notes
AWS Storage, Compute (+ VPC/SG/Subnet/IGW/RT/NAT/Peering/FlowLogs/NACL/EBS/Keys/AMIs/Snapshots/Spot/LaunchTemplates), NoSQL DB, Relational DB (RDS/Aurora/Neptune/DocumentDB/Redshift), Kubernetes (EKS control plane + shared data plane), Serverless, Message Queue, Monitoring The most-mature provider — EC2 was Phase 1 of SDK-compat
Azure Storage, Compute (+ Disks/Snapshots/Images/SSHKeys), NoSQL DB, Relational DB (SQL Database, PostgreSQL Flexible Server, MySQL Flexible Server), Kubernetes (AKS control plane + shared data plane), Serverless, Message Queue (ARM only), Networking, Monitoring Data-plane Service Bus over AMQP is out of scope (use raw-HTTP REST data plane for tests)
GCP Storage, Compute (+ Disks/Snapshots/Images), NoSQL DB, Relational DB (Cloud SQL), Kubernetes (GKE control plane + shared data plane), Serverless, Message Queue, Networking, Monitoring All driven via REST (the cloud.google.com/go/* clients with option.WithEndpoint, or the auto-generated google.golang.org/api/* clients)

Kubernetes ships as two cooperating handlers: per-provider control planes (EKS / AKS / GKE — clusters + node pools + addons / Fargate / maintenance configs) and a shared in-memory data plane registered under /k8s/{cluster-uid}/. The control plane mints a UID on every cluster Create and embeds it in the kubeconfig (or Cluster.Endpoint for GKE) along with a CA that certifies the data-plane serving cert, so client-go and kubectl connect over validated TLS. The data plane behaves like a tiny always-converged cluster (minikube-like): a synchronous reconcile engine runs on every write, so Deployments/ReplicaSets/StatefulSets/DaemonSets materialize Running Pods, Services get populated Endpoints, PVCs bind, and Jobs complete — all immediately and deterministically (no controller goroutines). Core, apps, batch, networking, rbac, storage, autoscaling, discovery, and policy groups are served, with /scale and /status subresources, label/field selectors, and ?watch=true streaming (selector-filtered) so real Informer / Reflector machinery works. Data-plane lists are unpaginated (limit/continue are ignored — every list returns the full set).

The data plane now covers CustomResourceDefinitions (dynamic servable kinds), server-side apply with managedFields field ownership + conflict detection, ?dryRun=All, finalizer-gated deletion, ?limit=&continue= pagination, synthetic pods/log + PDB-gated pods/eviction, metrics.k8s.io (kubectl top) + HPA actuation, object-count ResourceQuota / LimitRange / PDB enforcement, RBAC SubjectAccessReview + NetworkPolicy evaluation, opt-in admission webhooks, watch resourceVersion resume + BOOKMARK, and a deterministic injectable clock. Remaining emulation boundaries are deliberate simplifications: no real kubelet (synthetic logs; exec/attach/portforward return a typed 501), no scheduling beyond the single synthetic node (DaemonSet nodeSelector honored; no affinity/taints), admission webhooks call out only when explicitly enabled, RBAC/NetworkPolicy are queryable rather than request-time-enforced, CronJob fires via TickCronJobs (no wall clock), and rollouts converge instantly. See docs/services.md §18 for the full resource list.

Two provider-specific services also ship as full SDK-compat handlers. AWS Bedrock covers the bedrock control plane (foundation models, customization jobs, custom models, guardrails with policy configs + versions, provisioned throughput, invocation logging, resource tagging, model import/copy/evaluation jobs, inference profiles, prompt routers, marketplace model endpoints, foundation-model agreements, and automated-reasoning policies) and the bedrock-runtime data plane (InvokeModel with family-aware response envelopes, Converse, streaming ConverseStream / InvokeModelWithResponseStream over vnd.amazon.eventstream, CountTokens, ApplyGuardrail, and async invoke). A companion AWS Bedrock Agent handler covers the bedrock-agent control plane (agents, knowledge bases, data sources, flows, prompts) and the bedrock-agent-runtime data plane (InvokeAgent streaming, Retrieve, RetrieveAndGenerate); its runtime handler registers before the control plane and matches only POST so the two never collide on the shared /agents and /knowledgebases roots. bedrock-agent coverage is intentionally scoped to this core resource lifecycle and runtime data plane — agent versioning/aliases beyond basic create, action groups, and agent collaborators are out of scope for this iteration. Azure Databricks covers the armdatabricks ARM workspace resource plus the databricks-sdk-go workspace data plane — clusters, instance pools, jobs and runs, cluster policies, libraries, permissions, secrets, tokens, git credentials, repos, DBFS, workspace notebooks/directories, SQL warehouses, pipelines, serving endpoints, SCIM identity, and Unity Catalog.

Emulation caveats (Bedrock). Long-running jobs — model customization, import, and copy jobs (evaluation jobs start InProgress) — complete synchronously in the emulator, so Get/List observe a terminal state immediately rather than polling through intermediate progress. Inference and agent responses (InvokeModel, Converse, InvokeAgent, RetrieveAndGenerate) are deterministic simulations, not real model output.

The remaining service domains (DNS, Load Balancer, Cache, Secrets, Logging, Notifications, Container Registry, Event Bus) have full driver implementations in providers/{aws,azure,gcp}/; SDK-compat handlers are added in lockstep across all 3 providers as each domain ships.

Writing your own handler

If you need a service we don't cover yet, implement the server.Handler interface in your own package and register it:

type MyHandler struct{ /* driver */ }

func (*MyHandler) Matches(r *http.Request) bool {
    // your detection logic
}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // your logic
}

srv := server.New()
srv.Register(&MyHandler{...})

The Handler interface is the only contract — no registration is needed in core CloudEmu. If the handler is generally useful, a PR to add it under server/<provider>/<service> is welcome.

Limitations

  • No signature validation. CloudEmu is a local development tool, not a security boundary. Requests are accepted regardless of AWS SigV4 / Azure AAD / GCP OAuth signatures.
  • No AMQP for Azure Service Bus. The modern azservicebus SDK uses AMQP exclusively for data plane. ARM control plane is fully supported via armservicebus; tests that need send/receive can use the raw-HTTP REST data plane.
  • GCS direct-media downloads assume path-style URLs.
  • DynamoDB / Cosmos / Firestore filters and queries support common patterns but are not full DSL parsers.
  • Pagination tokens are honored where present in the SDK contract; some list operations short-circuit to a single page.
  • Resource Graph resourceGroup. Rows expose resourceGroup derived from the resource's ARM id. Where a mock doesn't model a per-resource resource group, the id (and thus resourceGroup) falls back to default, so all such resources share one resource group — fine for SKU/tier/size-sensitive discovery and cost tests, but consumers that key on distinct resource groups should be aware. Event Hubs (microsoft.eventhub/namespaces) is not yet modeled, so its sku.tier isn't surfaced.

When a client hits an unsupported operation, the server responds with the provider's native error code so failures are easy to diagnose.