Skip to content

download/cache full graph of dependencies at beta validate#5809

Merged
jbw976 merged 5 commits intocrossplane:masterfrom
enesonus:download-all-config-deps
Jul 31, 2024
Merged

download/cache full graph of dependencies at beta validate#5809
jbw976 merged 5 commits intocrossplane:masterfrom
enesonus:download-all-config-deps

Conversation

@enesonus
Copy link
Contributor

@enesonus enesonus commented Jul 1, 2024

Description of your changes

This PR enables 'beta validate' command to calculate all dependencies of the provided configurations and therefore the full graph of dependencies is downloaded/cached. Previously we were only downloading/caching the level-1 dependencies of a configuration which are the dependencies of the provided configuration..

Fixes #5803

Here are some examples with this functionality:

  1. configuration-aws-database:v0.10.0
    Dependency graph is:

    • provider-aws-rds
    • configuration-aws-network:v0.12.0
      • provider-aws-ec2:v1.2.0
      • function-patch-and-transform:v0.4.0

    Current behavior:

    crossplane beta validate .work/xfn/config-aws-db.yaml .work/xfn/
                                                                                                   
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-aws-database:v0.10.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-aws-rds:v1.2.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-aws-network:v0.12.0
    

    New behavior:

    go run cmd/crank/main.go beta validate .work/xfn/config-aws-db.yaml .work/xfn/
    
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-aws-database:v0.10.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-aws-rds:v1.2.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-aws-network:v0.12.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-aws-ec2:v1.2.0
    package schemas does not exist, downloading:  xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.4.0
    
  2. platform-ref-azure:v0.11.0:
    Dependency graph is:

    • provider-azure-containerservice:v0.42.1
    • configuration-azure-network:v0.8.0
      • provider-azure-network:v0.42.1
      • function-patch-and-transform:v0.4.0
    • configuration-azure-aks:v0.7.0
      • provider-azure-containerservice:v0.42.1
      • configuration-azure-network:v0.8.0
        • provider-azure-network:v0.42.1
        • function-patch-and-transform:v0.4.0
      • provider-helm:v0.17.0
      • provider-kubernetes:v0.12.1
    • configuration-azure-database:v0.11.1
      • provider-azure-dbformariadb:v0.42.1
      • provider-azure-dbforpostgresql:v0.42.1
      • configuration-azure-network:v0.8.0
        • provider-azure-network:v0.42.1
        • function-patch-and-transform:v0.4.0
      • function-patch-and-transform:v0.4.0
    • configuration-app:v0.5.0
      • provider-helm:v0.17.0
      • function-patch-and-transform:v0.4.0
    • configuration-observability-oss:v0.5.0
      • provider-helm:v0.17.0
      • provider-kubernetes:v0.12.1
      • provider-grafana:v0.8.0
      • function-patch-and-transform:v0.4.0
    • configuration-gitops-flux:v0.6.0
      • provider-helm:v0.17.0
      • function-patch-and-transform:v0.4.0

    This configuration has 14 distinct dependencies. We need to download it's own yaml plus 14 other yamls

    Current behavior:

    crossplane beta validate .work/xfn/config-plat-ref-azure.yaml .work/xfn/
    
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-gitops-flux:v0.6.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/platform-ref-azure:v0.11.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-azure-containerservice:v0.42.1
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-azure-network:v0.8.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-azure-aks:v0.7.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-azure-database:v0.11.1
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-app:v0.5.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-observability-oss:v0.5.0
    

    New behavior:

    go run cmd/crank/main.go beta validate .work/xfn/config-plat-ref-azure.yaml .work/xfn/
    
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/platform-ref-azure:v0.11.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-azure-network:v0.8.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-gitops-flux:v0.6.0
    package schemas does not exist, downloading:  xpkg.upbound.io/crossplane-contrib/provider-kubernetes:v0.12.1
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-azure-database:v0.11.1
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-app:v0.5.0
    package schemas does not exist, downloading:  xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.4.0
    package schemas does not exist, downloading:  xpkg.upbound.io/crossplane-contrib/provider-helm:v0.17.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-azure-aks:v0.7.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-azure-network:v0.42.1
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-azure-dbformariadb:v0.42.1
    package schemas does not exist, downloading:  xpkg.upbound.io/grafana/provider-grafana:v0.8.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-azure-containerservice:v0.42.1
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/configuration-observability-oss:v0.5.0
    package schemas does not exist, downloading:  xpkg.upbound.io/upbound/provider-azure-dbforpostgresql:v0.42.1
    

I have:

  • Read and followed Crossplane's contribution process.
  • Run earthly +reviewable to ensure this PR is ready for review.
  • Added or updated unit tests.
  • Added or updated e2e tests.
  • Linked a PR or a docs tracking issue to document this change.
  • Added backport release-x.y labels to auto-backport this PR.

Need help with this checklist? See the cheat sheet.

@enesonus enesonus requested review from a team and phisco as code owners July 1, 2024 00:13
@enesonus enesonus requested a review from bobh66 July 1, 2024 00:13
Copy link
Member

@ezgidemirel ezgidemirel left a comment

Choose a reason for hiding this comment

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

Thanks @enesonus for the PR, LGTM!

Copy link
Member

@jbw976 jbw976 left a comment

Choose a reason for hiding this comment

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

Nice @enesonus!! Are you able to add to the PR description the steps you took to test this change outside of unit tests? i'd love to test it out on my machine too :)

@enesonus
Copy link
Contributor Author

enesonus commented Jul 3, 2024

Nice @enesonus!! Are you able to add to the PR description the steps you took to test this change outside of unit tests? i'd love to test it out on my machine too :)

I added the examples now @jbw976 thanks for the suggestion!

m.deps[image] = true

if _, ok := m.confs[image]; !ok && dep.Configuration != nil {
m.confs[image] = true
Copy link
Member

Choose a reason for hiding this comment

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

it looks like this line is adding a new element to the m.confs map, while we are currently iterating through it (starting on line 173). This can be problematic with undefined behavior: https://stackoverflow.com/a/68639401

This is demonstrated in https://go.dev/play/p/V23Q7zkItEF - try running that multiple times and you see that you get inconsistent results.

Is the intent here that this iteration will also include the item we are adding here? If so, I don't think we can rely on that. What do you think of this scenario? 🤔

Copy link
Member

Choose a reason for hiding this comment

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

With more testing now, I think this is an actual problem if there is a 3rd level of dependencies in the tree, e.g. like xpkg.upbound.io/upbound/platform-ref-azure:v0.11.0 has. If there are only 2 levels of dependencies, then they can be added here and it doesn't matter if the iteration misses them because they have no further dependencies to find. However, if there is a 3rd level, and we miss a package at the 2nd level because we've added it to the map during our iteration of it, we will miss those 3rd+ level dependencies.

You can see this by running the commands in https://gist.github.com/jbw976/51d81caf0ece87e2bb6c64418ece8a8d#file-inconsistent-behavior for platform-ref-azure multiple times - you get an inconsistent number of dependencies found/downloaded each time. For example:

❯ export CCACHE="/Users/Jared/.crossplane/cache"; rm -fr "${CCACHE}"; go run cmd/crank/main.go beta validate ~/Desktop/crossplane/test/5809/config-plat-ref-azure.yaml ~/Desktop/crossplane/test/5809/resources --cache-dir="${CCACHE}" | tee cmd-out.txt; cat cmd-out.txt | wc -l
<packages ommitted>
      15
> <run again>
      13
> <run again>
      11

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm yes it looks like we have a bug here. I will be changing it to a new recursive approach that adds configurations and their dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hopefully this problematic situation is fixed with the recursive approach introduced by 70cc678

@jbw976
Copy link
Member

jbw976 commented Jul 9, 2024

I added the examples now @jbw976 thanks for the suggestion!

Awesome, that is definitely helpful @enesonus! If I could humbly provide a bit more opinion on how you've included these testing scenarios in the PR... 🙇‍♂️ 😇

The commands you have look similar to:

go run cmd/crank/main.go beta validate .work/xfn/config-aws-db.yaml .work/xfn/

I'm not sure everyone 100% agrees with me 😅, but I am very appreciative when I come to review a PR and I don't have to think or put much effort into recreating the testing scenarios the author is describing. I'm a bit slow 🐢, so it's ideal at least for me when the testing scenarios can be completely copy/pasted without any further work or thinking required at least to run them. Certainly there is thinking needed to evaluate and verify them, but getting the effort to run them down to 0 is really great.

All that to say - do you have examples of what is in your .work/xfn directory too? does it have other YAML files? I'd love to know exactly what you are testing so I can reproduce it exactly. If there are multiple files involved in a testing/repro scenario, it can be helpful to include them in a gist on https://gist.github.com/ so they don't clutter up the PR description too much.

Does that make sense? Other maintainers may not be as lazy, yet still thorough, as me 😂

EDIT: I found a bit more time today, so I got the testing scenario set up myself too - it wasn't too hard 😉. Basically, config-aws-db.yaml and config-plat-ref-azure.yaml are simple Configuration.pkg.crossplane.io that specify the full configuration package version, like xpkg.upbound.io/upbound/configuration-aws-database:v0.10.0. Then, the .work/xfn folder can be an entirely empty resources directory because we don't actually care about validating any resources, we care about downloading/caching the dependencies.

My setup/commands can be found in https://gist.github.com/jbw976/51d81caf0ece87e2bb6c64418ece8a8d

Copy link
Member

@jbw976 jbw976 left a comment

Choose a reason for hiding this comment

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

I got a chance to do further testing and it looks like there is a bug here for deeper dependency trees - do you want to take a deeper look to check my findings @enesonus, and then if needed update this PR with a fix? thank you! 🙇‍♂️

m.deps[image] = true

if _, ok := m.confs[image]; !ok && dep.Configuration != nil {
m.confs[image] = true
Copy link
Member

Choose a reason for hiding this comment

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

With more testing now, I think this is an actual problem if there is a 3rd level of dependencies in the tree, e.g. like xpkg.upbound.io/upbound/platform-ref-azure:v0.11.0 has. If there are only 2 levels of dependencies, then they can be added here and it doesn't matter if the iteration misses them because they have no further dependencies to find. However, if there is a 3rd level, and we miss a package at the 2nd level because we've added it to the map during our iteration of it, we will miss those 3rd+ level dependencies.

You can see this by running the commands in https://gist.github.com/jbw976/51d81caf0ece87e2bb6c64418ece8a8d#file-inconsistent-behavior for platform-ref-azure multiple times - you get an inconsistent number of dependencies found/downloaded each time. For example:

❯ export CCACHE="/Users/Jared/.crossplane/cache"; rm -fr "${CCACHE}"; go run cmd/crank/main.go beta validate ~/Desktop/crossplane/test/5809/config-plat-ref-azure.yaml ~/Desktop/crossplane/test/5809/resources --cache-dir="${CCACHE}" | tee cmd-out.txt; cat cmd-out.txt | wc -l
<packages ommitted>
      15
> <run again>
      13
> <run again>
      11

@enesonus
Copy link
Contributor Author

All that to say - do you have examples of what is in your .work/xfn directory too? does it have other YAML files? I'd love to know exactly what you are testing so I can reproduce it exactly. If there are multiple files involved in a testing/repro scenario, it can be helpful to include them in a gist on https://gist.github.com/ so they don't clutter up the PR description too much.

These are very valuable feedbacks on my side @jbw976! I wasn't very aware of how powerful was the github gists. I tried to make PR description as brief as possible so I did not add details. I will try to create a gist for this PR on how I was testing it.

@enesonus enesonus force-pushed the download-all-config-deps branch from 82b25e0 to 70cc678 Compare July 13, 2024 09:05
@enesonus
Copy link
Contributor Author

I changed the dependency addition function (m *Manager) addDependencies() to the new recursive (m *Manager) addDependencies(confs map[string]bool) so that we can go deeper at configurations. At this PR I declared m.confs variable type as map[string]bool but we have a possible type change at PR #5815 . We will probably need to merge #5815 before this PR and update the m.confs type in this one before merging.

I created a script that runs the beta validate N times on a configuration yaml to check if it outputs the same number of lines at dependency download phase. Here is the gist on how to test this code with that script. The gist you provided was really helpful, thanks for that one @jbw976!

@jbw976
Copy link
Member

jbw976 commented Jul 18, 2024

Very cool @enesonus, I was able to use your gist and testing script to get reliable download results as well. Looks like this approach is working well!

Quick question about the test script: https://gist.github.com/enesonus/481dd30a911f6e27c1d03c52d0fad1aa#file-test_add_dep-sh-L24. What does that kubectl context check for? I don't see kubectl used anywhere else, so it didn't seem needed to me. I actually removed the check from the script when I was running it 😇

@enesonus
Copy link
Contributor Author

Quick question about the test script: https://gist.github.com/enesonus/481dd30a911f6e27c1d03c52d0fad1aa#file-test_add_dep-sh-L24. What does that kubectl context check for? I don't see kubectl used anywhere else, so it didn't seem needed to me. I actually removed the check from the script when I was running it 😇

TBH I dont really know what it actually affects 😅 At my initial run of script I got:

[!] could not find CRD/XRD for: /apiextensions.crossplane.io, Kind=Composition

I tried some different things and somehow it got fixed. I didn't understand what fixed it so did not want to remove it and possibly break it again 😅 I tried running it on a different computer, it was running so I didnt spend much time thinking on the script's code :)

@enesonus enesonus force-pushed the download-all-config-deps branch from 70cc678 to 089a5df Compare July 24, 2024 10:59
Copy link
Member

@jbw976 jbw976 left a comment

Choose a reason for hiding this comment

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

Pretty much looks good to me now @enesonus! thank you for continuing to work on this. Just a bit of clean-up on comments for the unit test, then we can get this merged 😉

Comment on lines +321 to +322
confs: 2, // 1 Base Configuration, 1 Child Configuration
deps: 4, // 2 Configurations, 1 provider, 1 function
Copy link
Member

Choose a reason for hiding this comment

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

listing out the names of each would be a bit more helpful to understand here, e.g.:

// 1 Base configuration (config-dep-1), 1 child configuration (config-dep-2)
// 2 configurations (config-dep-1, config-dep-2), 1 provider (provider-dep-1), 1 function (function-dep-1)

fs := afero.NewMemMapFs()
w := &bytes.Buffer{}

m := NewManager(".crossplane/cache", fs, w)
Copy link
Member

Choose a reason for hiding this comment

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

does the global cache change from #5839 affect this cache usage in unit tests? i.e. if this will no longer be a relative path, where does it go? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually this cache is not even used since we get the yaml files from a MockFetcher. Normally this would create .crossplane/cache directory at the current directory and use it as a cache for next calls but we dont use it. I will change this to "" to prevent misunderstandings.

enesonus and others added 4 commits July 30, 2024 17:54
Signed-off-by: Mehmet Enes <menes.onus@gmail.com>
Signed-off-by: Mehmet Enes <menes.onus@gmail.com>
Signed-off-by: Mehmet Enes <menes.onus@gmail.com>
Co-authored-by: Jared Watts <jbw976@gmail.com>
Signed-off-by: Mehmet Enes <94247411+enesonus@users.noreply.github.com>
@enesonus enesonus force-pushed the download-all-config-deps branch from 3b3be23 to a6632ac Compare July 30, 2024 15:15
@jbw976
Copy link
Member

jbw976 commented Jul 30, 2024

Ah darn @enesonus, was just about to merge this but it looks like the last commit is failing the DCO check:

Could you amend that commit with the sign-off (https://github.com/crossplane/crossplane/tree/master/contributing#certificate-of-origin), then we can merge? 🙏

Signed-off-by: Mehmet Enes <menes.onus@gmail.com>
@enesonus enesonus force-pushed the download-all-config-deps branch from a6632ac to 93dff5d Compare July 31, 2024 05:18
@enesonus
Copy link
Contributor Author

enesonus commented Jul 31, 2024

Ahh sorry, I changed my laptop and I forgot to configure auto sign 😅 It should be good to go now

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.

validate command should download/cache full graph of dependencies

3 participants