Skip to content

Commit

Permalink
feat: implement source refs for helm set-file
Browse files Browse the repository at this point in the history
In multi-source applications helm values files can come from other repos
if you use the ref syntax but it is not possible for the --set-file
param to take files from other repos via the ref syntax. This extends
the behavior to cover set-file parameters as well as the values files.
fixes argoproj#13220, refs argoproj#17822

Signed-off-by: Doug Goldstein <cardoe@cardoe.com>
  • Loading branch information
cardoe committed Apr 27, 2024
1 parent 575575a commit e04ede0
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 7 deletions.
4 changes: 2 additions & 2 deletions docs/user-guide/helm.md
Expand Up @@ -220,8 +220,8 @@ source:
value: path/to/file.ext
```

!!! warning "Reference in multiple sources not supported"
Please note that using a multiple sources application will not let you load the file by reference. See [argoproj/argo-cd#13220](https://github.com/argoproj/argo-cd/issues/13220)
!!! warning "Reference in multiple sources not supported prior to ArgoCD 2.12"
Please note that using a multiple sources application will not let you load the file by reference when using ArgoCD versions prior to 2.12

## Helm Release Name

Expand Down
32 changes: 27 additions & 5 deletions reposerver/repository/repository.go
Expand Up @@ -474,7 +474,13 @@ func resolveReferencedSources(hasMultipleSources bool, source *v1alpha1.Applicat
return repoRefs, nil
}

for _, valueFile := range source.ValueFiles {
refFileParams := make([]string, 0)
for _, fileParam := range source.FileParameters {
refFileParams = append(refFileParams, fileParam.Path)
}
refCandidates := append(source.ValueFiles, refFileParams...)

for _, valueFile := range refCandidates {
if strings.HasPrefix(valueFile, "$") {
refVar := strings.Split(valueFile, "/")[0]

Expand Down Expand Up @@ -715,8 +721,14 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA,
if q.HasMultipleSources {
if q.ApplicationSource.Helm != nil {

refFileParams := make([]string, 0)
for _, fileParam := range q.ApplicationSource.Helm.FileParameters {
refFileParams = append(refFileParams, fileParam.Path)
}
refCandidates := append(q.ApplicationSource.Helm.ValueFiles, refFileParams...)

// Checkout every one of the referenced sources to the target revision before generating Manifests
for _, valueFile := range q.ApplicationSource.Helm.ValueFiles {
for _, valueFile := range refCandidates {
if strings.HasPrefix(valueFile, "$") {
refVar := strings.Split(valueFile, "/")[0]

Expand Down Expand Up @@ -1168,9 +1180,19 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
}
}
for _, p := range appHelm.FileParameters {
resolvedPath, _, err := pathutil.ResolveValueFilePathOrUrl(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes())
if err != nil {
return nil, fmt.Errorf("error resolving helm value file path: %w", err)
var resolvedPath pathutil.ResolvedFilePath
referencedSource := getReferencedSource(p.Path, q.RefSources)
if referencedSource != nil {
// If the $-prefixed path appears to reference another source, do env substituion _after_ resolving the source
resolvedPath, err = getResolvedRefValueFile(p.Path, env, q.GetValuesFileSchemes(), referencedSource.Repo.Repo, gitRepoPaths)
if err != nil {
return nil, fmt.Errorf("error resolving set-file path: %w", err)
}
} else {
resolvedPath, _, err = pathutil.ResolveValueFilePathOrUrl(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes())
if err != nil {
return nil, fmt.Errorf("error resolving helm value file path: %w", err)
}
}
templateOpts.SetFile[p.Name] = resolvedPath
}
Expand Down
38 changes: 38 additions & 0 deletions reposerver/repository/repository_test.go
Expand Up @@ -2208,6 +2208,44 @@ func TestGenerateManifestWithAnnotatedTagsAndMultiSourceApp(t *testing.T) {
}
}

func TestGenerateMultiSourceHelmWithFileParameter(t *testing.T) {

service := newService(t, "../../util/helm/testdata")

refSources := map[string]*argoappv1.RefTarget{}

refSources["$global"] = &argoappv1.RefTarget{
TargetRevision: "HEAD",
}

manifestRequest := &apiclient.ManifestRequest{
Repo: &argoappv1.Repository{},
ApplicationSource: &argoappv1.ApplicationSource{
Ref: "$global",
Path: "./redis",
TargetRevision: "HEAD",
Helm: &argoappv1.ApplicationSourceHelm{
ValueFiles: []string{"$global/redis/values-production.yaml"},
FileParameters: []argoappv1.HelmFileParameter{{
Name: "password",
Path: "$global/external/external-secret.txt",
}},
},
},
HasMultipleSources: true,
NoCache: true,
RefSources: refSources,
}

res, err := service.GenerateManifest(context.Background(), manifestRequest)
if err != nil {
t.Errorf("unexpected %s", err)
}

assert.NoError(t, err)
assert.Contains(t, res.Manifests[6], `"replicas":3`, "Values should not be overriden")
}

func TestFindResources(t *testing.T) {
testCases := []struct {
name string
Expand Down

0 comments on commit e04ede0

Please sign in to comment.