feat(helm): Add helm dependencies support#9624
feat(helm): Add helm dependencies support#9624alphanota merged 7 commits intoGoogleContainerTools:mainfrom
Conversation
ghost
left a comment
There was a problem hiding this comment.
Hi team,
I'm currently reviewing this pull request and will post my detailed review in a few minutes. In the meantime, here's a quick summary to help you and other reviewers get up to speed:
This pull request adds support for specifying Helm release dependencies using a dependsOn field. This is particularly useful when deploying multiple Helm releases concurrently, a feature introduced in PR #9451. The intent is to ensure that releases are deployed in the correct order, preventing issues caused by dependencies not being met.
Here's a breakdown of the changes:
- Schema Update (
docs-v2/content/en/schemas/v4beta12.json):- Lines 2369-2383: Added the
dependsOnfield to the Helm release schema. This field is an array of strings, each representing the name of a Helm release that the current release depends on. A default empty array is provided. - Lines 2484-2497: Updated the
propertiesarray within the schema to includedependsOn.
- Lines 2369-2383: Added the
- Deploy Logic Update (
pkg/skaffold/deploy/helm/helm.go):- Extensive changes (lines 261-354) were made to the Helm deployer to handle dependencies. This includes building a dependency graph, verifying for cycles, calculating deployment order, and grouping releases by dependency level to ensure correct execution order.
- New functions
calculateDeploymentOrder(lines 697-729) andgroupReleasesByLevel(lines 731-757) were added to manage dependency resolution.
- **Default Configuration Update (
pkg/skaffold/schema/defaults/defaults.go):- Lines 20-26: Added an import for the new Helm dependency functions.
- Lines 46-53: Modified the
setHelmDefaultsfunction to handle dependency graph verification. - Lines 114-143: The
setHelmDefaultsfunction now verifies the dependency graph for cycles if more than one release is defined.
- Skaffold Configuration Update (
pkg/skaffold/schema/latest/config.go):- Lines 1070-1076: Added the
DependsOnfield to theHelmReleasestruct.
- Lines 1070-1076: Added the
This PR significantly enhances the Helm deployment capabilities of Skaffold by enabling dependency management for concurrent deployments. The added dependency graph verification helps prevent deployment failures due to circular dependencies.
Let me know if you have any questions.
And now, a little haiku to lighten the mood:
Dependencies flow,
Code compiles, tests all pass,
Joyful release day!
ghost
left a comment
There was a problem hiding this comment.
This pull request introduces support for Helm dependencies using the dependsOn field. This is a valuable addition for managing complex Helm deployments. The implementation looks good overall, and addresses a clear need for managing dependencies between Helm releases within Skaffold. The changes are well-structured and follow good coding practices. The addition of dependency management is a significant improvement to Skaffold's Helm deployment capabilities.
Summary of Style Guide References:
- Error Wrapping: Used
fmt.Errorfwith%wfor error wrapping to preserve error context (as recommended by the Effective Go guide). - Function Naming: Descriptive function names like
calculateDeploymentOrderandgroupReleasesByLeveladhere to Go conventions. - Comment Clarity: Comments were added to explain complex logic and data structures.
- Concurrency Control: The use of mutexes ensures safe concurrent access to shared resources.
README Suggestions:
The README should be updated to include documentation for the new dependsOn feature. This should include:
- A clear explanation of the feature and its purpose.
- Examples of how to use
dependsOnin askaffold.yamlfile. - An explanation of how dependency resolution works.
- A section on best practices for managing Helm dependencies with Skaffold.
- Information on any limitations or known issues.
Additional Considerations:
- Testing: Add comprehensive unit tests for the new functions, including
BuildDependencyGraph,VerifyNoCycles,calculateDeploymentOrder, andgroupReleasesByLevel. These tests should cover various scenarios, including valid and invalid dependency graphs, and ensure correct deployment order. - Error Handling: While the error handling is generally good, consider adding more specific error messages to provide better context in case of failures. For example, in
BuildDependencyGraph, if a dependency is not found, the error message could indicate the missing release name. - Edge Cases: Consider testing with a larger number of releases and more complex dependency graphs to ensure robustness and identify potential performance bottlenecks.
| releaseNameToRelease := make(map[string]latest.HelmRelease) | ||
| for _, r := range h.Releases { | ||
| g.Go(func() error { | ||
| releaseName, err := util.ExpandEnvTemplateOrFail(r.Name, nil) | ||
| if err != nil { | ||
| return helm.UserErr(fmt.Sprintf("cannot expand release name %q", r.Name), err) | ||
| } | ||
| chartVersion, err := util.ExpandEnvTemplateOrFail(r.Version, nil) | ||
| if err != nil { | ||
| return helm.UserErr(fmt.Sprintf("cannot expand chart version %q", r.Version), err) | ||
| } | ||
| releaseName, err := util.ExpandEnvTemplateOrFail(r.Name, nil) | ||
| if err != nil { | ||
| return fmt.Errorf("cannot parse the release name template: %w", err) | ||
| } | ||
| releaseNameToRelease[releaseName] = r |
There was a problem hiding this comment.
It's good practice to check for errors after calling util.ExpandEnvTemplateOrFail, even though the function name suggests it will fail. This makes the error handling more explicit and robust. See Effective Go's section on error handling.
| releaseNameToRelease := make(map[string]latest.HelmRelease) | |
| for _, r := range h.Releases { | |
| g.Go(func() error { | |
| releaseName, err := util.ExpandEnvTemplateOrFail(r.Name, nil) | |
| if err != nil { | |
| return helm.UserErr(fmt.Sprintf("cannot expand release name %q", r.Name), err) | |
| } | |
| chartVersion, err := util.ExpandEnvTemplateOrFail(r.Version, nil) | |
| if err != nil { | |
| return helm.UserErr(fmt.Sprintf("cannot expand chart version %q", r.Version), err) | |
| } | |
| releaseName, err := util.ExpandEnvTemplateOrFail(r.Name, nil) | |
| if err != nil { | |
| return fmt.Errorf("cannot parse the release name template: %w", err) | |
| } | |
| releaseNameToRelease[releaseName] = r | |
| releaseNameToRelease := make(map[string]latest.HelmRelease) | |
| for _, r := range h.Releases { | |
| releaseName, err := util.ExpandEnvTemplateOrFail(r.Name, nil) | |
| if err != nil { | |
| return fmt.Errorf("cannot parse the release name template: %w", err) | |
| } | |
| releaseNameToRelease[releaseName] = r | |
| } |
pkg/skaffold/deploy/helm/helm.go
Outdated
| // Level 0 contains releases with no dependencies | ||
| // Level 1 contains releases that depend only on level 0 releases | ||
| // And so on... | ||
| func groupReleasesByLevel(order []string, graph map[string][]string) map[int][]string { |
There was a problem hiding this comment.
Consider adding a more detailed explanation of the leveling algorithm in the comment. This will improve understanding of the code's logic. Per the Effective Go guide, comments should provide context and explain complex algorithms.
| func groupReleasesByLevel(order []string, graph map[string][]string) map[int][]string { | |
| // groupReleasesByLevel groups releases by their dependency level. | |
| // Level 0 contains releases with no dependencies. | |
| // Level 1 contains releases that depend only on level 0 releases, and so on. | |
| // This grouping ensures that releases are deployed in the correct order, | |
| // respecting dependencies. |
3fdec62 to
2ca31da
Compare
|
@idsulik Thanks for this PR. Can you please take a look at the failing unit tests? Thanks! |
|
@alphanota pushed fix |
|
@alphanota, I'm wondering about the next release. Do you know when it will be? |
b799626 to
caa3728
Compare
|
@alphanota hi! Could you please check the PR? p.s. is there any plan to release the new version? |
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
f96187e to
4f63704
Compare
Description
Added
dependsOnto the helm release to specify dependencies, it requires when you use concurrency releases installation that was introduced here #9451The idea for the
dependsOnfeature goes to @orlandoburli (#9588), happy to close this PR if you'd prefer to implement it yourself!