k9s/internal/xray/container.go

105 lines
2.8 KiB
Go

// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s
package xray
import (
"context"
"fmt"
"github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/dao"
"github.com/derailed/k9s/internal/render"
"github.com/rs/zerolog/log"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
)
// Container represents an xray renderer.
type Container struct{}
// Render renders an xray node.
func (c *Container) Render(ctx context.Context, ns string, o interface{}) error {
co, ok := o.(render.ContainerRes)
if !ok {
return fmt.Errorf("expected ContainerRes, but got %T", o)
}
f, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
if !ok {
return fmt.Errorf("no factory found in context")
}
root := NewTreeNode("containers", client.FQN(ns, co.Container.Name))
parent, ok := ctx.Value(KeyParent).(*TreeNode)
if !ok {
return fmt.Errorf("Expecting a TreeNode but got %T", ctx.Value(KeyParent))
}
pns, _ := client.Namespaced(parent.ID)
c.envRefs(f, root, pns, co.Container)
parent.Add(root)
return nil
}
func (c *Container) envRefs(f dao.Factory, parent *TreeNode, ns string, co *v1.Container) {
for _, e := range co.Env {
if e.ValueFrom == nil {
continue
}
c.secretRefs(f, parent, ns, e.ValueFrom.SecretKeyRef)
c.configMapRefs(f, parent, ns, e.ValueFrom.ConfigMapKeyRef)
}
for _, e := range co.EnvFrom {
if e.ConfigMapRef != nil {
gvr, id := "v1/configmaps", client.FQN(ns, e.ConfigMapRef.Name)
addRef(f, parent, gvr, id, e.ConfigMapRef.Optional)
}
if e.SecretRef != nil {
gvr, id := "v1/secrets", client.FQN(ns, e.SecretRef.Name)
addRef(f, parent, gvr, id, e.SecretRef.Optional)
}
}
}
func (c *Container) secretRefs(f dao.Factory, parent *TreeNode, ns string, ref *v1.SecretKeySelector) {
if ref == nil {
return
}
gvr, id := "v1/secrets", client.FQN(ns, ref.LocalObjectReference.Name)
addRef(f, parent, gvr, id, ref.Optional)
}
func (c *Container) configMapRefs(f dao.Factory, parent *TreeNode, ns string, ref *v1.ConfigMapKeySelector) {
if ref == nil {
return
}
gvr, id := "v1/configmaps", client.FQN(ns, ref.LocalObjectReference.Name)
addRef(f, parent, gvr, id, ref.Optional)
}
// ----------------------------------------------------------------------------
// Helpers...
func addRef(f dao.Factory, parent *TreeNode, gvr, id string, optional *bool) {
if parent.Find(gvr, id) == nil {
n := NewTreeNode(gvr, id)
validate(f, n, optional)
parent.Add(n)
}
}
func validate(f dao.Factory, n *TreeNode, optional *bool) {
res, err := f.Get(n.GVR, n.ID, true, labels.Everything())
if err != nil || res == nil {
if optional == nil || !*optional {
log.Warn().Err(err).Msgf("Missing ref %q::%q", n.GVR, n.ID)
n.Extras[StatusKey] = MissingRefStatus
}
return
}
n.Extras[StatusKey] = OkStatus
}