Skip to content

Commit

Permalink
use predictable name for csiaddons object
Browse files Browse the repository at this point in the history
This PR does the below changes

* Use the deployment/Daemonset as the owner
of the csiaddons instead of pod

* Use predictable name which includes the
nodeID, owner name and the kind to ensure
that we get unique names per resources also
if the pod is restarting we will reuse the
same resource name for the csiAddonsNode object.
Using Resource Kind as csiAddonsNode object is
a namespaced resouces

* Take care of worst case where resource char limit
is not meet.

Signed-off-by: Madhu Rajanna <[email protected]>
  • Loading branch information
Madhu-1 committed Oct 30, 2024
1 parent 54944f9 commit 8a7299e
Show file tree
Hide file tree
Showing 273 changed files with 30,917 additions and 94 deletions.
114 changes: 81 additions & 33 deletions sidecar/internal/csiaddonsnode/csiaddonsnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package csiaddonsnode

import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"time"
Expand All @@ -27,11 +29,12 @@ import (

apierrors "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/klog/v2"
ctrlClient "sigs.k8s.io/controller-runtime/pkg/client"
)

const (
Expand All @@ -58,6 +61,9 @@ type Manager struct {
// Config is a ReST Config for the Kubernets API.
Config *rest.Config

// kubernetes client to interact with the Kubernetes API.
KubeClient kubernetes.Interface

// Node is the hostname of the system where the sidecar is running.
Node string

Expand Down Expand Up @@ -108,31 +114,22 @@ func (mgr *Manager) Deploy() error {
// If the CSIAddonsNode object already exists, it will not be re-created or
// modified, and the existing object is kept as-is.
func (mgr *Manager) newCSIAddonsNode(node *csiaddonsv1alpha1.CSIAddonsNode) error {
scheme, err := csiaddonsv1alpha1.SchemeBuilder.Build()
if err != nil {
return fmt.Errorf("failed to add scheme: %w", err)
s := runtime.Scheme{}
if err := csiaddonsv1alpha1.SchemeBuilder.AddToScheme(&s); err != nil {
return fmt.Errorf("failed to register scheme: %w", err)
}

crdConfig := *mgr.Config
crdConfig.GroupVersion = &csiaddonsv1alpha1.GroupVersion
crdConfig.APIPath = "/apis"
crdConfig.NegotiatedSerializer = serializer.NewCodecFactory(scheme)
crdConfig.UserAgent = rest.DefaultKubernetesUserAgent()

c, err := rest.UnversionedRESTClientFor(&crdConfig)
cli, err := ctrlClient.New(mgr.Config, ctrlClient.Options{Scheme: &s})
if err != nil {
return fmt.Errorf("failed to get REST Client: %w", err)
return fmt.Errorf("failed to create controller-runtime client: %w", err)
}

err = c.Post().
Resource("csiaddonsnodes").
Namespace(node.Namespace).
Name(node.Name).
Body(node).
Do(context.TODO()).
Error()

if err != nil && !apierrors.IsAlreadyExists(err) {
ctx := context.TODO()
err = cli.Create(ctx, node)
if err != nil {
if apierrors.IsAlreadyExists(err) {
klog.V(5).Infof("CSIAddonsNode %s/%s already exists", node.Namespace, node.Name)
return cli.Update(ctx, node)
}
return fmt.Errorf("failed to create csiaddonsnode object: %w", err)
}

Expand Down Expand Up @@ -166,18 +163,46 @@ func (mgr *Manager) getCSIAddonsNode() (*csiaddonsv1alpha1.CSIAddonsNode, error)
errInvalidConfig)
}

// Get the owner of the pod as we want to set the owner of the CSIAddonsNode
// so that it won't get deleted when the pod is deleted rather it will be deleted
// when the owner is deleted.

pod, err := mgr.KubeClient.CoreV1().Pods(mgr.PodNamespace).Get(context.TODO(), mgr.PodName, v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get pod: %w", err)
}

if len(pod.OwnerReferences) == 0 {
return nil, fmt.Errorf("%w: pod has no owner", errInvalidConfig)
}

ownerReferences := []v1.OwnerReference{}
if pod.OwnerReferences[0].Kind == "ReplicaSet" {
// If the pod is owned by a ReplicaSet, we need to get the owner of the ReplicaSet i.e. Deployment
rs, err := mgr.KubeClient.AppsV1().ReplicaSets(mgr.PodNamespace).Get(context.TODO(), pod.OwnerReferences[0].Name, v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get replicaset: %w", err)
}
if len(rs.OwnerReferences) == 0 {
return nil, fmt.Errorf("%w: replicaset has no owner", errInvalidConfig)
}
ownerReferences = append(ownerReferences, rs.OwnerReferences[0])
} else {
// If the pod is owned by DeamonSet or StatefulSet get the owner of the pod.
ownerReferences = append(ownerReferences, pod.OwnerReferences[0])
}
// we need to have the constant name for the CSIAddonsNode object.
// We will use the nodeID and the ownerName for the CSIAddonsNode object name.
name, err := generateName(mgr.Node, ownerReferences[0].Kind, ownerReferences[0].Name)
if err != nil {
return nil, fmt.Errorf("failed to generate name: %w", err)
}

return &csiaddonsv1alpha1.CSIAddonsNode{
ObjectMeta: v1.ObjectMeta{
Name: mgr.PodName,
Namespace: mgr.PodNamespace,
OwnerReferences: []v1.OwnerReference{
{
APIVersion: "v1",
Kind: "Pod",
Name: mgr.PodName,
UID: types.UID(mgr.PodUID),
},
},
Name: name,
Namespace: mgr.PodNamespace,
OwnerReferences: ownerReferences,
},
Spec: csiaddonsv1alpha1.CSIAddonsNodeSpec{
Driver: csiaddonsv1alpha1.CSIAddonsNodeDriver{
Expand All @@ -188,3 +213,26 @@ func (mgr *Manager) getCSIAddonsNode() (*csiaddonsv1alpha1.CSIAddonsNode, error)
},
}, nil
}

func generateName(nodeID, ownerKind, ownerName string) (string, error) {
if nodeID == "" {
return "", fmt.Errorf("nodeID is required")
}
if ownerKind == "" {
return "", fmt.Errorf("ownerKind is required")
}
if ownerName == "" {
return "", fmt.Errorf("ownerName is required")
}
base := fmt.Sprintf("%s-%s-%s", nodeID, ownerKind, ownerName)
if len(base) > 253 {
// Generate a UUID based on nodeID, ownerKind, and ownerName
data := nodeID + ownerKind + ownerName
hash := sha256.Sum256([]byte(data))
uuid := hex.EncodeToString(hash[:8]) // Use the first 8 characters of the hash as a UUID-like string
finalName := fmt.Sprintf("%s-%s", base[:251-len(uuid)-1], uuid) // Ensure total length is within 253
return finalName, nil
}

return base, nil
}
Loading

0 comments on commit 8a7299e

Please sign in to comment.