diff --git a/internal/rollouts/analysis_run_builder.go b/internal/rollouts/analysis_run_builder.go index 43f2972cd..50c1ec41b 100644 --- a/internal/rollouts/analysis_run_builder.go +++ b/internal/rollouts/analysis_run_builder.go @@ -67,7 +67,7 @@ func (b *AnalysisRunBuilder) Build( opts.ExtraLabels, ) - templates, err := b.getAnalysisTemplates( + analysisTemplates, clusterAnalysisTemplates, err := b.getAnalysisTemplates( ctx, namespace, cfg.AnalysisTemplates, @@ -76,7 +76,9 @@ func (b *AnalysisRunBuilder) Build( return nil, fmt.Errorf("get analysis templates: %w", err) } - spec, err := b.buildSpec(templates, cfg.Args) + analysisTemplateSpecs := combineAnalysisTemplateSpecs(analysisTemplates, clusterAnalysisTemplates) + + spec, err := b.buildSpec(analysisTemplateSpecs, cfg.Args) if err != nil { return nil, fmt.Errorf("build spec: %w", err) } @@ -149,10 +151,10 @@ func (b *AnalysisRunBuilder) buildMetadata( // buildSpec constructs an AnalysisRunSpec from the provided templates and // arguments. func (b *AnalysisRunBuilder) buildSpec( - templates []*rolloutsapi.AnalysisTemplate, + analysisTemplateSpecs []*rolloutsapi.AnalysisTemplateSpec, args []kargoapi.AnalysisRunArgument, ) (rolloutsapi.AnalysisRunSpec, error) { - template, err := flattenTemplates(templates) + template, err := flattenTemplates(analysisTemplateSpecs) if err != nil { return rolloutsapi.AnalysisRunSpec{}, fmt.Errorf("flatten templates: %w", err) } @@ -238,24 +240,51 @@ func (b *AnalysisRunBuilder) getAnalysisTemplates( ctx context.Context, namespace string, references []kargoapi.AnalysisTemplateReference, -) ([]*rolloutsapi.AnalysisTemplate, error) { - templates := make([]*rolloutsapi.AnalysisTemplate, len(references)) - - for i, ref := range references { - template := &rolloutsapi.AnalysisTemplate{} - if err := b.client.Get(ctx, types.NamespacedName{ - Namespace: namespace, - Name: ref.Name, - }, template); err != nil { - return nil, fmt.Errorf( - "get AnalysisRun %q in namespace %q: %w", - ref.Name, - namespace, - err, - ) +) ([]*rolloutsapi.AnalysisTemplate, []*rolloutsapi.ClusterAnalysisTemplate, error) { + analysisTemplates := []*rolloutsapi.AnalysisTemplate{} + clusterAnalysisTemplates := []*rolloutsapi.ClusterAnalysisTemplate{} + for _, ref := range references { + if ref.ClusterScope { + template := &rolloutsapi.ClusterAnalysisTemplate{} + if err := b.client.Get(ctx, types.NamespacedName{ + Name: ref.Name, + }, template); err != nil { + return nil, nil, fmt.Errorf( + "get ClusterAnalysisRun %q: %w", + ref.Name, + err, + ) + } + clusterAnalysisTemplates = append(clusterAnalysisTemplates, template) + } else { + template := &rolloutsapi.AnalysisTemplate{} + if err := b.client.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: ref.Name, + }, template); err != nil { + return nil, nil, fmt.Errorf( + "get AnalysisRun %q in namespace %q: %w", + ref.Name, + namespace, + err, + ) + } + analysisTemplates = append(analysisTemplates, template) } - templates[i] = template } - return templates, nil + return analysisTemplates, clusterAnalysisTemplates, nil +} + +// combineAnalysisTemplateSpecs combines the specs of analysis +// templates and cluster analysis templates into one array +func combineAnalysisTemplateSpecs(analysisTemplates []*rolloutsapi.AnalysisTemplate, clusterAnalysisTemplates []*rolloutsapi.ClusterAnalysisTemplate) []*rolloutsapi.AnalysisTemplateSpec { + templateSpecs := make([]*rolloutsapi.AnalysisTemplateSpec, 0, len(analysisTemplates)+len(clusterAnalysisTemplates)) + for _, template := range analysisTemplates { + templateSpecs = append(templateSpecs, &template.Spec) + } + for _, template := range clusterAnalysisTemplates { + templateSpecs = append(templateSpecs, &template.Spec) + } + return templateSpecs } diff --git a/internal/rollouts/analysis_template.go b/internal/rollouts/analysis_template.go index d7281b6cd..14df76ed8 100644 --- a/internal/rollouts/analysis_template.go +++ b/internal/rollouts/analysis_template.go @@ -9,23 +9,23 @@ import ( // flattenTemplates combines multiple analysis templates into a single // template. It merges metrics, dry-run metrics, measurement retention // metrics, and arguments. -func flattenTemplates(templates []*rolloutsapi.AnalysisTemplate) (*rolloutsapi.AnalysisTemplate, error) { - metrics, err := flattenMetrics(templates) +func flattenTemplates(analysisTemplateSpecs []*rolloutsapi.AnalysisTemplateSpec) (*rolloutsapi.AnalysisTemplate, error) { + metrics, err := flattenMetrics(analysisTemplateSpecs) if err != nil { return nil, fmt.Errorf("flatten metrics: %w", err) } - dryRun, err := flattenDryRunMetrics(templates) + dryRun, err := flattenDryRunMetrics(analysisTemplateSpecs) if err != nil { return nil, fmt.Errorf("flatten dry-run metrics: %w", err) } - retention, err := flattenMeasurementRetentionMetrics(templates) + retention, err := flattenMeasurementRetentionMetrics(analysisTemplateSpecs) if err != nil { return nil, fmt.Errorf("flatten measurement retention metrics: %w", err) } - args, err := flattenArgs(templates) + args, err := flattenArgs(analysisTemplateSpecs) if err != nil { return nil, fmt.Errorf("flatten arguments: %w", err) } @@ -42,12 +42,12 @@ func flattenTemplates(templates []*rolloutsapi.AnalysisTemplate) (*rolloutsapi.A // flattenMetrics combines metrics from multiple templates while ensuring // unique names. -func flattenMetrics(templates []*rolloutsapi.AnalysisTemplate) ([]rolloutsapi.Metric, error) { - metrics := make([]rolloutsapi.Metric, 0, len(templates)) +func flattenMetrics(analysisTemplateSpecs []*rolloutsapi.AnalysisTemplateSpec) ([]rolloutsapi.Metric, error) { + metrics := make([]rolloutsapi.Metric, 0, len(analysisTemplateSpecs)) seen := make(map[string]struct{}) - for _, tmpl := range templates { - for _, metric := range tmpl.Spec.Metrics { + for _, analysisTmplSpec := range analysisTemplateSpecs { + for _, metric := range analysisTmplSpec.Metrics { if _, exists := seen[metric.Name]; exists { return nil, fmt.Errorf("duplicate metric name: %q", metric.Name) } @@ -60,11 +60,11 @@ func flattenMetrics(templates []*rolloutsapi.AnalysisTemplate) ([]rolloutsapi.Me } // flattenDryRunMetrics combines dry-run metrics from multiple templates. -func flattenDryRunMetrics(templates []*rolloutsapi.AnalysisTemplate) ([]rolloutsapi.DryRun, error) { - dryRun := make([]rolloutsapi.DryRun, 0, len(templates)) +func flattenDryRunMetrics(analysisTemplateSpecs []*rolloutsapi.AnalysisTemplateSpec) ([]rolloutsapi.DryRun, error) { + dryRun := make([]rolloutsapi.DryRun, 0, len(analysisTemplateSpecs)) - for _, tmpl := range templates { - dryRun = append(dryRun, tmpl.Spec.DryRun...) + for _, tmplSpec := range analysisTemplateSpecs { + dryRun = append(dryRun, tmplSpec.DryRun...) } if err := validateUniqueDryRunMetrics(dryRun); err != nil { @@ -77,12 +77,12 @@ func flattenDryRunMetrics(templates []*rolloutsapi.AnalysisTemplate) ([]rollouts // flattenMeasurementRetentionMetrics combines measurement retention metrics // from multiple templates. func flattenMeasurementRetentionMetrics( - templates []*rolloutsapi.AnalysisTemplate, + analysisTemplateSpecs []*rolloutsapi.AnalysisTemplateSpec, ) ([]rolloutsapi.MeasurementRetention, error) { - retention := make([]rolloutsapi.MeasurementRetention, 0, len(templates)) + retention := make([]rolloutsapi.MeasurementRetention, 0, len(analysisTemplateSpecs)) - for _, tmpl := range templates { - retention = append(retention, tmpl.Spec.MeasurementRetention...) + for _, tmplSpec := range analysisTemplateSpecs { + retention = append(retention, tmplSpec.MeasurementRetention...) } if err := validateUniqueMeasurementRetentionMetrics(retention); err != nil { @@ -94,7 +94,7 @@ func flattenMeasurementRetentionMetrics( // flattenArgs combines arguments from multiple templates, handling conflicts // and updates. -func flattenArgs(templates []*rolloutsapi.AnalysisTemplate) ([]rolloutsapi.Argument, error) { +func flattenArgs(analysisTemplateSpecs []*rolloutsapi.AnalysisTemplateSpec) ([]rolloutsapi.Argument, error) { var combinedArgs []rolloutsapi.Argument updateOrAppend := func(newArg rolloutsapi.Argument) error { @@ -111,8 +111,8 @@ func flattenArgs(templates []*rolloutsapi.AnalysisTemplate) ([]rolloutsapi.Argum return nil } - for _, tmpl := range templates { - for _, arg := range tmpl.Spec.Args { + for _, tmplSpec := range analysisTemplateSpecs { + for _, arg := range tmplSpec.Args { if err := updateOrAppend(arg); err != nil { return nil, err }