package edgeinjector import ( "context" "fmt" "strings" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" "k8s.io/apimachinery/pkg/runtime" "edge-infra.dev/pkg/edge/api/utils" "edge-infra.dev/pkg/edge/controllers/envctl/pkg/nameutils" "edge-infra.dev/pkg/lib/fog" v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1" ) type NodeField string const ( Hostname = NodeField("NODE_HOSTNAME") Lane = NodeField("NODE_LANE") Role = NodeField("NODE_ROLE") Class = NodeField("NODE_CLASS") NodeUID = NodeField("NODE_UID") ) type NodeWebhook struct { client.Client } func (c *NodeWebhook) Default(ctx context.Context, obj runtime.Object) error { log := fog.FromContext(ctx).WithValues("name", "NodeWebhook") pod, ok := obj.(*corev1.Pod) if !ok { err := fmt.Errorf("expected a Pod but got a %T", obj) log.Error(err, "not a pod") return err } log = log.WithValues("pod", client.ObjectKeyFromObject(pod)) if SecretLabelValue(pod, NodeSecret) != "" { log.Info("node secret label already exists", client.ObjectKeyFromObject(pod)) return nil } ctx = fog.IntoContext(ctx, log) InjectSecret(ctx, pod, NodeSecret) log.Info("successfully injected node secret environment variables") return nil } // checkNodeSecret is needed due to how reconciliation can trigger before new version of the secret is created func checkNodeSecret(s *corev1.Secret) error { requiredFields := []NodeField{Hostname, Lane, NodeUID, Role, Class} for _, field := range requiredFields { if _, ok := s.Data[string(field)]; !ok { return errors.NewNotFound(corev1.Resource("secret"), fmt.Sprintf("secret: %s, missing field %s", s.Name, field)) } } return nil } func BuildNodeSecret(pod *corev1.Pod, info *nameutils.NodeInfo, customLabels map[string]string, secretName string) *corev1.Secret { customLabelsEnvs := map[string]string{ string(Hostname): info.Hostname, string(Lane): info.Lane, string(NodeUID): info.UID, string(Role): string(info.Role), string(Class): string(info.Class), } // convert the custom label key to be a k8s safe name // custom.node.com/label_key: val for key, val := range customLabels { labelKey := strings.TrimPrefix(key, fmt.Sprintf(v1ien.CustomNodeLabel, "")) customLabelsEnvs[utils.ToENVName(labelKey)] = val } return &corev1.Secret{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Secret", }, ObjectMeta: metav1.ObjectMeta{ Name: secretName, Namespace: pod.Namespace, OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef( pod, corev1.SchemeGroupVersion.WithKind("Pod"), ), }, }, StringData: customLabelsEnvs, } } func GetNodeCustomLabels(node *corev1.Node) (map[string]string, error) { customLabels := make(map[string]string, 0) labels := node.GetLabels() if len(labels) == 0 { return customLabels, nameutils.ErrMissingNodeLabels } for k, v := range labels { if IsCustomLabel(k) { customLabels[k] = v } } return customLabels, nil }