pulumi / pulumi-docker-build

A Pulumi native provider for Docker
Apache License 2.0
5 stars 3 forks source link

Crash when using plan and ECR images #277

Open stazz opened 2 days ago

stazz commented 2 days ago

What happened?

The docker-build provider crashed on up command with --plan=<path> argument with the following message:

error: resource urn:pulumi:<stack>::<project>::docker-build:index:Image::<resource> violates plan: properties changed: ~~registries[{[{map[address:{&{{<ecr URL>}}} password:{&{{<token1>}}} username:{&{{<username>}}}]}]}!={[{map[address:{&{{<ecr URL>}}} password:{&{{<token2>}}} username:{&{{<username>}}}]}]}]

Example

The code which causes this is like this:

import * as pulumi from "@pulumi/pulumi";
import * as legacyEcr from "@pulumi/aws/ecr";
import * as ecr from "@pulumi/aws-native/ecr";
import * as docker from "@pulumi/docker-build";
import * as process from "node:process";
import path from "node:path";

const repo = new ecr.Repository("...", {
  repositoryName: "...",
  ...
 });
const buildDirectory = path.join(process.cwd(), "docker");

const token = legacyEcr.getAuthorizationTokenOutput();

export const image = new docker.Image("...", {
  // Why is "push" and "exports" like this? See: https://github.com/pulumi/pulumi-docker-build/issues/252#issuecomment-2340554610
  push: false,
  exports: [
    {
      registry: {},
    },
  ],
  buildOnPreview: true, // Always build on preview
  tags: [pulumi.interpolate`${repo.repositoryUri}:latest`],
  dockerfile: {
    location: path.join(buildDirectory, "Dockerfile"),
  },
  context: {
    location: buildDirectory,
  },
  buildArgs: {
    ...
  },
  platforms: [docker.Platform.Linux_arm64],
  registries: [
    {
      address: pulumi.secret(repo.repositoryUri),
      username: pulumi.secret(token.userName),
      password: token.password,
    },
  ],
});

It works fine without --plan functionality, but not without. The plan was also extremely simple - on preview it said there are no changes to the stack (as it should be, since I changed nothing). However, on up command, the error message was seen (which btw printed the username and password in plaintext to console output), and process crashed.

Output of pulumi about

CLI
Version      3.134.1
Go Version   go1.23.1
Go Compiler  gc

Host
OS       debian
Version  12.7
Arch     aarch64

Backend
Name           pulumi.com
URL            https://app.pulumi.com
User           Unknown
Organizations
Token type     personal

Pulumi locates its logs in /tmp by default
warning: Failed to read project: no Pulumi.yaml project file found (searching upwards from <cwd>). If you have not created a project yet, use `pulumi new` to do so: no project file found
warning: Failed to get information about the current stack: no Pulumi.yaml project file found (searching upwards from <cwd>). If you have not created a project yet, use `pulumi new` to do so: no project file found

The output is a bit wonky since I am utilising Pulumi Automation API to run my pipeline, as it is a bit complex (has some other components than just Pulumi), and I am storing the state and encryption key in AWS (not using Pulumi cloud). Furthermore, I am running Pulumi inside Docker container pulumi/pulumi-nodejs-22:3.134.1.

But the versions in the package.json are like this:

    "@pulumi/aws-native": "0.125.0",
    "@pulumi/aws": "6.53.0",
    "@pulumi/docker-build": "0.0.6",
    "@pulumi/postgresql": "3.12.0",
    "@pulumi/pulumi": "3.134.1",
    "@pulumi/random": "4.16.6",

Additional context

Now that I've written the full report, I am not sure whether this actually belongs here or in AWS provider. Maybe the AWS provider for some reason provides same token during preview (and even refresh, as I've run that as well), but during up it is not? Since in the error message, the password values DO differ. I don't know. Feel free to move the issue over the AWS provider repo if it really belongs there. 👍

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

stazz commented 2 days ago

Okay, I found also a somewhat heavyweight workaround which is not optimal at all, but it DOES prevent crashing. I've added registries to the ignoreChanges provider options of docker.Image resource, and now up with no-op plan passes. This might bite me back later, but for now, it at least prevents crashing, and makes using plan files in general feasible.

export const image = new docker.Image(
  "...",
  {
    ...
  },
  {
    ignoreChanges: ["registries"],
  },
);