test: add integration suites that create real GCE instances - #174
Open
tas50 wants to merge 2 commits into
Open
Conversation
The unit suite stubs the Compute Engine client, so it proves the driver builds the right request and never that GCE accepts it. Nothing in CI has ever reached the API, and there was no kitchen.yml in the repository at all, so there was no way to run the driver end to end without writing one by hand. Ten suites in integration/, each creating a real instance and asserting, from inside the guest, that the driver configured it as asked: default . region . extra-disk . local-ssd . legacy-disk boot-disk-size . metadata . preemptible long-instance-and-disk-names . windows Several of them are regression tests for bugs fixed since 3.0.0 that a mocked test cannot catch, because the mock encodes the same assumption the code does: boot-disk-size covers a 10 GB request against a 20 GB image, long-instance-and-disk-names covers an instance name that left no room for its own disk name, and metadata covers the duplicate metadata keys GCE rejected outright. Assertions live in the shell provisioner rather than a verifier. The script is transferred over the driver's own transport and executed on the instance, so reaching the machine is part of every assertion, a non-zero exit fails the suite, and there is no verifier licence to satisfy. export GCE_PROJECT=my-gcp-project ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_kitchen_gce bundle exec rake integration:list bundle exec rake integration:test bundle exec rake integration:destroy Not part of rake default - these cost money. .github/workflows/integration.yml runs them weekly against main and on demand, never on a pull request: secrets are unavailable to forks and every run costs money. It authenticates with workload identity federation, so no service account key is stored. Destroy runs with if: always(), because a suite that leaks an instance on failure turns a red build into a recurring bill. Signed-off-by: Tim Smith <tim@mondoo.com>
Signed-off-by: Tim Smith <tim@mondoo.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The unit suite stubs the Compute Engine client, so it proves the driver builds the right request — never that GCE accepts it. Nothing in CI has ever reached the API. There was no
kitchen.ymlin the repository at all, so there was no way to run the driver end to end without writing one by hand first.That gap is where the bugs live. Several fixes since 3.0.0 were found by driving the thing against a real project, and every one of them is invisible to a mocked test, because the mock encodes the same assumption the code does:
:"created-by"and"created-by", rejected as duplicate keyscustom_imagesilently creating a blank disk, so a run verified nothingWhat this adds
Ten suites in
integration/, each creating a real instance and asserting on the instance that the driver configured it as asked:defaultregionregionand nozone, the driver lists the region's zones, picks one that is up, and the instance lands there.extra-diskREADY, attached, and deleted again on destroy.local-ssdlocal-ssdattached asSCRATCHat GCE's fixed 375 GB, with no size sent for it.legacy-diskdisk_size/disk_type/autodelete_diskoptions still producing a working boot disk.boot-disk-sizemetadataservice_account_scopesreaching the instance, with short aliases such asstorage-roexpanded.preemptiblepreemptible: truehonoured, and auto-restart and live migration forced off however the suite asks for them.long-instance-and-disk-nameswindowsAssertions live in the shell provisioner, not a verifier. The script is transferred over the driver's own transport and executed on the instance, so reaching the machine is part of every assertion, a non-zero exit fails the suite, and there is no verifier licence to satisfy. Everything the script needs to know travels as instance metadata — see the
regionsuite — because nothing of the local environment survives to the guest.Not part of
rake default— these cost money.CI
.github/workflows/integration.ymlruns weekly againstmainand on demand, never on a pull request: secrets are unavailable to forks and every run costs money.It authenticates with workload identity federation, exchanging GitHub's OIDC token for Google credentials, so no service account key is stored anywhere.
Three details that matter more than they look:
Destroy everythingruns withif: always(). A suite that leaks an instance on failure turns a red build into a recurring bill.concurrency: gce-integrationwithcancel-in-progress: false. A fresh project is often capped at 8–24 CPUs per region; two overlapping runs exhaust it and both fail.windowssuite just waits out its timeout on a running instance.Setup needs three repository secrets (
GCE_PROJECT,GCE_WORKLOAD_IDENTITY_PROVIDER,GCE_SERVICE_ACCOUNT) and a workload identity pool scoped to this repo, documented inintegration/README.mdalong with the roles the service account needs.One caveat worth reading before enabling this: the driver does not manage SSH keys, so
kitchen.ymlputs the public half intossh-keysmetadata itself. If the project enforces OS Login, metadata keys are ignored and nothing connects. That is called out inintegration/README.md.Testing
The suites are configuration; what can be checked without a project is that they render, that the merges come out right, and that nothing regressed:
kitchen diagnoseconfirms the merges: theregionsuite really does end up withzone:empty andregion: us-central1, and every suite that sets its ownmetadatakeeps thessh-keysentry from the top level rather than replacing it — which is the one merge that would have silently locked the runner out.Follow-ups, deliberately left out
use_private_ipneeds a bastion or an IAP tunnel to assert from CI; there is no point adding a suite that cannot connect.guest_acceleratorsneeds GPU quota, which a fresh project does not have.network_project,subnet_project) needs a second project.