Skip to content

Add Topology CLI: net can-connect / trace (#335 P2) - #340

Merged
thzgajendra merged 2 commits into
stackshy:developmentfrom
thzgajendra:feat/topology-cli
Aug 8, 2026
Merged

Add Topology CLI: net can-connect / trace (#335 P2)#340
thzgajendra merged 2 commits into
stackshy:developmentfrom
thzgajendra:feat/topology-cli

Conversation

@thzgajendra

Copy link
Copy Markdown
Collaborator

Objective / Issue

First P2 differentiator of the "minikube for cloud resources" roadmap (#335). cloudemu already has a network-reachability engine (features/topology: CanConnect/TraceRoute) that evaluates security groups, routes, NACLs, and VPC peering — but nothing exposed it. This surfaces it as a CLI so users can check, locally, whether one instance can actually reach another. No other local emulator (LocalStack, moto, minikube) does network reachability.

What we found

  • The engine is complete and tested; it reads live compute/networking/DNS driver state.
  • The admin control plane already fronts every provider port and does atomic rebuilds — the natural place to expose read-only topology queries against the live state.
  • Wire gap (important): instances launched via the API got a SubnetId but no VpcId — so topology saw every instance in one empty VPC (can-connect trivially "same VPC", trace failed "no route table for VPC "). The feature would only work for in-process setups, not the aws CLI / Terraform workflow it's meant for.

How we fixed it / How it works

  • serve builds the AWS topology engine (EC2/VPC/Route53) in rebuild() and serves GET /_cloudemu/net/can-connect and /net/trace. admin.NewControl gains an optional extra handler these routes plug into (unknown /_cloudemu/* → extra, else 404).
  • CLI: cloudemu net can-connect <A> <B> [--port] [--protocol] and net trace <A> <destIP>, human output or --json; clear errors for daemon-down / --admin=false / aws-not-running / instance-not-found.
  • EC2 subnet→VPC resolver: wire RunInstances now resolves an instance's VPC from its --subnet-id (mirrors the existing RDS SubnetResolver), wired via p.EC2.SetSubnetResolver(p.VPC). This is what makes the feature usable through Terraform / the aws CLI.
sequenceDiagram
    actor U as You
    participant CLI as cloudemu net
    participant S as serve (daemon)
    participant E as topology engine
    U->>CLI: net can-connect i-web i-db --port 5432
    CLI->>S: GET /_cloudemu/net/can-connect?from&to&port
    S->>E: CanConnect (VPC reachability, SG egress+ingress)
    E-->>S: Allowed? + reason + path
    S-->>U: YES/NO + hop path
Loading

Alternatives not taken

  • In-process only / no wire fix — leaves the feature unusable via Terraform/CLI; the subnet resolver is the minimal change that makes it real.
  • Add default allow-all egress to created SGs to match real AWS — a vpc test enshrines the no-default-egress model, so changing it is out of scope; documented instead.

Docs / Tests / Playground

  • Docs: docs/standalone-server.md — network-reachability section (usage, aws-only, egress nuance, --subnet-id note).
  • Tests: admin extra delegation; net handler validation/error paths; EC2 subnet→VPC resolver round-trip; net CLI helpers. Engine itself already thoroughly tested.

Test plan

  • go test -race ./providers/aws/ec2/... ./features/topology/... ./server/admin/... ./cmd/cloudemu/...
  • Full local CI: gofmt / build (incl. GOOS=windows) / vet / go test ./... / tidy / golangci-lint = clean (CodeQL: only pre-existing findings, none in changed files).
  • Live E2E via cloudemu start + real aws CLI on default ~/.cloudemu: create VPC/subnet/2 SGs/2 instances → can-connect NO (with blocking reason) → open web egress + db ingress → YES + hop pathtrace shows route-table/local hops → --json works.

Risk & Rollback

  • Low: the net endpoints are read-only; gated on --admin + the aws provider. The EC2 resolver only sets a previously-empty field (more correct, matches AWS). Rollback = revert.

Conclusion

cloudemu net can-connect / trace answers "will my security groups and routes actually let A reach B?" locally — the standout capability no competitor offers.

Follow-ups (#335): GCP/Azure topology; a default-egress fidelity toggle; more P2 items (cost preview, IAM enforcement, MCP server).

Surface the network-reachability engine so users can check, locally, whether
their security groups, routes, and peering actually let one instance reach
another — a capability no other local cloud emulator has.

- serve: builds the AWS topology engine (EC2/VPC/Route53) in rebuild() and
  serves GET /_cloudemu/net/can-connect and /net/trace; admin.NewControl gains
  an optional extra handler that these routes plug into.
- CLI: `cloudemu net can-connect <A> <B> [--port] [--protocol]` and
  `net trace <A> <destIP>`, with human output or --json.
- EC2: wire RunInstances to resolve an instance's VPC from its --subnet-id
  (mirrors the existing RDS SubnetResolver), so instances created via the API
  carry the VPCID that reachability analysis and trace depend on. Without this
  the feature only works for in-process setups, not the aws CLI / Terraform.

AWS-only (VPC/SG/route concepts). Note: cloudemu security groups have no
implicit allow-all egress, so can-connect needs an explicit egress rule.

@NitinKumar004 NitinKumar004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — topology CLI

Deep-reviewed in an isolated worktree at the PR head; gate green (build + GOOS=windows go build ./cmd/cloudemu / vet / go test -race ./providers/aws/ec2/... ./providers/aws/vpc/... ./features/topology/... ./server/admin/... ./cmd/cloudemu/... ok all / gofmt clean).

What stood out:

  • The EC2 subnet→VPC resolver is the right fix and follows the existing RDS/ElastiCache SetSubnetResolver pattern. Blast radius is small and I checked it: VPCID was already an instanceData field (already surfaced by DescribeInstances), and DeleteVPC gates on attached ENIs — not instances-by-VPCID (separate mocks) — so teardown behavior is unchanged. Populating it just feeds the topology engine + vpc-id filtering, which is strictly more correct and is what makes the feature usable through the real CLI/Terraform.
  • admin extra handler — clean delegation of unknown /_cloudemu/* paths, nil-safe (→404), only mounted when --admin. Tested.
  • netEngine concurrency is correct — read under rebuildMu, written under the same lock in rebuild(), and the query runs on the local eng outside the lock, matching the established seed/snapshot convention. No race.
  • net CLI — good validation, sensible defaults (port 0 / protocol tcp), reuses the established daemon-down/admin-off/timeout helpers with clean status→error mapping; endpoints are read-only.
  • Mirror rule — aws-only, explicitly scoped (GCP/Azure topology is a documented follow-up).

One non-blocking Low: gosec flags G704 "SSRF via taint" on net.go:184,189, but this is a local CLI calling its own daemon (URL from our own endpoints file + a hardcoded path) — no attacker-controlled destination. Same newer-gosec version drift as the earlier findings; a //nolint:gosec documents it if your pinned linter ever surfaces it.

Clean, well-scoped feature with a correct wire fix. LGTM.

…to feat/topology-cli

# Conflicts:
#	cmd/cloudemu/serve.go
#	docs/standalone-server.md
@thzgajendra
thzgajendra merged commit e29f48a into stackshy:development Aug 8, 2026
12 checks passed
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.

2 participants