Unable to write to $HOME/.pulumi/credentials.json during bazel test

The Problem

You can add it to your ~/.bazelrc (it needs the path to be absolute)

From our integration tests, we run pulumi stack output (or in some cases pulumi up) through the automation API before we run the tests so that we can

  • Confirm that the stack is up
  • Get the relevant parameters (actual names of lambdas / dynamo db tables etc.)

However, since we use bazel for our tests, we ran into a small problem in that Bazel (rightly) prevents the tests from writing to anything outside the sandbox. This restrictions results in this error

error: open /home/<username>/.pulumi/credentials.json: read-only file system
Continue reading

Separating out integration tests for golang in Bazel

Why

There are many kinds of automated tests and two main kinds are integration tests and unit tests.

Unit tests are designed to run as fast as possible, so any slower processes like databases are mocked out. While super helpful and powerful in terms of providing confidence in the software, it should be only one part of the testing strategy.

Integration tests, as is implied runs tests of the different part of the software integrated together. Technically speaking, you can still mock out the database and other slower layers to keep it running quickly. However, there is value in including a database or other slower services in the process to test as them in an automated fashion.

What this does mean though, is that you want to be able to run only the unit tests or run the integration tests as well. You might also want to have smoke tests, which are run on your live production environment.

How

You could define a separate target in your BUILD file with the unit tests and let gazelle automatically build your default test target with all the tests. I found this frustrating to use as I had to keep tweaking the dependencies manually whenever anything changed (which happened often)

Tagging

The easiest way to achieve this for golang and bazel is to tag your source code files. You can do this by adding the following to the top of your integration test files

Continue reading

Bazel + Pulumi Automation API. Deploying an inline stack along with Pulumi.[stack].yaml

I believe in CI/CD/CD as in Continuous, integration, delivery and deployment. As part of this, I am setting up a workflow where on merge to develop (or main/trunk), the deployment is triggered automatically. Pulumi deploys the current state of code and infrastructure through GitHub actions and OpenID Connect(OIDC) as part of the GitHub Action.

I used to configure Pulumi to be triggered directly from the build process, but bazel (as far I know), does not support Pulumi. When I used pants, there was a custom module, developed by one of the community members which did support pulumi (You might have to ask in the slack channel if you’re interested), but they stopped maintaining it as they moved to the Pulumi Automation API.

I am using Automation API from the start, and configuring a “deployer” per product/project within the monorepo. The intention is for the deployer to be as smart as possible – eventually up-ing only the stacks that have changes since the last time- but that’s a way down the line.

Another benefit from the Automation API is to pick up the stack outputs automatically when running integration/e2e tests, making the test configuration smoother.

Continue reading

Including a built artifact in another target (Bazel, golang)

We use pulumi to do IaC and we use a monorepo with Bazel as the build tool. We have out modules set out as following

One of the requirements we have is to build a lambda module and then deploy it. The lambda module is a target being built by Bazel (golang, but shouldn’t matter):

go_binary(
    name = "lambda_module",
    visibility = ["//visibility:public"],
)

We then have the iac module, which should get the built version of the above module, so that it can then upload it into lambda

go_binary(
    name = "iac",
    args = [
        "-lambda_module",
        "$(location //products/productA/module/lambda_module)",
    ],
    data = ["//products/productA/module/lambda_module"],
    visibility = ["//visibility:public"],
)
Continue reading