From b2d0df03b1b9e9ea17f9260f373a762d03bdb10b Mon Sep 17 00:00:00 2001 From: Joshua Hoblitt Date: Tue, 9 Jun 2026 15:05:19 -0700 Subject: [PATCH] k8sutil: remove unused helper functions Remove dead code from the k8sutil package; none of these symbols had any callers anywhere in the repo (verified with deadcode, staticcheck U1000, and repo-wide grep, tests included): - patcher.go: delete file (Patcher type, NewPatcher, Patch) - replicaset.go: delete file (DeleteReplicaSet) - customresource.go: WatchCR (the CustomResource type remains in use) - deployment.go: WaitForDeploymentImage - job.go: WaitForJobCompletion - k8sutil.go: GetK8SVersion - pod.go: ConfigOverrideMount, ConfigOverrideVolume, GetPodLog - prometheus.go: DeleteServiceMonitor - service.go: DeleteService - volume.go: NodeConfigURI, BinariesMountInfo, YamlToVolumes, YamlToVolumeMounts, and the BinariesMountPath const (only used by the removed BinariesMountInfo) Now-unused imports are dropped from each file. The shared deleteResourceAndWait helper remains (still used by DeleteDeployment). Signed-off-by: Joshua Hoblitt (cherry picked from commit b29e89ef674e952143019dd5fae33cb1219c9167) --- pkg/operator/k8sutil/customresource.go | 22 ----- pkg/operator/k8sutil/deployment.go | 38 --------- pkg/operator/k8sutil/job.go | 27 ------ pkg/operator/k8sutil/k8sutil.go | 19 ----- pkg/operator/k8sutil/patcher.go | 110 ------------------------- pkg/operator/k8sutil/pod.go | 43 ---------- pkg/operator/k8sutil/prometheus.go | 23 ------ pkg/operator/k8sutil/replicaset.go | 36 -------- pkg/operator/k8sutil/service.go | 11 --- pkg/operator/k8sutil/volume.go | 69 ---------------- 10 files changed, 398 deletions(-) delete mode 100644 pkg/operator/k8sutil/patcher.go delete mode 100644 pkg/operator/k8sutil/replicaset.go diff --git a/pkg/operator/k8sutil/customresource.go b/pkg/operator/k8sutil/customresource.go index 487d088b6..d2135c541 100644 --- a/pkg/operator/k8sutil/customresource.go +++ b/pkg/operator/k8sutil/customresource.go @@ -17,13 +17,6 @@ limitations under the License. // Package kit for Kubernetes operators package k8sutil -import ( - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/cache" -) - // CustomResource is for creating a Kubernetes TPR/CRD type CustomResource struct { // Name of the custom resource @@ -44,18 +37,3 @@ type CustomResource struct { // APIVersion is the full API version name (combine Group and Version) APIVersion string } - -// WatchCR begins watching the custom resource (CRD). The call will block until a Done signal is raised during in the context. -// When the watch has detected a create, update, or delete event, it will handled by the functions in the resourceEventHandlers. After the callback returns, the watch loop will continue for the next event. -// If the callback returns an error, the error will be logged. -func WatchCR(resource CustomResource, namespace string, handlers cache.ResourceEventHandlerFuncs, client rest.Interface, objType runtime.Object, done <-chan struct{}) { - source := cache.NewListWatchFromClient( - client, - resource.Plural, - namespace, - fields.Everything()) - _, controller := cache.NewInformerWithOptions(cache.InformerOptions{ListerWatcher: source, ObjectType: objType, ResyncPeriod: 0, Handler: handlers}) - - go controller.Run(done) - <-done -} diff --git a/pkg/operator/k8sutil/deployment.go b/pkg/operator/k8sutil/deployment.go index 73940177c..4cfa91b0f 100644 --- a/pkg/operator/k8sutil/deployment.go +++ b/pkg/operator/k8sutil/deployment.go @@ -424,44 +424,6 @@ func GetDeploymentOwnerReference(ctx context.Context, clientset kubernetes.Inter return deploymentRef, nil } -// WaitForDeploymentImage waits for all deployments with the given labels are running. -// WARNING:This is currently only useful for testing! -func WaitForDeploymentImage(ctx context.Context, clientset kubernetes.Interface, namespace, label, container string, initContainer bool, desiredImage string) error { - sleepTime := 3 - attempts := 120 - for i := 0; i < attempts; i++ { - deployments, err := clientset.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{LabelSelector: label}) - if err != nil { - return fmt.Errorf("failed to list deployments with label %s. %v", label, err) - } - - matches := 0 - for _, d := range deployments.Items { - image, err := GetDeploymentSpecImage(clientset, d, container, initContainer) - if err != nil { - logger.Infof("failed to get image for deployment %s. %+v", d.Name, err) - continue - } - if image == desiredImage { - matches++ - } - } - - if matches == len(deployments.Items) && matches > 0 { - logger.Infof("all %d %s deployments are on image %s", matches, label, desiredImage) - return nil - } - - if len(deployments.Items) == 0 { - logger.Infof("waiting for at least one deployment to start to see the version") - } else { - logger.Infof("%d/%d %s deployments match image %s", matches, len(deployments.Items), label, desiredImage) - } - time.Sleep(time.Duration(sleepTime) * time.Second) - } - return fmt.Errorf("failed to wait for image %s in label %s", desiredImage, label) -} - // AddRookVersionLabelToDeployment adds or updates a label reporting the Rook version which last // modified a deployment. func AddRookVersionLabelToDeployment(d *appsv1.Deployment) { diff --git a/pkg/operator/k8sutil/job.go b/pkg/operator/k8sutil/job.go index 615005289..96a49fb20 100644 --- a/pkg/operator/k8sutil/job.go +++ b/pkg/operator/k8sutil/job.go @@ -25,7 +25,6 @@ import ( batch "k8s.io/api/batch/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" ) @@ -58,32 +57,6 @@ func RunReplaceableJob(ctx context.Context, clientset kubernetes.Interface, job return err } -// WaitForJobCompletion waits for a job to reach the completed state. -// Assumes that only one pod needs to complete. -func WaitForJobCompletion(ctx context.Context, clientset kubernetes.Interface, job *batch.Job, timeout time.Duration) error { - logger.Infof("waiting for job %s to complete...", job.Name) - return wait.PollUntilContextTimeout(ctx, 5*time.Second, timeout, true, func(context context.Context) (bool, error) { - job, err := clientset.BatchV1().Jobs(job.Namespace).Get(ctx, job.Name, metav1.GetOptions{}) - if err != nil { - return false, fmt.Errorf("failed to detect job %s. %+v", job.Name, err) - } - - // if the job is still running, allow it to continue to completion - if job.Status.Active > 0 { - logger.Debugf("job is still running. Status=%+v", job.Status) - return false, nil - } - if job.Status.Failed > 0 { - return false, fmt.Errorf("job %s failed", job.Name) - } - if job.Status.Succeeded > 0 { - return true, nil - } - logger.Debugf("job is still initializing") - return false, nil - }) -} - // DeleteBatchJob deletes a Kubernetes job. func DeleteBatchJob(ctx context.Context, clientset kubernetes.Interface, namespace, name string, wait bool) error { propagation := metav1.DeletePropagationForeground diff --git a/pkg/operator/k8sutil/k8sutil.go b/pkg/operator/k8sutil/k8sutil.go index 79aa66dba..e275ec9a6 100644 --- a/pkg/operator/k8sutil/k8sutil.go +++ b/pkg/operator/k8sutil/k8sutil.go @@ -30,8 +30,6 @@ import ( kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/apimachinery/pkg/util/version" - "k8s.io/client-go/kubernetes" ) var logger = capnslog.NewPackageLogger("github.com/rook/rook", "op-k8sutil") @@ -60,23 +58,6 @@ const ( DefaultServiceAccount = "rook-ceph-default" ) -// GetK8SVersion gets the version of the running K8S cluster -func GetK8SVersion(clientset kubernetes.Interface) (*version.Version, error) { - serverVersion, err := clientset.Discovery().ServerVersion() - if err != nil { - return nil, fmt.Errorf("error getting server version: %v", err) - } - - // make sure the kubernetes version is parseable - index := strings.Index(serverVersion.GitVersion, "+") - if index != -1 { - newVersion := serverVersion.GitVersion[:index] - logger.Debugf("returning version %s instead of %s", newVersion, serverVersion.GitVersion) - serverVersion.GitVersion = newVersion - } - return version.MustParseSemantic(serverVersion.GitVersion), nil -} - // Hash stableName computes a stable pseudorandom string suitable for inclusion in a Kubernetes object name from the given seed string. // Do **NOT** edit this function in a way that would change its output as it needs to // provide consistent mappings from string to hash across versions of rook. diff --git a/pkg/operator/k8sutil/patcher.go b/pkg/operator/k8sutil/patcher.go deleted file mode 100644 index 2bf061182..000000000 --- a/pkg/operator/k8sutil/patcher.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2020 The Rook Authors. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package k8sutil - -import ( - "context" - "reflect" - - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - kerrors "k8s.io/apimachinery/pkg/util/errors" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -// Patcher is a utility for patching of objects and their status. -// Portion of this file is coming from https://github.com/kubernetes-sigs/cluster-api/blob/master/util/patch/patch.go -type Patcher struct { - client client.Client - hasStatus bool - old map[string]interface{} - oldStatus interface{} - objectPatch client.Patch - statusPatch client.Patch -} - -func NewPatcher(object client.Object, crclient client.Client) (*Patcher, error) { - if object == nil { - return nil, errors.Errorf("expected non-nil resource") - } - - if _, ok := object.(runtime.Unstructured); ok { - object = object.DeepCopyObject().(client.Object) - } - - old, err := runtime.DefaultUnstructuredConverter.ToUnstructured(object) - if err != nil { - return nil, err - } - - hasStatus := false - oldStatus, ok, err := unstructured.NestedFieldCopy(old, "status") - if err != nil { - return nil, err - } - if ok { - hasStatus = true - unstructured.RemoveNestedField(old, "status") - } - - return &Patcher{ - client: crclient, - hasStatus: hasStatus, - old: old, - oldStatus: oldStatus, - objectPatch: client.MergeFrom(object.DeepCopyObject().(client.Object)), - statusPatch: client.MergeFrom(object.DeepCopyObject().(client.Object)), - }, nil -} - -func (p *Patcher) Patch(ctx context.Context, object client.Object) error { - if object == nil { - return errors.Errorf("expected non-nil resource") - } - - newObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(object) - if err != nil { - return err - } - - hasStatus := false - newStatus, ok, err := unstructured.NestedFieldCopy(newObj, "status") - if err != nil { - return err - } - - if ok { - hasStatus = true - unstructured.RemoveNestedField(newObj, "status") - } - - var errs []error - if !reflect.DeepEqual(p.old, newObj) { - if err := p.client.Patch(ctx, object, p.objectPatch); err != nil { - errs = append(errs, err) - } - } - - if (p.hasStatus || hasStatus) && !reflect.DeepEqual(p.oldStatus, newStatus) { - if err := p.client.Status().Patch(ctx, object, p.statusPatch); err != nil { - errs = append(errs, err) - } - } - - return kerrors.NewAggregate(errs) -} diff --git a/pkg/operator/k8sutil/pod.go b/pkg/operator/k8sutil/pod.go index c15daa1ab..bf7130072 100644 --- a/pkg/operator/k8sutil/pod.go +++ b/pkg/operator/k8sutil/pod.go @@ -20,11 +20,9 @@ package k8sutil import ( "context" "fmt" - "io" "os" "path" "strconv" - "strings" "github.com/pkg/errors" "github.com/rook/rook/pkg/clusterd" @@ -53,18 +51,6 @@ const ( ObservedGenerationNotAvailable int64 = -1 ) -// ConfigOverrideMount is an override mount -func ConfigOverrideMount() v1.VolumeMount { - return v1.VolumeMount{Name: ConfigOverrideName, MountPath: configMountDir} -} - -// ConfigOverrideVolume is an override volume -func ConfigOverrideVolume() v1.Volume { - cmSource := &v1.ConfigMapVolumeSource{Items: []v1.KeyToPath{{Key: ConfigOverrideVal, Path: overrideFilename}}} - cmSource.Name = ConfigOverrideName - return v1.Volume{Name: ConfigOverrideName, VolumeSource: v1.VolumeSource{ConfigMap: cmSource}} -} - // ConfigOverrideEnvVar config override env var func ConfigOverrideEnvVar() v1.EnvVar { return v1.EnvVar{Name: "ROOK_CEPH_CONFIG_OVERRIDE", Value: path.Join(configMountDir, overrideFilename)} @@ -233,35 +219,6 @@ func GetPodPhaseMap(pods *v1.PodList) map[v1.PodPhase][]string { return podPhaseMap } -// GetJobLog gets the logs for the pod. If there is more than one pod with the label selector, the logs from -// the first pod will be returned. -func GetPodLog(ctx context.Context, clientset kubernetes.Interface, namespace string, labelSelector string) (string, error) { - opts := metav1.ListOptions{ - LabelSelector: labelSelector, - } - pods, err := clientset.CoreV1().Pods(namespace).List(ctx, opts) - if err != nil { - return "", fmt.Errorf("failed to get version pod. %+v", err) - } - for _, pod := range pods.Items { - req := clientset.CoreV1().Pods(namespace).GetLogs(pod.Name, &v1.PodLogOptions{}) - readCloser, err := req.Stream(ctx) - if err != nil { - return "", fmt.Errorf("failed to read from stream. %+v", err) - } - - builder := &strings.Builder{} - defer readCloser.Close() - _, err = io.Copy(builder, readCloser) - if err != nil { - return "", errors.Wrapf(err, "error copying file from %s to %s", builder, readCloser) - } - return builder.String(), err //nolint // no else statement needed - } - - return "", fmt.Errorf("did not find any pods with label %s", labelSelector) -} - // ClusterDaemonEnvVars Environment variables used by storage cluster daemon func ClusterDaemonEnvVars(image string) []v1.EnvVar { return []v1.EnvVar{ diff --git a/pkg/operator/k8sutil/prometheus.go b/pkg/operator/k8sutil/prometheus.go index dfea5355b..c2869b666 100644 --- a/pkg/operator/k8sutil/prometheus.go +++ b/pkg/operator/k8sutil/prometheus.go @@ -21,7 +21,6 @@ import ( "context" "fmt" - "github.com/pkg/errors" monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" monitoringclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned" "github.com/rook/rook/pkg/clusterd" @@ -104,25 +103,3 @@ func CreateOrUpdateServiceMonitor(context *clusterd.Context, ctx context.Context } return sm, nil } - -// DeleteServiceMonitor deletes a ServiceMonitor and returns the error if any -func DeleteServiceMonitor(context *clusterd.Context, ctx context.Context, ns string, name string) error { - client, err := getMonitoringClient(context) - if err != nil { - return fmt.Errorf("failed to get monitoring client. %v", err) - } - _, err = client.MonitoringV1().ServiceMonitors(ns).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - // Either the service monitor does not exist or there are no privileges to detect it - // so we ignore any errors - return nil - } - err = client.MonitoringV1().ServiceMonitors(ns).Delete(ctx, name, metav1.DeleteOptions{}) - if err != nil { - if kerrors.IsNotFound(err) { - return nil - } - return errors.Wrapf(err, "failed to delete service monitor %q", name) - } - return nil -} diff --git a/pkg/operator/k8sutil/replicaset.go b/pkg/operator/k8sutil/replicaset.go deleted file mode 100644 index d502752d8..000000000 --- a/pkg/operator/k8sutil/replicaset.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2018 The Rook Authors. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package k8sutil - -import ( - "context" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -// DeleteReplicaSet makes a best effort at deleting a deployment and its pods, then waits for them to be deleted -func DeleteReplicaSet(ctx context.Context, clientset kubernetes.Interface, namespace, name string) error { - deleteAction := func(options *metav1.DeleteOptions) error { - return clientset.AppsV1().ReplicaSets(namespace).Delete(ctx, name, *options) - } - getAction := func() error { - _, err := clientset.AppsV1().ReplicaSets(namespace).Get(ctx, name, metav1.GetOptions{}) - return err - } - return deleteResourceAndWait(namespace, name, "replicaset", deleteAction, getAction) -} diff --git a/pkg/operator/k8sutil/service.go b/pkg/operator/k8sutil/service.go index 18b578452..8a7c48065 100644 --- a/pkg/operator/k8sutil/service.go +++ b/pkg/operator/k8sutil/service.go @@ -72,17 +72,6 @@ func UpdateService( return clientset.CoreV1().Services(namespace).Update(ctx, serviceDefinition, metav1.UpdateOptions{}) } -// DeleteService deletes a Service and returns the error if any -func DeleteService(ctx context.Context, clientset kubernetes.Interface, namespace, name string) error { - err := clientset.CoreV1().Services(namespace).Delete(ctx, name, metav1.DeleteOptions{}) - if err != nil { - if kerrors.IsNotFound(err) { - return nil - } - } - return err -} - // ParseServiceType parses a string and returns a*v1.ServiceType. If the ServiceType is invalid, // this should be considered an error. func ParseServiceType(serviceString string) v1.ServiceType { diff --git a/pkg/operator/k8sutil/volume.go b/pkg/operator/k8sutil/volume.go index ea4cdfc3e..54d9b90ea 100644 --- a/pkg/operator/k8sutil/volume.go +++ b/pkg/operator/k8sutil/volume.go @@ -18,18 +18,10 @@ limitations under the License. package k8sutil import ( - "encoding/json" "fmt" - "os" "strings" - v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/apimachinery/pkg/util/yaml" -) - -const ( - BinariesMountPath = "/rook" ) // PathToVolumeName converts a path to a valid volume name @@ -72,64 +64,3 @@ func PathToVolumeName(path string) string { return volumeName } - -// NodeConfigURI returns the node config URI path for this node -func NodeConfigURI() (string, error) { - nodeName := os.Getenv(NodeNameEnvVar) - if nodeName == "" { - return "", fmt.Errorf("cannot detect the node name. Please provide using the downward API in the rook operator manifest file") - } - return fmt.Sprintf("api/v1/nodes/%s/proxy/configz", nodeName), nil -} - -func BinariesMountInfo() (v1.EnvVar, v1.Volume, v1.VolumeMount) { - // To get rook inside the container, the config init container needs to copy "rook" binary into a volume. - // Set the config flag so rook will copy the binaries. - // Create the volume and mount that will be shared between the init container and the daemon container - volumeName := "rookbinaries" - e := v1.EnvVar{Name: "ROOK_COPY_BINARIES_PATH", Value: BinariesMountPath} - v := v1.Volume{Name: volumeName, VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}} - m := v1.VolumeMount{Name: volumeName, MountPath: BinariesMountPath} - return e, v, m -} - -// This function takes raw YAML string and converts it to Kubernetes Volume array. -func YamlToVolumes(raw string) ([]v1.Volume, error) { - if raw == "" { - return []v1.Volume{}, nil - } - - rawJSON, err := yaml.ToJSON([]byte(raw)) - if err != nil { - return []v1.Volume{}, err - } - - var volume []v1.Volume - err = json.Unmarshal(rawJSON, &volume) - if err != nil { - return []v1.Volume{}, err - } - - return volume, nil -} - -// This function takes raw YAML string and converts it to Kubernetes Volume -// mount array. -func YamlToVolumeMounts(raw string) ([]v1.VolumeMount, error) { - if raw == "" { - return []v1.VolumeMount{}, nil - } - - rawJSON, err := yaml.ToJSON([]byte(raw)) - if err != nil { - return []v1.VolumeMount{}, err - } - - var volumeMount []v1.VolumeMount - err = json.Unmarshal(rawJSON, &volumeMount) - if err != nil { - return []v1.VolumeMount{}, err - } - - return volumeMount, nil -}