Skip to content

Add a simulated dev/test environment and simulator-based e2e CI - #105

Draft
vishesh92 wants to merge 1 commit into
mainfrom
add-simulator-e2e-environment
Draft

Add a simulated dev/test environment and simulator-based e2e CI#105
vishesh92 wants to merge 1 commit into
mainfrom
add-simulator-e2e-environment

Conversation

@vishesh92

@vishesh92 vishesh92 commented Aug 31, 2026

Copy link
Copy Markdown
Member

Fixes #4

What this does

Issue #4 asked for documentation on running kube-apiserver and
cloudstack-simulator locally, "preferring containers so automated test
workloads can be implemented later." This does both halves.

make e2e-up brings up a complete, unmocked stack in about seven minutes: a
kind cluster, the CloudStack simulator with its advanced zone deployed,
CloudStack VMs matching the kind nodes, and the CCM built from the checkout.
docs/development.md walks through the same steps manually, so the environment
can be understood and debugged rather than just invoked.

make e2e-up
kubectl create deployment web --image=nginx
kubectl expose deployment web --port=80 --type=LoadBalancer
kubectl get svc web -w      # EXTERNAL-IP arrives from 192.168.2.0/24
make test-e2e
make e2e-down

Why it is worth the files

EnsureLoadBalancer, UpdateLoadBalancer and EnsureLoadBalancerDeleted had
no tests. Only their helpers did, and those mostly pass gomock.Any() for
request parameters, so what the CCM actually sends to CloudStack was largely
unverified. The new suite is 15 tests covering load balancer lifecycle, node
initialization, annotations and session affinity, and the VPC/network ACL path
against a real management server.

It lives in test/e2e behind the e2e build tag, so it stays out of
make test and go build ./..., and it needs no new module dependencies.

Two bugs this found

Both affect anyone running the CCM against a CloudStack project, and both
are fixed here:

  • updateNetworkACL fetched the network and its ACL list without project
    scoping. On a VPC owned by a project, every LoadBalancer service failed with
    error fetching Network with ID: ... No match found and never received an
    ingress address.
  • getNetworkIDFromIPAddress had the same omission on two calls, which breaks
    load balancer deletion for projects.

The fix is four added cloudstack.WithProject(...) arguments, matching what
the neighbouring call sites already do. Note this is distinct from the
could not find network case in the Troubleshooting section, which is in
associatePublicIPAddress and was already scoped correctly.

CI

.github/workflows/e2e-simulator.yml runs on pull requests and pushes to
main, as a 2x2 matrix:

Kubernetes CloudStack
v1.37.0, v1.36.4 4.22.1.0, 4.20.2.0

The CloudStack axis buys branch coverage, not just version coverage: 4.22+
updates a rule's CIDR list in place, 4.20 deletes and recreates it. A shared
build job compiles the image once and the four cells run in parallel, so the
workflow takes roughly as long as a single run (~15 minutes). Failures upload
simulator logs, CCM logs, node and service dumps, and CloudStack-side state.

Not added as a required check in .asf.yaml yet — worth letting it prove
itself stable first.

Known limitation

kind starts kubelet with --provider-id=kind://..., and Kubernetes only lets a
provider ID be set once, so the CCM never assigns
external-cloudstack://<uuid> in this environment. TestNode_ProviderID
detects that, logs the value it would have assigned, and reports itself as
skipped, so the gap stays visible instead of quietly passing. It is called out
in the docs.

Notes for reviewers

  • The README's Debugging section moved to docs/development.md, where the
    launch.json snippet now points at the harness-generated
    cloud-config-host and kubeconfig. The README keeps a pointer to it.
  • The stale cloudstack/simulator Docker Hub link is corrected to
    apache/cloudstack-simulator.
  • .gitignore now covers the local cloud-config, cmk-config and
    kube-config files. They hold live credentials and were previously
    untracked but not ignored.
  • Mock expectations in cloudstack_loadbalancer_test.go gained a
    gomock.Any() argument for the new variadic project option, matching the
    existing project-scoped call sites.

Testing

Ran the full harness locally against apache/cloudstack-simulator:

  • 12/13 phase-1 e2e tests pass, 1 informative skip (provider ID, above)
  • both VPC-phase tests pass, and failed before the project-scoping fix
  • make test, golangci-lint run and go build ./... are clean
  • artifact collection and teardown verified; teardown leaves nothing behind

The CCM's k8s.io/* v0.24 libraries worked fine against a v1.37 API server.

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings August 31, 2026 08:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov-commenter

codecov-commenter commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.19048% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.56%. Comparing base (151452f) to head (f5f9f69).

Files with missing lines Patch % Lines
cloudstack_loadbalancer.go 70.58% 4 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #105      +/-   ##
==========================================
+ Coverage   50.05%   50.56%   +0.50%     
==========================================
  Files           4        4              
  Lines         975      981       +6     
==========================================
+ Hits          488      496       +8     
+ Misses        473      471       -2     
  Partials       14       14              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from 9e0a52b to b3a11f1 Compare August 31, 2026 10:19
Copilot AI review requested due to automatic review settings August 31, 2026 10:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from b3a11f1 to 193dabc Compare September 1, 2026 04:54
Copilot AI review requested due to automatic review settings September 1, 2026 04:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 4 comments.

Suppressed comments (1)

cloudstack_loadbalancer.go:487

  • The netErr branch returns the wrong error variable (it returns err from the previous GetPublicIpAddressByID call). If the first call succeeded (err==nil) but GetNetworkByID fails, this currently returns a nil error and masks the failure.
		network, _, netErr := cs.client.Network.GetNetworkByID(ip.Associatednetworkid, cloudstack.WithProject(cs.projectID))
		if netErr != nil {
			klog.Errorf("Failed to fetch the network for id: %v", ip.Associatednetworkid)
			return "", err
		}

Comment thread cloudstack_loadbalancer.go
Comment thread test/e2e/framework.go
Comment thread test/e2e/vpc_test.go Outdated
Comment thread .github/workflows/e2e-simulator.yml
@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from 193dabc to f656173 Compare September 1, 2026 07:26
Copilot AI review requested due to automatic review settings September 1, 2026 07:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 2 comments.

Comment thread hack/e2e/10-simulator-up.sh Outdated
Comment thread test/e2e/framework.go Outdated
@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from f656173 to 98f7d4a Compare September 1, 2026 09:22
Copilot AI review requested due to automatic review settings September 1, 2026 09:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 5 comments.

Comment thread Makefile Outdated
Comment thread test/e2e/annotations_test.go Outdated
Comment thread test/e2e/loadbalancer_test.go
Comment thread test/e2e/framework.go Outdated
Comment thread test/e2e/framework.go
Copilot AI review requested due to automatic review settings September 1, 2026 09:59
@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from 98f7d4a to 0ac220a Compare September 1, 2026 09:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 6 comments.

Comment thread test/e2e/framework.go Outdated
Comment thread test/e2e/annotations_test.go
Comment thread cloudstack_loadbalancer.go
Comment thread cloudstack_loadbalancer.go
Comment thread Makefile
# environment, so `make test-e2e` reaches the same simulator `make e2e-up`
# published rather than assuming the default port.
SIM_HOST_PORT ?= 8080
CS_API_URL ?= http://localhost:$(SIM_HOST_PORT)/client/api
Comment thread Makefile

# Simulator-based e2e environment; see docs/development.md
e2e-up:
hack/e2e/up.sh
Copilot AI review requested due to automatic review settings September 1, 2026 10:59
@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from 0ac220a to 80f3681 Compare September 1, 2026 10:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.

Comment thread test/e2e/framework.go
Comment thread hack/e2e/90-collect-artifacts.sh
The repository had no way to exercise the CCM end to end. The only
"run against real CloudStack" hook was configFromEnv() in
cloudstack_test.go, which skips unless CS_API_URL and friends are set,
and nothing set them. As a result EnsureLoadBalancer,
UpdateLoadBalancer and EnsureLoadBalancerDeleted -- the three functions
holding nearly all of the load balancer branching -- had no test
coverage at all, and the README pointed at a Docker Hub image
(cloudstack/simulator) that no longer exists.

Add hack/e2e, which brings up a CloudStack simulator, deploys its
advanced zone, mints admin API keys, creates a kind cluster and
deploys CloudStack VMs matching its nodes, then runs the CCM against
both. CloudStack calls go through cmk, so the scripts run the same
commands the documentation tells you to run, and cmk's own async job
handling removes any need to poll queryAsyncJobResult.
docs/development.md walks through the same steps by hand so the
environment is understandable rather than magic.

Add a Go e2e suite under test/e2e covering load balancer lifecycle,
node initialization, service annotations and the VPC/network ACL path.
It is behind the e2e build tag, so it stays out of `make test` and
`go build ./...`, and it needs no new module dependencies.

Run all of it in CI as a matrix of the latest two Kubernetes minors
against CloudStack 4.22.1.0 and 4.20.2.0. The CloudStack axis is not
only version coverage: 4.22 and later update a load balancer rule's
CIDR list in place while earlier releases delete and recreate the
rule, so both branches are exercised. Cells run in parallel and share
a single image build, and the simulator and kind node images are
cached between runs, so the workflow costs about as much wall-clock
as a single run.

Fix two latent bugs in the load balancer path that the new suite
exposed, both affecting CloudStack projects. updateNetworkACL fetched
the network and its ACL list without the project, so every
LoadBalancer service on a VPC owned by a project failed with "error
fetching Network with ID" and never got an ingress address.
getNetworkIDFromIPAddress had the same omission, breaking load
balancer deletion for projects; it also reported a failed network
lookup as success by returning the wrong error variable, and guarded
on Networkid while looking up Associatednetworkid. Either could hand
the caller an empty network ID, which GetNetworkByID does not reject
but looks up as an unfiltered network list, so it could resolve to an
arbitrary network instead of failing.

Also add the local cloud-config, cmk-config and kube-config files to
.gitignore. They hold live credentials and were previously untracked
but not ignored.

Fixes #4

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 1, 2026 11:23
@vishesh92
vishesh92 force-pushed the add-simulator-e2e-environment branch from 80f3681 to f5f9f69 Compare September 1, 2026 11:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated no new comments.

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.

[OLD] Document how to run a fully simulated dev/test environment

3 participants