Merge pull request #17739 from rook/mergify/bp/release-1.20/pr-17726

k8sutil: remove unused helper functions (backport #17726)
This commit is contained in:
Joshua Hoblitt
2026-06-12 10:37:27 -07:00
committed by GitHub
10 changed files with 0 additions and 398 deletions
-22
View File
@@ -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
}
-38
View File
@@ -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) {
-27
View File
@@ -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
-19
View File
@@ -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.
-110
View File
@@ -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)
}
-43
View File
@@ -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{
-23
View File
@@ -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
}
-36
View File
@@ -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)
}
-11
View File
@@ -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 {
-69
View File
@@ -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
}