pulumi / pulumi-docker

A Docker Pulumi resource package, providing multi-language access to Docker resources and building images.
84 stars 14 forks source link

Invalid credentials causes multiple connection attempts #586

Closed bennbollay closed 1 year ago

bennbollay commented 1 year ago

What happened?

While trying to get the new Docker v4 working with AWS, I've been running into credential validation issues. I noticed the following behavior as it retried several times: https://user-images.githubusercontent.com/3607121/230786184-3ebbc18e-4190-4cd9-93f8-701ca90b2ad0.mov

This seems to indicate that there are multiple timers, all trying to retry concurrently.

Expected Behavior

The timer ticks down one value per second, monotonically, and retries when the specified value hits 0.

Steps to reproduce

Note: this code has several things that aren't working correctly, so don't use it as a reference:

  1. imageName is manually constructed because proxyEndpoint has https:// at the front of it, which is forbidden.
  2. getAuthorizationTokenOutput creates an object with userName, but docker.Image expects username.
import * as fs from 'node:fs';

import * as pulumi from '@pulumi/pulumi';

import * as aws from '@pulumi/aws';
import * as docker from '@pulumi/docker';

const SERVICE_PATH = '../../apps/recorder-service';

const imageName = 'recorder';
const imageVersion = '1.0.21';

const createImage = (registryId: pulumi.Output<string>) => {
  const registryToken = aws.ecr.getAuthorizationTokenOutput({ registryId });

  return registryToken.apply((registry) => {
    registry = { ...registry, username: registry.userName } as any;
    const recorderImage = new docker.Image('recorder', {
      imageName: '111111111111.dkr.ecr.us-west-1.amazonaws.com/recorder:1.0.21',
      build: {
        context: SERVICE_PATH,
        platform: 'linux/amd64',
      },
      registry,
    });
    return recorderImage.imageName;
  });
};

export { createImage };

Output of pulumi about

% pulumi about CLI Version 3.62.0 Go Version go1.20.2 Go Compiler gc

Plugins NAME VERSION aws 5.30.0 awsx 1.0.2 docker 4.1.2 nodejs unknown

Host OS darwin Version 13.2.1 Arch arm64

Additional context

No response

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).

AaronFriel commented 1 year ago

Hey @bennbollay, sharing my debugging steps and notes here for posterity rather than via DM.

I think this is how I'd approach your function.

import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
import * as docker from '@pulumi/docker';

const SERVICE_PATH = '../../apps/recorder-service';

// Should these be parameters to createImage?
// const imageName = 'recorder';
// const imageVersion = '1.0.21';

// Best practice: ensure that functions that create resources take a unique name. It's illegal to
// create two resources with the same name in Pulumi; each new `Docker.Image(name, ...)` must have a
// unique name.
function createImage({
  name,
  tag,
  registryId,
}: {
  name: string;
  tag: string;
  registryId: pulumi.Output<string>;
}) {
  const registryToken = aws.ecr.getAuthorizationTokenOutput({ registryId });

  // let's log out what we got so we know what we're working with:
  registryToken.apply((tokenOutput) => {
    console.log(`💥 creating image ${name}`, tokenOutput);
  });

  const recorderImage = new docker.Image(name, {
    // use interpolate to create an image name string
    imageName: pulumi.interpolate`${registryId}:${tag}`,
    // or omit the tag, and we'll create :latest by default (is that documented?)
    build: {
      context: SERVICE_PATH,
      platform: 'linux/amd64',
    },
    registry: {
      server: registryId,
      username: registryToken.userName,
      password: registryToken.password,
    },
  });

  // Log out the image results as well, let's pull out all of the fields of recorder image and log them:
  pulumi.all({ ...recorderImage }).apply((imageProps) => {
    console.log(`✅ created image ${name}`, imageProps);
  });

  return {
    imageName: recorderImage.imageName,
    imageDigest: recorderImage.repoDigest, // will be a image name using a sha256 digest
  };
}

export { createImage };

I'm logging out some additional info which you should see in your console on up, which will hopefully help us understand the auth issue(s) involved.

mjeffryes commented 1 year ago

Closing due to inactivity