Skip to content
cloudemu

Documentation

SDK-Compatible Server

Point real aws-sdk-go-v2, azure-sdk-for-go, Google Cloud, and oci-go-sdk clients at cloudemu without changing your application code

Point a real aws-sdk-go-v2, azure-sdk-for-go, cloud.google.com/go, or oci-go-sdk client at cloudemu and run production code unchanged. The HTTP servers speak each provider's actual wire protocol; the custom endpoint is the only change.

one server, four wire protocols

aws-sdk-go-v2Query · JSON · Smithy CBORazure-sdk-for-goARM JSONcloud.google.com/goRESToci-go-sdkOCI RESTcloudemuserve · :4566
FIG.The wire protocols cloudemu speaks, per provider.

Nothing to mock. No cloud accounts. No bills. The same SDK calls you'd run against real cloud APIs hit a cloudemu server and get back SDK-decodable responses. This page shows the in-process form (httptest.NewServer) for Go tests; to integrate an existing app, run the Standalone Server and override your SDK endpoint.

Why#

cloudemu's Portable API works well 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)#

package main

import (
    "context"
    "net/http/httptest"

    "github.com/aws/aws-sdk-go-v2/aws"
    awsconfig "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"

    "github.com/stackshy/cloudemu/v2"
    awsserver "github.com/stackshy/cloudemu/v2/server/aws"
)

func main() {
    ctx := context.Background()

    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,
    })

    ts := httptest.NewServer(srv)
    defer ts.Close()

    cfg, _ := awsconfig.LoadDefaultConfig(ctx,
        awsconfig.WithRegion("us-east-1"),
        awsconfig.WithCredentialsProvider(
            credentials.NewStaticCredentialsProvider("test", "test", ""),
        ),
    )

    // Use the REAL aws-sdk-go-v2 client — only the endpoint changes.
    client := s3.NewFromConfig(cfg, func(o *s3.Options) {
        o.BaseEndpoint = aws.String(ts.URL)
        o.UsePathStyle = true
    })

    client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: aws.String("my-bucket")})
    // ... full SDK API works
}

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

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,
})

// Azure SDK refuses bearer tokens over plain HTTP — use TLS.
ts := httptest.NewTLSServer(srv)

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,
})

ts := httptest.NewServer(srv)

opts := []option.ClientOption{
    option.WithEndpoint(ts.URL),
    option.WithoutAuthentication(),
    option.WithHTTPClient(ts.Client()),
}

client, _ := gcpcompute.NewInstancesRESTClient(ctx, opts...)

Quick start (OCI)#

import (
    "github.com/oracle/oci-go-sdk/v65/common"
    "github.com/oracle/oci-go-sdk/v65/objectstorage"
    "github.com/stackshy/cloudemu/v2"
    ociserver "github.com/stackshy/cloudemu/v2/server/oci"
)

ts := httptest.NewServer(ociserver.New(ociserver.DriversFrom(cloudemu.NewOCI())))

// Signatures aren't checked, so any key works.
cp := common.NewRawConfigurationProvider(
    "ocid1.tenancy.oc1..aaaaaaaacloudemulocaltenancy", "ocid1.user.oc1..test",
    "us-ashburn-1", "aa:bb", privateKeyPEM, nil)

client, _ := objectstorage.NewObjectStorageClientWithConfigurationProvider(cp)
client.Host = ts.URL

Every OCI service is on the one server, so each client's Host is the same URL. The tenancy OCID is also the root compartment. Mutations OCI runs asynchronously answer with an opc-work-request-id that the SDK's work request client can poll.

Currently supported#

AWS handlers#

ServiceOperations
S3CreateBucket, DeleteBucket, ListBuckets, PutObject, GetObject, HeadObject, DeleteObject, ListObjectsV2 (prefix, delimiter, common prefixes, continuation token), CopyObject
DynamoDBCreateTable, DeleteTable, DescribeTable, ListTables, PutItem, GetItem, DeleteItem, UpdateItem (SET/REMOVE), Query, Scan (with FilterExpression), BatchWriteItem, BatchGetItem, TransactWriteItems
EC2RunInstances, DescribeInstances (filters: instance-id, instance-type, instance-state-name, tag:*), Start/Stop/Reboot/TerminateInstances, ModifyInstanceAttribute
EC2 — VPC + NetworkingVPCs, Subnets, Security Groups + ingress/egress rules, Internet Gateways, Route Tables + Routes, NAT Gateways, VPC Peering, Flow Logs, Network ACLs
EC2 — EBS + Key PairsVolumes (Create/Delete/Describe/Attach/Detach), Key Pairs
EC2 — Snapshots + AMIs + Spot + Launch TemplatesSnapshots, Images, Spot instance requests, Launch Templates
Auto ScalingCreateAutoScalingGroup, 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
RDSCreateDBInstance, DescribeDBInstances, Modify/Delete/Start/Stop/RebootDBInstance; DB clusters (Create/Describe/Modify/Delete/Start/Stop); DB + cluster snapshots + restore (Aurora, Neptune, DocumentDB engines)
RedshiftCreateCluster, DescribeClusters, Modify/Delete/RebootCluster; cluster snapshots (Create/Describe/Delete) + RestoreFromClusterSnapshot
EKSClusters (Create/Describe/List/UpdateConfig/UpdateVersion/Delete); managed node groups; Fargate profiles; addons. Issues kubeconfigs pointing at the shared Kubernetes data plane
IAMUsers, groups, roles, managed policies (+ versions) & attach/detach, access keys, instance profiles
ECRCreateRepository, DescribeRepositories, DeleteRepository; PutImage, ListImages, DescribeImages, BatchDeleteImage
Bedrock (+ bedrock-runtime)ListFoundationModels, GetFoundationModel; custom models, guardrails, provisioned throughput, invocation logging; runtime InvokeModel, Converse (deterministic echo responses)
SageMaker (+ sagemaker-runtime)Models, endpoint configs, endpoints, inference components; training/tuning/transform/AutoML jobs; registry, Studio, notebooks, Feature Store, pipelines; runtime InvokeEndpoint / InvokeEndpointAsync
Resource Explorer 2CreateView, DeleteView, ListViews, GetView, Search, ListResources, ListIndexes, GetIndex (service: / tag.k:v / region: filters)
Resource Groups Tagging APIGetResources, GetTagKeys, GetTagValues, TagResources, UntagResources
Route 53 (DNS)Hosted zones (Create/Get/List/Delete); resource record sets (ChangeResourceRecordSets, ListResourceRecordSets); health checks
ELBv2 (Load Balancer)Load balancers, target groups, listeners, rules; RegisterTargets/DeregisterTargets, DescribeTargetHealth; Modify/DescribeLoadBalancerAttributes
ElastiCache (Cache)Cache clusters + replication groups + subnet groups (Create/Describe/Modify/Delete)
Secrets ManagerCreateSecret, GetSecretValue, PutSecretValue, DescribeSecret, ListSecrets, ListSecretVersionIds, DeleteSecret
CloudWatch LogsLog groups + log streams (Create/Delete/Describe); PutLogEvents, GetLogEvents, FilterLogEvents; metric filters
SNS (Notification)CreateTopic, DeleteTopic, ListTopics, Subscribe, Unsubscribe, ListSubscriptions, Publish
EventBridge (Event Bus)Event buses (Create/Delete/List); PutRule, DeleteRule, Enable/DisableRule, ListRules; PutTargets, RemoveTargets, ListTargets; PutEvents
ECSClusters, task definitions, services, tasks (register/run/list/describe/update/delete)
SSM (Parameter Store)PutParameter, GetParameter(s), GetParametersByPath, DescribeParameters, DeleteParameter(s), label/history
STSGetCallerIdentity, AssumeRole, GetSessionToken (identity reported by the emulator)
Keyspaces (Cassandra)Keyspaces + tables (Create/Get/List/Update/Delete) — AWS JSON 1.0
MemoryDB (Redis/Valkey)Clusters (Create/Describe/Update/Delete, FailoverShard), ACLs + users, subnet/parameter groups — AWS JSON 1.1
Network FirewallFirewalls, firewall policies, rule groups (Create/Describe/Update/Delete)

Azure handlers#

All speak ARM JSON over HTTPS unless noted.

ServiceARM provider / operations
Virtual MachinesMicrosoft.Compute/virtualMachines — CreateOrUpdate, Get, List, Delete, start, powerOff, restart
Disks / Snapshots / Images / SSH Public KeysMicrosoft.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 NetworkMicrosoft.Network/virtualNetworks — CRUD + subnets
Azure Monitormicrosoft.insights/metricAlerts and metric data ingest/read
FunctionsMicrosoft.Web/sites (Function Apps): CreateOrUpdate, Get, List, Delete + non-ARM /api/{name} invoke
Service BusMicrosoft.ServiceBus/namespaces[/queues] ARM CRUD + raw-HTTP REST data plane (POST /{ns}/{queue}/messages, DELETE /messages/head)
SQL DatabaseMicrosoft.Sql/servers + .../databases — PUT/GET/PATCH/DELETE/LIST
PostgreSQL / MySQL Flexible ServerMicrosoft.DBforPostgreSQL/flexibleServers, Microsoft.DBforMySQL/flexibleServers — CRUD + start/stop/restart
AKSMicrosoft.ContainerService/managedClusters — CreateOrUpdate/Get/List/UpdateTags/Delete/RotateCertificates; agent pools; maintenance configs. Issues kubeconfigs for the shared Kubernetes data plane
IAMMicrosoft.Authorization — role assignments + role definitions
ACRMicrosoft.ContainerRegistry/registries — registries + repositories + tags
Databricks (ARM + data plane)Microsoft.Databricks/workspaces control plane + workspace REST data plane (clusters, jobs, runs, instance pools, policies, libraries, permissions, DBFS, repos, secrets, Unity Catalog, SQL warehouses, …)
Resource GraphPOST /providers/Microsoft.ResourceGraph/resources — KQL subset over the Resources table (where type ==, in~, location, tags[…], limit/take)
Azure DNSMicrosoft.Network/dnsZones + record sets — CreateOrUpdate/Get/List/Delete
Load BalancerMicrosoft.Network/loadBalancers — CreateOrUpdate/Get/List/Delete + rules, probes, backend pools
Azure Cache for RedisMicrosoft.Cache/redis — CreateOrUpdate/Get/List/Delete + keys
Key Vault (Secrets)Microsoft.KeyVault/vaults control plane + secrets data plane (Set/Get/List/Delete versions)
Log AnalyticsMicrosoft.OperationalInsights/workspaces + data-plane ingest/query
Notification HubsMicrosoft.NotificationHubs/namespaces[/notificationHubs] — CRUD + send
Event GridMicrosoft.EventGrid/topics + event subscriptions; event publish
Azure AIMicrosoft.CognitiveServices/accounts (AI Foundry / AI Studio) — accounts + deployments
Azure AI SearchMicrosoft.Search/searchServices — CreateOrUpdate/Get/List/Delete
Table Storage (data plane)Tables + entities — Create/Query/Insert/Merge/Delete
Cosmos DB for PostgreSQLMicrosoft.DBforPostgreSQL/serverGroupsv2 (Citus) — CRUD
Managed CassandraMicrosoft.DocumentDB/cassandraClusters[/dataCenters] — CRUD

GCP handlers#

All speak REST + JSON.

ServiceOperations
Compute EngineInstances + Disks + Snapshots + Images: insert/get/list/delete with LRO envelopes
NetworksVPCs, Subnetworks, Firewalls, Routes
Cloud Storage (GCS)Buckets + Objects: create/get/list/delete, upload, download, copy
FirestoreDocuments + Collections via :commit, :batchGet, :runQuery
Cloud MonitoringTime-series ingest/read, alert policies
Cloud Functions v1Create (LRO), Get, List, Delete (LRO), :call (sync invoke)
Pub/SubTopics + Subscriptions lifecycle, :publish, :pull, :acknowledge
Cloud SQLInstances insert/get/list/update/delete, restart, restoreBackup; backup runs; operations (MySQL/PostgreSQL/SQL Server)
GKEClusters (Create/Get/List/Update/Delete) + config setters; node pools (Create/Get/List/Update/Delete, SetSize/Autoscaling/Management, Rollback); operations. Issues kubeconfigs for the shared Kubernetes data plane
IAMService accounts + roles (getIamPolicy / setIamPolicy bindings)
Artifact RegistryRepositories + Docker images
Vertex AIModels, endpoints (Deploy/Undeploy), datasets, jobs, pipelines, Feature Store, Vector Search; runtime GenerateContent (Gemini), CountTokens, Predict, RawPredict
Cloud Asset InventorysearchAllResources, searchAllIamPolicies, exportAssets, batchGetAssetsHistory, assets.list, feeds CRUD
Cloud DNSManaged zones + resource record sets — create/get/list/delete + changes
Cloud Load BalancingBackend services, URL maps, target proxies, forwarding rules, health checks
Memorystore (Cache)Redis instances — create (LRO)/get/list/update/delete
Secret ManagerSecrets + versions — create/get/list/delete, :access, :addVersion
Cloud LoggingLog entries (entries:write, entries:list), log buckets/sinks
FCM (Notification)projects/*/messages:send — send to token / topic / condition
Eventarc (Event Bus)Triggers + channels — create (LRO)/get/list/delete
AlloyDBClusters + instances — create (LRO)/get/list/delete
BigtableInstances, clusters, tables — admin create/get/list/delete

OCI handlers#

All speak OCI's REST + JSON, with opc-request-id on every response and opc-next-page paging.

ServiceOperations
IdentityCompartments (with subtree listing and moves), users, groups, group memberships, policies
VCNVCNs, subnets, security lists, network security groups and rules, route tables, DHCP options, internet/NAT/service gateways, DRGs and attachments, local and remote peering, VNICs, private and public IPs
Compute and Block VolumeInstances (launch, actions, update, terminate), shapes, images, block and boot volumes, attachments, backups, volume groups, instance configurations and pools
Object StorageNamespaces, buckets, objects (multipart, versioning, copy), pre-authenticated requests, retention rules, lifecycle policies
NoSQLTables from DDL, indexes, rows with conditional writes and TTL, SQL queries
VaultVaults, keys and key versions, secrets and versions, the secret-bundle data plane
LoggingLog groups, logs, ingestion, search
MonitoringMetric ingestion, listing and summaries, alarms
NotificationsTopics, subscriptions, message publishing
Work requestsPolling for every asynchronous mutation above

Vault's KMS crypto operations (encrypt, decrypt, sign and so on) return 501 for now.

Any operation not in these tables returns 501 Not Implemented or the provider's native error code (UnknownOperation, NotImplemented, NOT_FOUND).

Kubernetes data plane (shared across providers)#

EKS, AKS, and GKE each issue kubeconfigs that point at a single shared in-memory Kubernetes API server (kubernetes.NewAPIServer(), passed as K8sAPI to each provider's Drivers). Real client-go / kubectl drive it end-to-end: Namespace, Pod, Service, ConfigMap, Secret, ServiceAccount, Deployment support Create/Get/List/Update/Delete/Patch (JSON-merge) + Watch streaming; Endpoints are read-only. API groups core/v1 and apps/v1. See the Kubernetes service page for what's intentionally out of scope (no scheduler, controllers, RBAC, or PV/PVC).

Multi-region isolation (AWS)#

The AWS wire server routes every request to a per-region backend, keyed by the region in the caller's SigV4 credential scope (Credential=AKID/DATE/REGION/SERVICE/aws4_request). A region's provider is built lazily on its first request and cached from then on; an unsigned request, or one whose scope names the server's default region, routes to the pre-built default backend — so a single-region workload never touches the mux at all.

  • Regional state is isolated per region. DynamoDB tables, SQS queues, EC2 instances/VPCs, Lambda functions, and every other regional service each get a fresh, independent backend per region.
  • Global services are shared across every region. IAM, STS (one session store, so an ASIA credential minted in one region verifies in another), Route 53, CloudFront, and Global Accelerator all read and write the same underlying state no matter which region's endpoint a request hits — mirroring real AWS, where these services aren't regional. The S3 bucket-name namespace is shared the same way, so bucket names stay globally unique across regions even though each region's S3 backend is otherwise independent.
  • Cost and Resource Explorer aggregate across every region that's been touched so far, not just the default one.

The testable behavior: a resource created against a us-east-1-scoped request is invisible to a list call scoped to eu-west-1 — and vice versa — while an IAM user, role, or hosted zone created in either region is visible from both.

How it works#

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 + dispatcher (~80 LOC)
├── wire/
│   ├── wire.go                  # shared XML/JSON helpers
│   ├── awsquery/                # AWS query-protocol decoder + XML envelope
│   ├── azurearm/                # ARM URL parser + JSON helpers + error envelope
│   ├── gcprest/                 # GCP REST URL parser + Operation LRO helpers
│   └── ocirest/                 # OCI REST helpers: opc-request-id, paging, errors
├── aws/
│   ├── aws.go                   # awsserver.New(Drivers{...})
│   ├── s3/  ec2/  dynamodb/  lambda/  sqs/  cloudwatch/  rds/  redshift/
│   ├── eks/  iam/  ecr/  ecs/  ssm/  sts/  bedrock/  sagemaker/
│   ├── bedrockagent/  bedrockagentruntime/  keyspaces/  memorydb/  networkfirewall/
│   ├── route53/  elbv2/  elasticache/  secretsmanager/  cloudwatchlogs/  sns/  eventbridge/
│   └── resourceexplorer2/  resourcegroupstaggingapi/
├── azure/
│   ├── azure.go                 # azureserver.New(Drivers{...})
│   ├── virtualmachines/  disks/  snapshots/  images/  sshpublickeys/
│   ├── blobstorage/  cosmosdb/  cosmosaccount/  vnet/  monitor/  functions/  servicebus/  queue/
│   ├── sql/  postgresflex/  mysqlflex/  cosmospostgresql/  managedcassandra/  aks/  iam/  acr/
│   ├── dns/  loadbalancer/  cache/  keyvault/  loganalytics/  notificationhubs/  eventgrid/
│   ├── ai/  search/  tablestorage/  storageaccount/  subscriptions/  resourcegroups/
│   ├── databricks/              # ARM + workspace data plane (dbfs, repos, uc, …)
│   └── resourcegraph/
└── gcp/
    ├── gcp.go                   # gcpserver.New(Drivers{...})
    ├── compute/  vpc/  gcs/  firestore/  monitoring/  lro/  servicenetworking/
    ├── cloudfunctions/  pubsub/  cloudsql/  gke/  iam/  alloydb/  bigtable/
    ├── clouddns/  loadbalancer/  memorystore/  secretmanager/  cloudlogging/  fcm/  eventarc/
    └── artifactregistry/  vertexai/  cloudasset/
└── oci/
    ├── oci.go                   # ociserver.New(ociserver.DriversFrom(cloudemu.NewOCI()))
    ├── identity/  vcn/  compute/  objectstorage/  nosql/  vault/
    └── logging/  monitoring/  notifications/  workrequest/

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:

HandlerHow it's detected
AWS DynamoDBX-Amz-Target: DynamoDB_20120810.* header
AWS SQSX-Amz-Target: AmazonSQS.* header
AWS LambdaURL prefix /2015-03-31/functions
AWS EC2Action=… in URL query or Content-Type: application/x-www-form-urlencoded POST
AWS CloudWatchSmithy-Protocol: rpc-v2-cbor header
AWS S3Fallback (everything else REST-shaped)
Azure (all ARM)URL begins with /subscriptions/{sub} and matches Microsoft.<Provider>/<Type>
Azure CosmosURL begins with /dbs/ (data plane, non-ARM)
Azure Functions invokeURL begins with /api/ (non-ARM data plane)
Azure Service Bus data planeNon-ARM URL ending in /messages or /messages/head
Azure BlobFallback (everything else non-ARM REST-shaped)
GCP Compute / NetworksURL 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 GCSFallback (/storage/v1/ and /{bucket}/{object} direct-media)

The newer handlers follow the same per-provider scheme: AWS RDS/Redshift use the query protocol (Action=…), Bedrock/SageMaker/Resource Explorer dispatch on X-Amz-Target or their REST path prefix; Azure SQL/Postgres/MySQL/AKS/ACR/Resource Graph match their Microsoft.<Provider>/<Type> ARM path, and Databricks data-plane calls match the /api/2.x/ prefix; GCP Cloud SQL, GKE, Vertex AI, and Cloud Asset match their REST path prefixes.

Registration order matters when handlers share a path prefix — the provider factories register more-specific handlers ahead of catch-alls (S3, Blob, GCS, Firestore) so first-match-wins resolves correctly.

Coverage status#

ProviderDomains shipped
AWSStorage, Compute (full VPC stack), Database (+ Keyspaces/MemoryDB), Relational DB (RDS/Aurora/Redshift), Serverless, Kubernetes (EKS + data plane), Container Orchestration (ECS), Message Queue, Monitoring, Logging, DNS, Load Balancer, Cache, Secrets, Notification, Event Bus, IAM/STS, Parameter Store (SSM), Container Registry, Network Firewall, Resource Discovery, Bedrock, SageMaker
AzureStorage (+ Table Storage), Compute (+ Disks/Snapshots/Images/SSHKeys), Database (+ Managed Cassandra), Relational DB (SQL + Postgres/MySQL Flex + Cosmos-for-PostgreSQL), Serverless, Kubernetes (AKS + data plane), Message Queue (ARM + REST data plane), Networking, Monitoring, Logging, DNS, Load Balancer, Cache, Secrets (Key Vault), Notification, Event Bus, IAM, Container Registry, Resource Discovery, Azure AI, Azure AI Search, Databricks
GCPStorage, Compute (+ Disks/Snapshots/Images), Database (+ Bigtable), Relational DB (Cloud SQL + AlloyDB), Serverless, Kubernetes (GKE + data plane), Message Queue, Networking, Monitoring, Logging, DNS, Load Balancer, Cache, Secrets, Notification, Event Bus, IAM, Container Registry, Resource Discovery, Vertex AI
OCIStorage (Object Storage), Compute (+ Block Volume), Database (NoSQL), Networking (VCN), Monitoring, Logging, Secrets (Vault), Notification, IAM (Identity), Work Requests

Every core service domain now ships an SDK-compat handler across AWS, Azure, and GCP — including DNS, Load Balancer, Cache, Secrets, Logging, Notification, and Event Bus, which were the last cross-cloud domains to land. OCI covers a smaller set; a service it doesn't emulate yet (Functions, Queue, Load Balancer, DNS, Container Registry, Cache, Events, MySQL/PostgreSQL, OKE) has no handler. New services continue to drop in as self-contained handler packages without touching the core.

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#

  • Signature validation is off by default. With no flags, requests are accepted regardless of AWS SigV4 / Azure AAD / GCP OAuth signatures, so local development just works. Opt in with --enforce-auth — see Auth Enforcement for exactly what's verified per provider and its non-guarantees.
  • 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.

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

On this page

On this page