@@ -13,8 +13,8 @@ import (
1313 "github.com/ohler55/ojg/jp"
1414 "github.com/samber/lo"
1515
16- "github.com/flanksource/commons/logger"
1716 "github.com/flanksource/commons-db/types"
17+ "github.com/flanksource/commons/logger"
1818 "github.com/patrickmn/go-cache"
1919 authenticationv1 "k8s.io/api/authentication/v1"
2020 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -71,6 +71,46 @@ func GetEnvStringFromCache(ctx Context, env string, namespace string) (string, e
7171 return GetEnvValueFromCache (ctx , envvar , namespace )
7272}
7373
74+ // debugJsonPath is a helper function to visualize the result of a jsonpath expression on some data
75+ // it splits the jsonpath into parts, and then applies each part sequentially, printing the intermediate success
76+ // and highlighting which part failed, and what the available keys where at the failure point
77+ //
78+ // jsonPath: "spec.template.spec.containers[0].image"
79+ //
80+ // spec: ✓
81+ // template: ✓
82+ // spec: ✓
83+ // containers: ✓
84+ // [0]: ✓
85+ // image: ✖ available keys: [name image ports]
86+ func debugJsonPath (key string , data any ) string {
87+ parts := strings .Split (key , "." )
88+ current := data
89+ var result strings.Builder
90+ for _ , part := range parts {
91+ jpExpr , err := jp .ParseString (part )
92+ if err != nil {
93+ result .WriteString (fmt .Sprintf ("%s: ✖ could not parse jsonpath expression: %s\n " , part , err ))
94+ break
95+ }
96+ values := jpExpr .Get (current )
97+ if len (values ) == 0 {
98+ switch v := current .(type ) {
99+ case map [string ]any :
100+ result .WriteString (fmt .Sprintf ("%s: ✖ available keys: [%s]\n " , part , strings .Join (lo .Keys (v ), ", " )))
101+ default :
102+ result .WriteString (fmt .Sprintf ("%s: ✖ could not find key in current data\n " , part ))
103+ }
104+ break
105+ } else {
106+ result .WriteString (fmt .Sprintf ("%s: ✓\n " , part ))
107+ current = values [0 ]
108+ }
109+ }
110+ return result .String ()
111+
112+ }
113+
74114func GetHelmValueFromCache (ctx Context , namespace , releaseName , key string ) (string , error ) {
75115 id := fmt .Sprintf ("helm/%s/%s/%s" , namespace , releaseName , key )
76116 if value , found := envCache .Get (id ); found {
@@ -132,7 +172,13 @@ func GetHelmValueFromCache(ctx Context, namespace, releaseName, key string) (str
132172
133173 results := keyJPExpr .Get (merged )
134174 if len (results ) == 0 {
135- return "" , fmt .Errorf ("could not find key %s in merged helm secret %s/%s: %w" , key , namespace , secret .Name , err )
175+ switch v := merged .(type ) {
176+ case map [string ]any :
177+
178+ return "" , fmt .Errorf ("could not find key %s in merged helm secret %s/%s (%s)" , key , namespace , secret .Name , debugJsonPath (key , v ))
179+ default :
180+ return "" , fmt .Errorf ("could not find key %s in merged helm secret %s/%s" , key , namespace , secret .Name )
181+ }
136182 }
137183
138184 val := ""
@@ -231,3 +277,59 @@ func GetServiceAccountTokenFromCache(ctx Context, namespace, serviceAccount stri
231277 envCache .Set (id , tokenRequest .Status .Token , time .Until (tokenRequest .Status .ExpirationTimestamp .Time ))
232278 return tokenRequest .Status .Token , nil
233279}
280+
281+ func (ctx Context ) Lookup (namespace string ) * EnvVarSourceBuilder {
282+ return & EnvVarSourceBuilder {
283+ envVarSource : & types.EnvVarSource {},
284+ context : ctx ,
285+ namespace : namespace ,
286+ }
287+ }
288+
289+ type EnvVarSourceBuilder struct {
290+ envVarSource * types.EnvVarSource
291+ context Context
292+ namespace string
293+ }
294+
295+ func (b * EnvVarSourceBuilder ) MustGetString () string {
296+ value , err := b .GetString ()
297+ if err != nil {
298+ panic (err )
299+ }
300+ return value
301+ }
302+
303+ func (b * EnvVarSourceBuilder ) GetString () (string , error ) {
304+
305+ return GetEnvValueFromCache (b .context , types.EnvVar {ValueFrom : b .envVarSource }, b .namespace )
306+ }
307+
308+ func (b * EnvVarSourceBuilder ) WithServiceAccount (name string ) * EnvVarSourceBuilder {
309+ b .envVarSource .ServiceAccount = & name
310+ return b
311+ }
312+
313+ func (b * EnvVarSourceBuilder ) WithHelmRef (name , key string ) * EnvVarSourceBuilder {
314+ b .envVarSource .HelmRef = & types.HelmRefKeySelector {
315+ LocalObjectReference : types.LocalObjectReference {Name : name },
316+ Key : key ,
317+ }
318+ return b
319+ }
320+
321+ func (b * EnvVarSourceBuilder ) WithConfigMapKeyRef (name , key string ) * EnvVarSourceBuilder {
322+ b .envVarSource .ConfigMapKeyRef = & types.ConfigMapKeySelector {
323+ LocalObjectReference : types.LocalObjectReference {Name : name },
324+ Key : key ,
325+ }
326+ return b
327+ }
328+
329+ func (b * EnvVarSourceBuilder ) WithSecretKeyRef (name , key string ) * EnvVarSourceBuilder {
330+ b .envVarSource .SecretKeyRef = & types.SecretKeySelector {
331+ LocalObjectReference : types.LocalObjectReference {Name : name },
332+ Key : key ,
333+ }
334+ return b
335+ }
0 commit comments