Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions pkg/apis/application/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,19 @@ func (a *ApplicationSpec) GetSource() ApplicationSource {
return ApplicationSource{}
}

func (a *ApplicationSpec) GetSources() ApplicationSources {
if a.HasMultipleSources() {
return a.Sources
}
if a.Source != nil {
if a.Source == nil {
return ApplicationSources{}
}
return ApplicationSources{*a.Source}
}
return ApplicationSources{}
}

func (a *ApplicationSpec) HasMultipleSources() bool {
return a.Sources != nil && len(a.Sources) > 0
}
Expand Down
4 changes: 2 additions & 2 deletions reposerver/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,8 +942,8 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
pathStrings := strings.Split(val, "/")
refVar := strings.Split(val, "/")[0]
refSourceRepo := q.RefSources[refVar].Repo.Repo
repoPath, err := gitRepoPaths.GetPath(refSourceRepo)
if err != nil {
repoPath := gitRepoPaths.GetPathIfExists(git.NormalizeGitURL(refSourceRepo))
if repoPath == "" {
log.Warnf("Failed to find path for ref %s", refVar)
continue
}
Expand Down
258 changes: 139 additions & 119 deletions util/argo/argo.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ func ValidateRepo(
settingsMgr *settings.SettingsManager,
) ([]argoappv1.ApplicationCondition, error) {
spec := &app.Spec
var kustomizeOptions *argoappv1.KustomizeOptions

conditions := make([]argoappv1.ApplicationCondition, 0)

Expand Down Expand Up @@ -241,63 +240,21 @@ func ValidateRepo(
return nil, fmt.Errorf("error getting enabled source types: %w", err)
}

// If source is Kustomize add build options
kustomizeSettings, err := settingsMgr.GetKustomizeSettings()
if err != nil {
return nil, fmt.Errorf("error getting kustomize settings: %w", err)
}

sourceCondition := make([]argoappv1.ApplicationCondition, 0)
if spec.HasMultipleSources() {
for _, source := range spec.Sources {
kustomizeOptions, err = kustomizeSettings.GetOptions(source)
if err != nil {
return nil, err
}
// stores conditions for each source
var condition []argoappv1.ApplicationCondition
condition, err = validateRepo(
ctx,
app,
db,
&source,
repoClient,
kustomizeOptions,
plugins,
permittedHelmRepos,
helmOptions,
cluster,
apiGroups,
proj,
permittedHelmCredentials,
enabledSourceTypes,
settingsMgr)
// append condition of each source to collection of conditions
sourceCondition = append(sourceCondition, condition...)
}
} else {
source := spec.GetSource()
kustomizeOptions, err = kustomizeSettings.GetOptions(source)
if err != nil {
return nil, err
}
sourceCondition, err = validateRepo(
ctx,
app,
db,
&source,
repoClient,
kustomizeOptions,
plugins,
permittedHelmRepos,
helmOptions,
cluster,
apiGroups,
proj,
permittedHelmCredentials,
enabledSourceTypes,
settingsMgr)
}
sourceCondition, err := validateRepo(
ctx,
app,
db,
app.Spec.GetSources(),
repoClient,
plugins,
permittedHelmRepos,
helmOptions,
cluster,
apiGroups,
proj,
permittedHelmCredentials,
enabledSourceTypes,
settingsMgr)
if err != nil {
return nil, err
}
Expand All @@ -309,9 +266,8 @@ func ValidateRepo(
func validateRepo(ctx context.Context,
app *argoappv1.Application,
db db.ArgoDB,
source *argoappv1.ApplicationSource,
sources []argoappv1.ApplicationSource,
repoClient apiclient.RepoServerServiceClient,
kustomizeOptions *argoappv1.KustomizeOptions,
plugins []*argoappv1.ConfigManagementPlugin,
permittedHelmRepos []*argoappv1.Repository,
helmOptions *argoappv1.HelmOptions,
Expand All @@ -325,45 +281,46 @@ func validateRepo(ctx context.Context,
conditions := make([]argoappv1.ApplicationCondition, 0)
errMessage := ""

repo, err := db.GetRepository(ctx, source.RepoURL)
if err != nil {
return nil, err
}
if err := TestRepoWithKnownType(ctx, repoClient, repo, source.IsHelm(), source.IsHelmOci()); err != nil {
errMessage = fmt.Sprintf("repositories not accessible: %v", repo)
}
repoAccessible := false
for _, source := range sources {
repo, err := db.GetRepository(ctx, source.RepoURL)
if err != nil {
return nil, err
}
if err := TestRepoWithKnownType(ctx, repoClient, repo, source.IsHelm(), source.IsHelmOci()); err != nil {
errMessage = fmt.Sprintf("repositories not accessible: %v", repo)
}
repoAccessible := false

if errMessage != "" {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("repository not accessible: %v", errMessage),
})
} else {
repoAccessible = true
}
if errMessage != "" {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("repository not accessible: %v", errMessage),
})
} else {
repoAccessible = true
}

// Verify only one source type is defined
_, err = source.ExplicitType()
if err != nil {
return nil, fmt.Errorf("error verifying source type: %w", err)
}
// Verify only one source type is defined
_, err = source.ExplicitType()
if err != nil {
return nil, fmt.Errorf("error verifying source type: %w", err)
}

// is the repo inaccessible - abort now
if !repoAccessible {
return conditions, nil
// is the repo inaccessible - abort now
if !repoAccessible {
return conditions, nil
}
}

conditions = append(conditions, verifyGenerateManifests(
ctx,
repo,
db,
permittedHelmRepos,
helmOptions,
app.Name,
app.Spec.Destination,
source,
sources,
repoClient,
kustomizeOptions,
plugins,
cluster.ServerVersion,
APIResourcesToStrings(apiGroups, true),
Expand Down Expand Up @@ -598,49 +555,94 @@ func GetAppProject(app *argoappv1.Application, projLister applicationsv1.AppProj
}

// verifyGenerateManifests verifies a repo path can generate manifests
func verifyGenerateManifests(ctx context.Context, repoRes *argoappv1.Repository, helmRepos argoappv1.Repositories, helmOptions *argoappv1.HelmOptions, name string, dest argoappv1.ApplicationDestination, source *argoappv1.ApplicationSource, repoClient apiclient.RepoServerServiceClient, kustomizeOptions *argoappv1.KustomizeOptions, plugins []*argoappv1.ConfigManagementPlugin, kubeVersion string, apiVersions []string, repositoryCredentials []*argoappv1.RepoCreds, enableGenerateManifests map[string]bool, settingsMgr *settings.SettingsManager, hasMultipleSources bool) []argoappv1.ApplicationCondition {
func verifyGenerateManifests(
ctx context.Context,
db db.ArgoDB,
helmRepos argoappv1.Repositories,
helmOptions *argoappv1.HelmOptions,
name string,
dest argoappv1.ApplicationDestination,
sources []argoappv1.ApplicationSource,
repoClient apiclient.RepoServerServiceClient,
plugins []*argoappv1.ConfigManagementPlugin,
kubeVersion string,
apiVersions []string,
repositoryCredentials []*argoappv1.RepoCreds,
enableGenerateManifests map[string]bool,
settingsMgr *settings.SettingsManager,
hasMultipleSources bool,
) []argoappv1.ApplicationCondition {
var conditions []argoappv1.ApplicationCondition
if dest.Server == "" {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: errDestinationMissing,
})
}
req := apiclient.ManifestRequest{
Repo: &argoappv1.Repository{
Repo: source.RepoURL,
Type: repoRes.Type,
Name: repoRes.Name,
Proxy: repoRes.Proxy,
},
Repos: helmRepos,
Revision: source.TargetRevision,
AppName: name,
Namespace: dest.Namespace,
ApplicationSource: source,
Plugins: plugins,
KustomizeOptions: kustomizeOptions,
KubeVersion: kubeVersion,
ApiVersions: apiVersions,
HelmOptions: helmOptions,
HelmRepoCreds: repositoryCredentials,
TrackingMethod: string(GetTrackingMethod(settingsMgr)),
EnabledSourceTypes: enableGenerateManifests,
NoRevisionCache: true,
HasMultipleSources: hasMultipleSources,
}
req.Repo.CopyCredentialsFromRepo(repoRes)
req.Repo.CopySettingsFrom(repoRes)

// Only check whether we can access the application's path,
// and not whether it actually contains any manifests.
_, err := repoClient.GenerateManifest(ctx, &req)
// If source is Kustomize add build options
kustomizeSettings, err := settingsMgr.GetKustomizeSettings()
if err != nil {
errMessage := fmt.Sprintf("Unable to generate manifests in %s: %s", source.Path, err)
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: errMessage,
Message: fmt.Sprintf("Error getting Kustomize settings: %v", err),
})
return conditions // Can't perform the next check without settings.
}

for _, source := range sources {
repoRes, err := db.GetRepository(ctx, source.RepoURL)
if err != nil {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("Unable to get repository: %v", err),
})
continue
}
kustomizeOptions, err := kustomizeSettings.GetOptions(source)
if err != nil {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("Error getting Kustomize options: %v", err),
})
continue
}
req := apiclient.ManifestRequest{
Repo: &argoappv1.Repository{
Repo: source.RepoURL,
Type: repoRes.Type,
Name: repoRes.Name,
Proxy: repoRes.Proxy,
},
Repos: helmRepos,
Revision: source.TargetRevision,
AppName: name,
Namespace: dest.Namespace,
ApplicationSource: &source,
Plugins: plugins,
KustomizeOptions: kustomizeOptions,
KubeVersion: kubeVersion,
ApiVersions: apiVersions,
HelmOptions: helmOptions,
HelmRepoCreds: repositoryCredentials,
TrackingMethod: string(GetTrackingMethod(settingsMgr)),
EnabledSourceTypes: enableGenerateManifests,
NoRevisionCache: true,
HasMultipleSources: hasMultipleSources,
}
req.Repo.CopyCredentialsFromRepo(repoRes)
req.Repo.CopySettingsFrom(repoRes)
req.RefSources = GetRefSources(sources, *req.Repo, hasMultipleSources)

// Only check whether we can access the application's path,
// and not whether it actually contains any manifests.
_, err = repoClient.GenerateManifest(ctx, &req)
if err != nil {
errMessage := fmt.Sprintf("Unable to generate manifests in %s: %s", source.Path, err)
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: errMessage,
})
}
}

return conditions
Expand Down Expand Up @@ -725,6 +727,24 @@ func NormalizeSource(source *argoappv1.ApplicationSource) *argoappv1.Application
return source
}

func GetRefSources(sources []argoappv1.ApplicationSource, repo argoappv1.Repository, hasMultipleSources bool) map[string]*argoappv1.RefTargeRevisionMapping {
refSources := make(map[string]*argoappv1.RefTargeRevisionMapping)
if hasMultipleSources {
// Get Repositories for all sources before generating Manifests
for _, source := range sources {
if source.Ref != "" {
refKey := "$" + source.Ref
refSources[refKey] = &argoappv1.RefTargeRevisionMapping{
Repo: repo,
TargetRevision: source.TargetRevision,
Chart: source.Chart,
}
}
}
}
return refSources
}

func GetPermittedReposCredentials(proj *argoappv1.AppProject, repoCreds []*argoappv1.RepoCreds) ([]*argoappv1.RepoCreds, error) {
var permittedRepoCreds []*argoappv1.RepoCreds
for _, v := range repoCreds {
Expand Down
10 changes: 10 additions & 0 deletions util/io/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@ func (p *TempPaths) GetPath(key string) (string, error) {
p.paths[key] = repoPath
return repoPath, nil
}

// GetPathIfExists gets a path for the given key if it exists. Otherwise, returns an empty string.
func (p *TempPaths) GetPathIfExists(key string) string {
p.lock.Lock()
defer p.lock.Unlock()
if val, ok := p.paths[key]; ok {
return val
}
return ""
}