Skip to content

Commit 8c9c3dc

Browse files
committed
chore: add ctx.Lookup() builder
1 parent 3f6a396 commit 8c9c3dc

2 files changed

Lines changed: 106 additions & 4 deletions

File tree

context/context.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,13 +384,13 @@ func (k Context) WithLocalKubernetes(client *dutyKubernetes.Client) Context {
384384
return k
385385
}
386386

387-
func (k Context) LocalKubernetes() (*dutyKubernetes.Client, error) {
387+
func (k Context) LocalKubernetes(kubeconfigPaths ...string) (*dutyKubernetes.Client, error) {
388388
if localKubernetes != nil {
389389
return localKubernetes, nil
390390
}
391391

392392
var k8s = logger.GetLogger("k8s")
393-
c, rc, err := dutyKubernetes.NewClient(k8s)
393+
c, rc, err := dutyKubernetes.NewClient(k8s, kubeconfigPaths...)
394394
if err != nil {
395395
return nil, err
396396
}

context/envvar.go

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
74114
func 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

Comments
 (0)