pulumi / actions

Deploy continuously to your cloud of choice, using your favorite language, Pulumi, and GitHub!
Apache License 2.0
241 stars 73 forks source link

Support command flags such as `--config` #716

Open jessicayuen opened 1 year ago

jessicayuen commented 1 year ago

Hello!

Issue details

Affected area/feature

Use Case

I am building an automated release workflow. When I publish a Github release, I want to supply the following command in order to properly tag my AWS ECR image with the release version.

pulumi up --config my-app:releasetag=$GITHUB_REF

and in the pulumi code:

...
const config = new pulumi.Config();
const releaseTag = config.require("releasetag");

const imageName = myrepo.repositoryUri;

const image = new docker.Image(`my-app-${releaseTag}`, {
  imageName: pulumi.interpolate`${imageName}:${releaseTag}`,
  build: "../",
  localImageName: "../Dockerfile.client",
});

Problem

Running pulumi preview with the config flag via console works, but it does not appear to be currently supported through the Github Actions. I get an error.

Run pulumi/actions@v3
  with:
    command: preview --config my-app:releasetag=$GITHUB_REF
    stack-name: production
    comment-on-pr: false
    github-token: ***
    work-dir: pulumi-my-app
    parallel: ...
    target-dependents: false
    refresh: false
    upsert: false
    edit-pr-comment: true
    pulumi-version: ^3
    color: auto
  env:
    AWS_DEFAULT_REGION: us-east-1
    AWS_REGION: us-east-1
    AWS_ACCESS_KEY_ID: ***
    AWS_SECRET_ACCESS_KEY: ***
    PULUMI_ACCESS_TOKEN: ***
Error: Expected { command: "up" | "update" | "refresh" | "destroy" | "preview"; stackName: string; workDir: string; commentOnPr: boolean; options: { parallel?: number; message?: string; expectNoChanges?: boolean; diff?: boolean; replace?: string[]; target?: string[]; policyPacks?: string[]; policyPackConfigs?: string[]; targetDependents?: boolean; editCommentOnPr?: boolean; userAgent?: "pulumi/actions@v3"; pulumiVersion?: string; }; isPullRequest: boolean; }, but was incompatible
RobbieMcKinstry commented 1 year ago

Hi @jessicayuen.

The command input must be one variant of the enum described here. That error message starts off helpful...

Error: Expected { command: "up" | "update" | "refresh" | "destroy" | "preview";

...but then I can see it descends into madness.

I think the feature you're looking for is the config-map option listed in the extra-options section of the documentation. Would you mind giving this a try?

  with:
    command: preview
    config-map:
        "my-app:releasetag": $GITHUB_REF
    stack-name: production
    comment-on-pr: false
    github-token: ***
    work-dir: pulumi-my-app
    parallel: ...
    target-dependents: false
    refresh: false
    upsert: false
    edit-pr-comment: true
    pulumi-version: ^3
    color: auto
  env:
    AWS_DEFAULT_REGION: us-east-1
    AWS_REGION: us-east-1
    AWS_ACCESS_KEY_ID: ***
    AWS_SECRET_ACCESS_KEY: ***
    PULUMI_ACCESS_TOKEN: ***

I'm sorry if my suggestion isn't quite right, I haven't used this feature myself yet.

jessicayuen commented 1 year ago

@RobbieMcKinstry Thanks for the response, I just tried using config-map but I am getting a github actions lint error:

expected scalar node for string value but found mapping node with "!!map" tag [syntax-check]

I've tried both formats below.

  1. per docs:

        uses: pulumi/actions@v3
        with:
          command: preview
          config-map: { "my-app:releasetag": { value: $GITHUB_REF } }
  2. per suggestion:

        uses: pulumi/actions@v3
        with:
          command: preview
          config-map:
            "my-app:releasetag": $GITHUB_REF

Is it possible I'm configuring this wrong?

elMolda commented 1 year ago

I'm also experiencing the same error while specifying config map values with my flows, I have the following notation

 - name: Deploy with pulumi
        uses: pulumi/actions@v3
        with:
          command: up
          stack-name: ${{ steps.stack_name.outputs.stack_name }}
          work-dir: ./infrastructure
          upsert: true
          config-map: "{config: {'gcp:project':my-project, 'gcp:region': us-central1}}"
RobbieMcKinstry commented 1 year ago

Sorry for the slow reply.

Is it possible I'm configuring this wrong?

Yes, I think this is user error, but I'm not certain. I haven't had a chance to reproduce yet. Providing config is new feature, so I'm not as sharp in this area as I could be :)

I'll attempt to reproduce and report back.

jessicayuen commented 1 year ago

Hi @RobbieMcKinstry! Were you able to reproduce the issue?

CmdrSharp commented 1 year ago

Whilst the original users issue may be user error, the ability to supply flags is missing (and not solved via the config-map parameter). Perhaps this is what should be the target?

EDIT: Looking at the source code, I don't think that implementing an args field is a very simple fix, since it's not compatible (from what I see) with the declared implementations in pulumi/automation. It does however seem illogical that the action shouldn't support all flags that can be passed via Pulumi CLI (such as --config-file).

RobbieMcKinstry commented 1 year ago

Hi @jessicayuen. I'm sorry I haven't gotten back to you on this yet. I haven't had the bandwidth yet to attempt a reproduction. You might have some luck getting help on the Community Slack since I'm afraid I might not have time myself.

RobbieMcKinstry commented 1 year ago

@CmdrSharp

It does however seem illogical that the action shouldn't support all flags that can be passed via Pulumi CLI (such as --config-file).

I agree that it's illogical and IMO ultimately unhelpful.

I don't think that implementing an args field is a very simple fix, since it's not compatible (from what I see) with the declared implementations in pulumi/automation.

I think the approach would be to accept options command: raw and args: List<String>. Then, we'd add a case for raw here, but instead of using the Automation API, we'd shell out to the CLI like we do here. Happy to accept PRs from the community. Lately, my time has been allocated to performance improvements, but I can always shepherd items through review. :^)

serdarkkts commented 1 year ago

@jessicayuen @elMolda I am not sure if you guys are still dealing with the problem but I wanted to share what was wrong with your definitions.

The config-map parameter expects you to provide your configurations in the following format: {<key | string>: {value: <value | string>, secret: <is_secret | boolean> },}. So suppose that you have the following configurations:

env: dev
my-app:releasetag: sandbox

which can be defined like this for configmap parameter:

{env: {value: dev, secret: false}, my-app:releasetag: { value: sandbox, secret: false}}

and you can use it in your flow now:

 - name: Deploy with pulumi
   uses: pulumi/actions@v3
   with:
     command: preview
     stack-name: dev
     work-dir: infra
     config-map: "{env: {value: dev, secret: false}, my-app:releasetag: { value: sandbox, secret: false}}"
kiweezi commented 1 year ago

Thanks @serdarkkts, that was really helpful. It's just nice to see an example with these things!

If anyone else is wondering how you format larger configs including GitHub secrets, here's how I did it for Azure:

- name: Deploy with pulumi
   uses: pulumi/actions@v3
   with:
     command: preview
     stack-name: dev
     work-dir: infra
     config-map: "{
       azure-native:clientId: {value: '${{ secrets.AZURE_DETAILS_CLIENT_ID }}', secret: false},
       azure-native:clientSecret: {value: '${{ secrets.AZURE_DETAILS_CLIENT_SECRET }}', secret: true},
       azure-native:location: {value: 'westeurope', secret: false},
       azure-native:subscriptionId: {value: '${{ secrets.AZURE_DETAILS_SUBSCRIPTION_ID }}', secret: false},
       azure-native:tenantId: {value: '${{ secrets.AZURE_DETAILS_TENANT_ID }}', secret: false},
       environment:size: {value: 'xs', secret: false},
       environment:type: {value: 'testing', secret: false}
       }"

You can use multi-line double-quoted strings to help make it easier on the eyes. When expanding GitHub variables, wrap them in single-quotes.

jessicayuen commented 1 year ago

@serdarkkts @kiweezi Thank you for the examples! They helped a lot and did work for me.

I'm back with a question about complex value types that aren't strings.

The following tokens value isn't being registered as valid json:

  config-map: "{
    env: { value: dev, secret: false },
    tokens: {
      value: {
        \"GITHUB_TOKEN\": \"'${{ secrets.CI_BOT_ACCESS_TOKEN }}'\",
        \"PAGERDUTY_ACCOUNT_TOKEN\": \"'${{ secrets.PAGERDUTY_RW_KEY }}'\"
      },
      secret: false
    }
  }"

I'm reading it as follows:

const config = new pulumi.Config();
const tokens = config.getObject<{ [s: string]: string }>("tokens") || {};

error: Configuration '<service>:tokens' value '[object Object]' is not a valid JSON object


For additional context, I am able to load the configs fine outside of github actions using the following config:

config:
  env: "dev"
  tokens:
    "GITHUB_TOKEN": "test"
    "PAGERDUTY_ACCOUNT_TOKEN": "test"

Are complex value types supported? If yes, what am I doing wrong?

serdarkkts commented 1 year ago

@jessicayuen I am not sure if this can work but I would try setting the values for each key separately:

- name: Deploy with pulumi
   uses: pulumi/actions@v3
   with:
     command: preview
     stack-name: dev
     work-dir: infra
     config-map: "{
       tokens:GITHUB_TOKEN: {value: '${{ secrets.CI_BOT_ACCESS_TOKEN }}', secret: false},
       tokens:PAGERDUTY_ACCOUNT_TOKEN: {value: '${{ secrets.PAGERDUTY_RW_KEY }}', secret: false},
       env: {value: 'dev', secret: false}
       }"
RobbieMcKinstry commented 1 year ago

I could be very wrong here, but I think you need a multiline string in config-map:

  config-map: |
    {
      env: { value: dev, secret: false },
      tokens: {
        value: {
          "GITHUB_TOKEN": "${{ secrets.CI_BOT_ACCESS_TOKEN }}",
          "PAGERDUTY_ACCOUNT_TOKEN": "${{ secrets.PAGERDUTY_RW_KEY }}"
        },
        secret: false
      }
    }