@@ -18,18 +18,113 @@ package generateManifest
1818
1919import (
2020 "context"
21+ "errors"
2122 "fmt"
23+ "os"
24+ "path/filepath"
25+ "strings"
26+
2227 "github.com/devtron-labs/common-lib/utils/yaml"
2328 "github.com/devtron-labs/devtron/api/helm-app/gRPC"
2429 "github.com/devtron-labs/devtron/internal/sql/repository/app"
2530 "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig"
2631 clusterBean "github.com/devtron-labs/devtron/pkg/cluster/bean"
2732 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository"
33+ "github.com/go-pg/pg"
2834 "go.opentelemetry.io/otel"
2935 "golang.org/x/exp/maps"
3036 k8sYaml "sigs.k8s.io/yaml"
3137)
3238
39+ const (
40+ releaseValuesYamlFile = "release-values.yaml"
41+ releaseValuesYmlFile = "release-values.yml"
42+ imageDescriptorTemplateFile = ".image_descriptor_template.json"
43+ )
44+
45+ // readReleaseValuesJsonFromRefChart looks for release-values.yaml / release-values.yml
46+ // at the root of the reference chart directory and returns its content converted to
47+ // JSON. Returns an empty string (without erroring the caller) when the file is absent
48+ // or unreadable — not every chart defines release overrides, and manifest generation
49+ // must still proceed. This mirrors the file-discovery logic in
50+ // ChartTemplateServiceImpl.getValues so behaviour matches the save-time path.
51+ func (impl DeploymentTemplateServiceImpl ) readReleaseValuesJsonFromRefChart (refChartPath string ) string {
52+ data , ok := impl .readFileFromRefChart (refChartPath , releaseValuesYamlFile , releaseValuesYmlFile )
53+ if ! ok {
54+ return ""
55+ }
56+ jsonBytes , err := k8sYaml .YAMLToJSON (data )
57+ if err != nil {
58+ impl .Logger .Errorw ("error in converting release-values yaml to json" , "refChartPath" , refChartPath , "err" , err )
59+ return ""
60+ }
61+ return string (jsonBytes )
62+ }
63+
64+ // readImageDescriptorTemplateFromRefChart reads .image_descriptor_template.json from
65+ // the reference chart directory. Used when the chart hasn't been saved to the DB yet
66+ // and chartDto.ImageDescriptorTemplate isn't available. Returns an empty string on
67+ // missing file / read error — RenderJson handles an empty template gracefully.
68+ func (impl DeploymentTemplateServiceImpl ) readImageDescriptorTemplateFromRefChart (refChartPath string ) string {
69+ data , ok := impl .readFileFromRefChart (refChartPath , imageDescriptorTemplateFile )
70+ if ! ok {
71+ return ""
72+ }
73+ return string (data )
74+ }
75+
76+ // readFileFromRefChart scans refChartPath (non-recursive) for the first file whose
77+ // name (case-insensitive) matches one of fileNames and returns its contents. ok=false
78+ // means the path was empty, unreadable, or the file was absent — all logged at the
79+ // appropriate level by the caller's context.
80+ func (impl DeploymentTemplateServiceImpl ) readFileFromRefChart (refChartPath string , fileNames ... string ) (data []byte , ok bool ) {
81+ if len (refChartPath ) == 0 {
82+ return nil , false
83+ }
84+ entries , err := os .ReadDir (refChartPath )
85+ if err != nil {
86+ impl .Logger .Errorw ("error in reading ref chart dir" , "refChartPath" , refChartPath , "err" , err )
87+ return nil , false
88+ }
89+ targets := make (map [string ]struct {}, len (fileNames ))
90+ for _ , name := range fileNames {
91+ targets [strings .ToLower (name )] = struct {}{}
92+ }
93+ for _ , entry := range entries {
94+ if entry .IsDir () {
95+ continue
96+ }
97+ if _ , match := targets [strings .ToLower (entry .Name ())]; ! match {
98+ continue
99+ }
100+ path := filepath .Clean (filepath .Join (refChartPath , entry .Name ()))
101+ contents , err := os .ReadFile (path )
102+ if err != nil {
103+ impl .Logger .Errorw ("error in reading file from ref chart" , "path" , path , "err" , err )
104+ return nil , false
105+ }
106+ return contents , true
107+ }
108+ return nil , false
109+ }
110+
111+ // resolveImageDescriptorTemplate returns the image descriptor template for the app's
112+ // chart. It prefers the saved chart in DB; if no chart has been saved for this
113+ // (appId, chartRefId) pair (pg.ErrNoRows), it falls back to the reference chart's
114+ // .image_descriptor_template.json on disk so manifest rendering works before save.
115+ // Any other DB error is returned to the caller.
116+ func (impl DeploymentTemplateServiceImpl ) resolveImageDescriptorTemplate (appId , chartRefId int , refChartPath string ) (string , error ) {
117+ chartDto , err := impl .chartReadService .GetByAppIdAndChartRefId (appId , chartRefId )
118+ if err == nil {
119+ return chartDto .ImageDescriptorTemplate , nil
120+ }
121+ if ! errors .Is (err , pg .ErrNoRows ) {
122+ impl .Logger .Errorw ("error in getting chart by appId and chartRefId" , "appId" , appId , "chartRefId" , chartRefId , "err" , err )
123+ return "" , err
124+ }
125+ return impl .readImageDescriptorTemplateFromRefChart (refChartPath ), nil
126+ }
127+
33128// mergeReleaseOverrideIntoValuesYaml merges the chart's ReleaseOverride JSON
34129// on top of the given values YAML. On any failure the input valuesYaml is
35130// returned unchanged so template rendering can still proceed.
0 commit comments