<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pulumi-Automation-Api on despatches</title><link>https://icle.es/tags/pulumi-automation-api/</link><description>Recent content in Pulumi-Automation-Api on despatches</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 20 Jun 2025 08:42:17 +0100</lastBuildDate><atom:link href="https://icle.es/tags/pulumi-automation-api/index.xml" rel="self" type="application/rss+xml"/><item><title>Use `protoc` bin instead of building from source in `bazel`</title><link>https://icle.es/2025/06/09/use-protoc-bin-in-bazel/</link><pubDate>Mon, 09 Jun 2025 20:57:53 +0000</pubDate><guid>https://icle.es/2025/06/09/use-protoc-bin-in-bazel/</guid><description>&lt;p>I work on a project that uses &lt;code>pulumi&lt;/code> automation api, which in turn uses
&lt;code>protobuf&lt;/code>. I think there are other bits in &lt;code>bazel&lt;/code> that also uses it.&lt;/p>
&lt;p>For a while, it was fine - except that some &lt;code>CI&lt;/code> runs would take 15 minutes and
we couldn&amp;rsquo;t quite figure out why.&lt;/p>
&lt;p>I finally had to update &lt;code>bazel&lt;/code> from 7.x to 8 and in that process (which
honestly could have been easier, but oh well), I ran into a problem with
compiling protobuf.&lt;/p>
&lt;p>Namely, I kept running into this error:&lt;/p>
```
error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
```
&lt;p>I tried many things but was not able to get past this error. In the end, I was
able to narrow it down to devbox/nix and how it messes with the environment that
doesn&amp;rsquo;t quite agree with &lt;code>bazel&lt;/code>.&lt;/p>
&lt;h2 id="what-didnt-work">What didn&amp;rsquo;t work&lt;/h2>
&lt;ul>
&lt;li>installing &lt;code>gcc&lt;/code> from devbox&lt;/li>
&lt;li>installing &lt;code>stdenv.cc.cc.lib&lt;/code>&lt;/li>
&lt;li>Setting &lt;code>LD_LIBRARY_PATH&lt;/code> (to
&lt;code>&amp;lt;workspace-dir&amp;gt;/.devbox/nix/profile/default/lib&lt;/code>, which is where the devbo
version of &lt;code>libstdc++.so.6&lt;/code> is installed by &lt;code>stdenv.cc.cc.lib&lt;/code>)&lt;/li>
&lt;li>Using the &lt;code>--action-env=&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://github.com/tweag/rules_nixpkgs">rules-nixpkgs&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>None of which really worked.&lt;/p>
&lt;p>Disabling &lt;code>devbox&lt;/code> &lt;strong>did&lt;/strong> work, which was at least partly encouraging. I also
found a bunch of evidence online around this issue
(&lt;a href="https://github.com/bazelbuild/bazel/issues/12978">1&lt;/a>,
&lt;a href="https://github.com/jetify-com/devbox/issues/1100">2&lt;/a>,
&lt;a href="https://github.com/jetify-com/devbox/issues/1596">3&lt;/a>,
&lt;a href="https://github.com/jetify-com/devbox/issues/710">4&lt;/a>,
&lt;a href="https://github.com/tweag/rules_nixpkgs/issues/573">5&lt;/a>). Bazel seems to
&lt;a href="https://discuss.ray.io/t/bazel-protobuf-build-errors-libstdc-with-non-system-gcc/3329">generally dislike non-system gcc&lt;/a>.&lt;/p></description><content:encoded><![CDATA[<p>I work on a project that uses <code>pulumi</code> automation api, which in turn uses
<code>protobuf</code>. I think there are other bits in <code>bazel</code> that also uses it.</p>
<p>For a while, it was fine - except that some <code>CI</code> runs would take 15 minutes and
we couldn&rsquo;t quite figure out why.</p>
<p>I finally had to update <code>bazel</code> from 7.x to 8 and in that process (which
honestly could have been easier, but oh well), I ran into a problem with
compiling protobuf.</p>
<p>Namely, I kept running into this error:</p>
```
error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
```
<p>I tried many things but was not able to get past this error. In the end, I was
able to narrow it down to devbox/nix and how it messes with the environment that
doesn&rsquo;t quite agree with <code>bazel</code>.</p>
<h2 id="what-didnt-work">What didn&rsquo;t work</h2>
<ul>
<li>installing <code>gcc</code> from devbox</li>
<li>installing <code>stdenv.cc.cc.lib</code></li>
<li>Setting <code>LD_LIBRARY_PATH</code> (to
<code>&lt;workspace-dir&gt;/.devbox/nix/profile/default/lib</code>, which is where the devbo
version of <code>libstdc++.so.6</code> is installed by <code>stdenv.cc.cc.lib</code>)</li>
<li>Using the <code>--action-env=</code></li>
<li><a href="https://github.com/tweag/rules_nixpkgs">rules-nixpkgs</a></li>
</ul>
<p>None of which really worked.</p>
<p>Disabling <code>devbox</code> <strong>did</strong> work, which was at least partly encouraging. I also
found a bunch of evidence online around this issue
(<a href="https://github.com/bazelbuild/bazel/issues/12978">1</a>,
<a href="https://github.com/jetify-com/devbox/issues/1100">2</a>,
<a href="https://github.com/jetify-com/devbox/issues/1596">3</a>,
<a href="https://github.com/jetify-com/devbox/issues/710">4</a>,
<a href="https://github.com/tweag/rules_nixpkgs/issues/573">5</a>). Bazel seems to
<a href="https://discuss.ray.io/t/bazel-protobuf-build-errors-libstdc-with-non-system-gcc/3329">generally dislike non-system gcc</a>.</p>
<h2 id="a-ray-of-hope">A ray of hope</h2>
<p>I was just about ready to throw in the towel when ChatGPT, in passing suggested
using the <code>protobuf</code> binary directly. I wasn&rsquo;t even using this binary - it was
being pulled in as a dependency and I just needed it to work. I did not need it
to be built from source.</p>
<p>Furthermore, I found, from my research into trying to solve this that building
<code>protobuf</code> was the likely culprit in the <code>CI</code> taking 15 minutes.</p>
<p>I also remembered that someone else on the team had issues trying to get it to
build on a mac at some point.</p>
<p>All in all, it was a problematic piece of software and I was seriously
considering switching to <code>opentofu</code> - but they might be using it too.</p>
<h2 id="bin-protoc">bin <code>protoc</code></h2>
<p>It was difficult to find decent documentation about how to achieve this though,
apart from a partially answered on:</p>
<ul>
<li><a href="https://stackoverflow.com/questions/68918369/is-it-possible-to-use-bazel-without-compiling-protobuf-compiler">stackoverflow question</a>,</li>
<li><a href="https://groups.google.com/g/bazel-discuss/c/3Q_GEqNZrC0">google groups for bazel-discuss</a>
<ul>
<li>which also led me to
<a href="https://gitlab.com/mvfwd/issue-bazel-protobuf-compile/-/tree/main">a gitlab repo with some code</a></li>
</ul>
</li>
</ul>
<p>These resources gave me just enough to be able to cobble together a working
solution, which needs:</p>
<h3 id="install-protoc">Install <code>protoc</code></h3>
<p>The first thing we need is a locally installed <code>protoc</code> bin (I&rsquo;ll used devbox to
install it for consistency across dev environments)</p>
```bash
devbox add protobuf
```
<p>You can add a version specifier for better reproducibility.</p>
<h3 id="runnable-target">Runnable Target</h3>
<p>We also need a shell target that will execute this correctly. The <code>bazel</code> flag
to override <code>protoc</code> takes a local target, not a bin.</p>
<p><code>third_party/tools/BUILD.bazel</code></p>
```python
package(default_visibility = ["//visibility:public"])

sh_binary(
    name = "protoc",
    srcs = ["protoc.sh"],
)

# https://github.com/protocolbuffers/protobuf/blob/b4b0e304be5a68de3d0ee1af9b286f958750f5e4/BUILD#L773
proto_lang_toolchain(
    name = "cc_toolchain",
    command_line = "--cpp_out=$(OUT)",
    runtime = ":protoc",
    visibility = ["//visibility:public"],
)
```
<p><code>third_party/tools/protoc.sh</code></p>
```bash
#!/bin/env bash
protoc "$@"
```
<h3 id="override-protoc">Override protoc</h3>
<p>You should now be able to override <code>protoc</code> with:</p>
```bash
bazel build --proto_compiler=//third_party/tools:protoc ...
```
<p>Having to pass in a flag each time is annoying though, and you can add it to
your <code>.bazelrc</code></p>
```
build --proto_compiler=//third_party/tools:protoc
```
<h3 id="sample-code">Sample code</h3>
<p>You can find the sample code in
<a href="https://github.com/drone-ah/wordsonsand">the wordsonsand repo</a> which uses this
exact solution to override <code>protoc</code> and get the <code>pulumi</code> sample code to work ;)</p>
<p>PS: It also includes a fully migrated <code>MODULES.bazel</code> with support for <code>golang</code>.
You will also want to check out <code>BUILD</code> in the root.</p>]]></content:encoded></item><item><title>Streaming Progress With Pulumi Automation API</title><link>https://icle.es/2023/11/08/streaming-progress-with-pulumi-automation-api/</link><pubDate>Wed, 08 Nov 2023 12:38:32 +0000</pubDate><guid>https://icle.es/2023/11/08/streaming-progress-with-pulumi-automation-api/</guid><description>&lt;p>When using the pulumi automation API, you lose some of the niceties of the
pulumi CLI, like having to set up command line args processing and the output is
not as friendly or pretty as before. It also doesn't stream the output - though
this one is easier to fix.&lt;/p>
&lt;p>This is lifted straight out of
&lt;a href="https://github.com/pulumi/automation-api-examples/blob/3114b754ea84ebd0cc1e1b67f128df75795bd4c3/go/local_program/automation/main.go#L74C2-L82C3">their golang example code&lt;/a>,
so if you're working in another language - you should be able to find the
relevant code in the same repo&lt;/p></description><content:encoded><![CDATA[<p>When using the pulumi automation API, you lose some of the niceties of the
pulumi CLI, like having to set up command line args processing and the output is
not as friendly or pretty as before. It also doesn't stream the output - though
this one is easier to fix.</p>
<p>This is lifted straight out of
<a href="https://github.com/pulumi/automation-api-examples/blob/3114b754ea84ebd0cc1e1b67f128df75795bd4c3/go/local_program/automation/main.go#L74C2-L82C3">their golang example code</a>,
so if you're working in another language - you should be able to find the
relevant code in the same repo</p>
```go
   // wire up our update to stream progress to stdout
    stdoutStreamer := optup.ProgressStreams(os.Stdout)

    // run the update to deploy our fargate web service
    res, err := stack.Up(ctx, stdoutStreamer)
    if err != nil {
        fmt.Printf("Failed to update stack: %v\n\n", err)
    }
```
]]></content:encoded></item><item><title>Bazel + Pulumi Automation API. Deploying an inline stack along with Pulumi.[stack].yaml</title><link>https://icle.es/2023/11/07/bazel-pulumi-automation-api-deploying-an-inline-stack-along-with-pulumi-yaml/</link><pubDate>Tue, 07 Nov 2023 15:57:52 +0000</pubDate><guid>https://icle.es/2023/11/07/bazel-pulumi-automation-api-deploying-an-inline-stack-along-with-pulumi-yaml/</guid><description>&lt;p>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
&lt;a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services">OpenID Connect(OIDC)&lt;/a>
as part of the GitHub Action.&lt;/p>
&lt;p>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.&lt;/p></description><content:encoded><![CDATA[<p>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
<a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services">OpenID Connect(OIDC)</a>
as part of the GitHub Action.</p>
<p>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.</p>
<p>I am using Automation API from the start, and configuring a &quot;deployer&quot; per
product/project within the monorepo. The intention is for the deployer to be as
smart as possible - eventually <code>up</code>-ing only the stacks that have changes since
the last time- but that's a way down the line.</p>
<p>Another benefit from the Automation API is to pick up the stack outputs
automatically when running integration/e2e tests, making the test configuration
smoother.</p>
<p>The first step is to be able to define a stack within a product, hook it into
the main iac executable and have it working. My directory structure is roughly
as below: While I am using golang as my language of choice, it's probably not
hugely different in other languages.</p>
<ul>
<li>products
<ul>
<li>productA
<ul>
<li>auth
<ul>
<li>iac_auth
<ul>
<li>BUILD</li>
<li>deploy.go</li>
<li>Pulumi.dev.yaml</li>
<li>Pulumi.yaml</li>
</ul>
</li>
<li>OtherAuthModules</li>
</ul>
</li>
<li>iac
<ul>
<li>BUILD</li>
<li>main.go</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="iac_authbuild"><code>iac_auth/BUILD</code></h1>
```wp-block-syntaxhighlighter-code
# load etc.
go_library(
    name = "iac_auth",
    srcs = ["deploy.go"],
    data = glob([
        "Pulumi.*.yaml",
    ]) + [
        "Pulumi.yaml",
    ],
    visibility = ["//visibility:public"],
    deps = [
       # dependencies automated with gazelle
    ],
)
```
<h1 id="iac_authdeploy.go"><code>iac_auth/deploy.go</code></h1>
```wp-block-syntaxhighlighter-code
package iac_sync

import (
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

const moduleName = "auth"

func DeployGithubLambda(ctx *pulumi.Context) error {
    fmt.Println("Deploy")

    conf := config.Require(ctx, "key")
    fmt.Printf("conf: %s\n", conf) // Will successfully pick up the value if key is in Pulumi.<stack>.yaml

    // Actual deployment code here

    return nil
}
```
<h1 id="iacbuild"><code>iac/BUILD</code></h1>
```wp-block-syntaxhighlighter-code
# other config including standard config of :iac_lib by gazelle

go_binary(
    name = "iac",
    args = [
        "-iac_auth",
        "$(location //products/productA/auth/iac_auth)",
    ],
    data = [
        "//products/gitolink/productA/iac_auth",
    ],
    embed = [":iac_lib"],
    visibility = ["//visibility:public"],
)
```
<p>Worth noting the <code>args</code> bit, which is what we use to identify the path where the
<code>Pulumi.yaml</code> and <code>Pulumi.&lt;stack&gt;.yaml</code> files are:</p>
<h1 id="iacmain.go"><code>iac/main.go</code></h1>
```wp-block-syntaxhighlighter-code
package main

import (
    "context"
    "flag"
    "fmt"
    iacAuth "github.com/drone-ah/monorepo/products/gitolink/auth/iac_auth"
    "github.com/pulumi/pulumi/sdk/v3/go/auto"
    "path/filepath"
)

func main() {

    // Pick up the path from args
    var iacAuthPath = flag.String("iac_auth", "", "bin for iac_auth")
    flag.Parse()
    fmt.Printf("param iac: %s \n", *iacAuthPath)

    ctx := context.Background()

    projectName := "gitolink"
    stackName := "dev"

    stack, err := auto.NewStackInlineSource(ctx,
        stackName,
        projectName,
        iacAuth.DeployGithubLambda,
        // Define workdir for locatin of the Pulumi yaml files
        auto.WorkDir(filepath.Dir(*iacAuthPath)))

    preview, err := stack.Preview(ctx)

    fmt.Println(err)
    fmt.Println(preview)
}
```
<p>You might also have to use <code>RLocation</code> (see my previous post about
<a href="https://drone-ah.com/2023/11/01/including-a-built-artifact-in-another-target-bazel-golang/">including an artifact in another target</a>
for an example of this), though when I tried it, it was missing one of the yaml
files and I didn't investigate further.</p>]]></content:encoded></item></channel></rss>