Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve passing custom values as build arguments #2641

Merged
merged 4 commits into from
Mar 27, 2023

Conversation

carolynvs
Copy link
Member

What does this change

Currently porter passes all custom values defined in porter.yaml as build arguments when using docker to build the invocation image.

custom:
  app:
    version: 1.2.3

The above porter.yaml results in porter passing --build-arg CUSTOM_APP_VERSION=1.2.3

We have some users who are storing longer values in the custom map and have managed to hit the max argument length on their system. To address this, I am no longer passing all custom values as build arguments, and only pass them when the Dockerfile declares a build argument with the same name. In the example above, we only pass the app version when the Dockerfile declares ARG CUSTOM_APP_VERSION. In this users's case that's enough to avoid the problem.

In addition to the change above, I have also added a max length check on build arguments so that we can detect that it may be too long and provide a better error message. When we let the large value get passed to docker the error is simply "exit code 1" and we don't get any context into what failed. This will ensure that long values are caught before calling docker and telling the user to save the value in a file, and then read it back out in the Dockerfile instead.

What issue does it fix

Closes #2633

Notes for the reviewer

N/A

Checklist

  • Did you write tests?
  • Did you write documentation?
  • Did you change porter.yaml or a storage document record? Update the corresponding schema file.
  • If this is your first pull request, please add your name to the bottom of our Contributors list. Thank you for making Porter better! 🙇‍♀️

Reviewer Checklist

  • Comment with /azp run test-porter-release if a magefile or build script was modified
  • Comment with /azp run porter-integration if it's a non-trivial PR

@carolynvs carolynvs force-pushed the selective-build-args branch 3 times, most recently from 3a42500 to 09ce26c Compare March 21, 2023 17:47
Currently porter passes all custom values defined in porter.yaml as build arguments when using docker to build the invocation image.

```yaml
custom:
  app:
    version: 1.2.3
```

The above porter.yaml results in porter passing --build-arg CUSTOM_APP_VERSION=1.2.3

We have some users who are storing longer values in the custom map and have managed to hit the max argument length on their system. To address this, I am no longer passing all custom values as build arguments, and only pass them when the Dockerfile declares a build argument with the same name. In the example above, we only pass the app version when the Dockerfile declares `ARG CUSTOM_APP_VERSION`. In this users's case that's enough to avoid the problem.

In addition to the change above, I have also added a max length check on build arguments so that we can detect that it may be too long and provide a better error message. When we let the large value get passed to docker the error is simply "exit code 1" and we don't get any context into what failed. This will ensure that long values are caught before calling docker and telling the user to save the value in a file, and then read it back out in the Dockerfile instead.

Signed-off-by: Carolyn Van Slyck <[email protected]>
@carolynvs carolynvs marked this pull request as ready for review March 21, 2023 18:49
@carolynvs carolynvs requested a review from vdice March 21, 2023 19:08
Signed-off-by: Carolyn Van Slyck <[email protected]>
Copy link
Contributor

@arschles arschles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some nit-pick comments and suggestions. Overall, LGTM!

docs/content/bundle/custom-dockerfile.md Outdated Show resolved Hide resolved
docs/content/bundle/custom-dockerfile.md Outdated Show resolved Hide resolved
docs/content/bundle/custom-dockerfile.md Outdated Show resolved Hide resolved
pkg/build/buildkit/buildx.go Outdated Show resolved Hide resolved
* Use code blocks such as `porter build --build-arg` instead of "--build-arg flag on porter build". It reads more cleanly when someone is just reading the markdown and not the rendered HTML
* Split function arguments onto seprate lines since they are long lines

Signed-off-by: Carolyn Van Slyck <[email protected]>
@carolynvs
Copy link
Member Author

Thanks @arschles! I've updated the code to be a bit more readable, especially when viewing the raw markdown. The --build-arg is a Hugo thing, it let's me use a double hypen without it being turned into a dash. But I can see how it's super confusing in markdown and not all previewers support the escape code.

BuildArgs: []string{"BIG_BUILD_ARG=" + oversizedArg},
}
_, err := b.determineBuildArgs(ctx, m, opts)
assert.ErrorContains(t, err, "BIG_BUILD_ARG is longer than the max")
Copy link
Contributor

@joshuabezaleel joshuabezaleel Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a specific need here that we use assert when the rest is using require?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! We are slowly reworking the integration tests to be written like the smoke tests, longer tests that validate a number of scenarios to limit how much setup is required for reach test.

Right now the integration tests are kind of written like unit tests, and they try to set a small set of assertions. This isn't working well for us in Porter because the cost of test setup (building and publishing a bundle) is very high compared to the cost of the rest of the test. By testing a "workflow" or series of test cases in a single test, for example checkout the airgap test, we can check more assertions with less setup cost.

The problem with long tests though is that it's easy to have the first thing fail, and nothing else after that is going to pass (because each part of the test sets up the next part, such as installing a bundle, then upgrading it). By using require, we make the test stop on the first error. It then fails more quickly (instead of running when we know everything after that point will most likely fail). It also helps make it easier to troubleshoot since you only see the most relevant failure (the first one) instead of 20 assert messages, and you have to scroll to figure out which one is the cause of it all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great question, I'll add it to a README in the tests directory so it's easier to discover.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, make sense, thank you lots for the explanation, Carolyn!

test.Chdir(test.TestDir)

// Use a unique version for appversion so that docker doesn't cache the result and not print the value used in the Dockerfile
appversion := fmt.Sprintf("app.versio=%d", time.Now().Unix())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small typo: i guess it should be app.version instead of app.versio

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that, it actually pointed out a problem with how I was doing the test, so I've cleaned it up a bit more.

I was being too clever trying to deal with cachebusting the dockerfile and it totally wasn't necesary. I've simplified the test and fixed the typo

Signed-off-by: Carolyn Van Slyck <[email protected]>
carolynvs added a commit to carolynvs/porter that referenced this pull request Mar 22, 2023
This is follow up to getporter#2641 (comment) which documents why we use require in integration/smoke tests instead of assert.

Signed-off-by: Carolyn Van Slyck <[email protected]>
@carolynvs
Copy link
Member Author

@joshuabezaleel I've fixed the test, can you take another look?

carolynvs added a commit that referenced this pull request Mar 23, 2023
* Document why we use require in long tests

This is follow up to #2641 (comment) which documents why we use require in integration/smoke tests instead of assert.

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Apply suggestions from code review

Co-authored-by: Aaron Schlesinger <[email protected]>
Signed-off-by: Carolyn Van Slyck <[email protected]>

---------

Signed-off-by: Carolyn Van Slyck <[email protected]>
Co-authored-by: Aaron Schlesinger <[email protected]>
@joshuabezaleel
Copy link
Contributor

joshuabezaleel commented Mar 25, 2023

@carolynvs Apologize for the late reply.
Thank you for always taking the extra miles in making Porter an accessible and welcoming project to contributors, Carolyn, in which you didn't just kindly explain in length about the reasoning but also sent a PR to update the docs for others to read, really appreciate that from the very beginning.

The changes looks awesome to me, all good 👍

@carolynvs carolynvs merged commit 7d35c81 into getporter:main Mar 27, 2023
@carolynvs carolynvs deleted the selective-build-args branch March 27, 2023 19:25
bdegeeter pushed a commit to bdegeeter/porter that referenced this pull request May 11, 2023
* Document why we use require in long tests

This is follow up to getporter#2641 (comment) which documents why we use require in integration/smoke tests instead of assert.

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Apply suggestions from code review

Co-authored-by: Aaron Schlesinger <[email protected]>
Signed-off-by: Carolyn Van Slyck <[email protected]>

---------

Signed-off-by: Carolyn Van Slyck <[email protected]>
Co-authored-by: Aaron Schlesinger <[email protected]>
bdegeeter pushed a commit to bdegeeter/porter that referenced this pull request May 11, 2023
* Improve passing custom values as build arguments

Currently porter passes all custom values defined in porter.yaml as build arguments when using docker to build the invocation image.

```yaml
custom:
  app:
    version: 1.2.3
```

The above porter.yaml results in porter passing --build-arg CUSTOM_APP_VERSION=1.2.3

We have some users who are storing longer values in the custom map and have managed to hit the max argument length on their system. To address this, I am no longer passing all custom values as build arguments, and only pass them when the Dockerfile declares a build argument with the same name. In the example above, we only pass the app version when the Dockerfile declares `ARG CUSTOM_APP_VERSION`. In this users's case that's enough to avoid the problem.

In addition to the change above, I have also added a max length check on build arguments so that we can detect that it may be too long and provide a better error message. When we let the large value get passed to docker the error is simply "exit code 1" and we don't get any context into what failed. This will ensure that long values are caught before calling docker and telling the user to save the value in a file, and then read it back out in the Dockerfile instead.

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Document max length on --custom field

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Improve readability

* Use code blocks such as `porter build --build-arg` instead of "--build-arg flag on porter build". It reads more cleanly when someone is just reading the markdown and not the rendered HTML
* Split function arguments onto seprate lines since they are long lines

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Fix build test

I was being too clever trying to deal with cachebusting the dockerfile and it totally wasn't necesary. I've simplified the test and fixed the typo

Signed-off-by: Carolyn Van Slyck <[email protected]>

---------

Signed-off-by: Carolyn Van Slyck <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Large custom values in porter.yaml break build
3 participants