github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/resources/persistentvolumeclaim.go (about)

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package resources
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	corev1 "k8s.io/api/core/v1"
    12  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    15  	"k8s.io/apimachinery/pkg/runtime"
    16  	types "k8s.io/apimachinery/pkg/types"
    17  	"k8s.io/client-go/kubernetes"
    18  
    19  	k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants"
    20  	"github.com/juju/juju/core/status"
    21  )
    22  
    23  // PersistentVolumeClaim extends the k8s persistentVolumeClaim.
    24  type PersistentVolumeClaim struct {
    25  	corev1.PersistentVolumeClaim
    26  }
    27  
    28  // NewPersistentVolumeClaim creates a new persistent volume claim resource.
    29  func NewPersistentVolumeClaim(name string, namespace string, in *corev1.PersistentVolumeClaim) *PersistentVolumeClaim {
    30  	if in == nil {
    31  		in = &corev1.PersistentVolumeClaim{}
    32  	}
    33  	in.SetName(name)
    34  	in.SetNamespace(namespace)
    35  	return &PersistentVolumeClaim{*in}
    36  }
    37  
    38  // ListPersistentVolumeClaims returns a list of persistent volume claims.
    39  func ListPersistentVolumeClaims(ctx context.Context, client kubernetes.Interface, namespace string, opts metav1.ListOptions) ([]PersistentVolumeClaim, error) {
    40  	api := client.CoreV1().PersistentVolumeClaims(namespace)
    41  	var items []PersistentVolumeClaim
    42  	for {
    43  		res, err := api.List(ctx, opts)
    44  		if err != nil {
    45  			return nil, errors.Trace(err)
    46  		}
    47  		for _, item := range res.Items {
    48  			items = append(items, PersistentVolumeClaim{PersistentVolumeClaim: item})
    49  		}
    50  		if res.RemainingItemCount == nil || *res.RemainingItemCount == 0 {
    51  			break
    52  		}
    53  		opts.Continue = res.Continue
    54  	}
    55  	return items, nil
    56  }
    57  
    58  // Clone returns a copy of the resource.
    59  func (pvc *PersistentVolumeClaim) Clone() Resource {
    60  	clone := *pvc
    61  	return &clone
    62  }
    63  
    64  // ID returns a comparable ID for the Resource
    65  func (pvc *PersistentVolumeClaim) ID() ID {
    66  	return ID{"PersistentVolumeClaim", pvc.Name, pvc.Namespace}
    67  }
    68  
    69  // Apply patches the resource change.
    70  func (pvc *PersistentVolumeClaim) Apply(ctx context.Context, client kubernetes.Interface) error {
    71  	api := client.CoreV1().PersistentVolumeClaims(pvc.Namespace)
    72  	data, err := runtime.Encode(unstructured.UnstructuredJSONScheme, &pvc.PersistentVolumeClaim)
    73  	if err != nil {
    74  		return errors.Trace(err)
    75  	}
    76  	res, err := api.Patch(ctx, pvc.Name, types.StrategicMergePatchType, data, metav1.PatchOptions{
    77  		FieldManager: JujuFieldManager,
    78  	})
    79  	if k8serrors.IsNotFound(err) {
    80  		res, err = api.Create(ctx, &pvc.PersistentVolumeClaim, metav1.CreateOptions{
    81  			FieldManager: JujuFieldManager,
    82  		})
    83  	}
    84  	if k8serrors.IsConflict(err) {
    85  		return errors.Annotatef(errConflict, "persistent volume claim %q", pvc.Name)
    86  	}
    87  	if err != nil {
    88  		return errors.Trace(err)
    89  	}
    90  	pvc.PersistentVolumeClaim = *res
    91  	return nil
    92  }
    93  
    94  // Get refreshes the resource.
    95  func (pvc *PersistentVolumeClaim) Get(ctx context.Context, client kubernetes.Interface) error {
    96  	api := client.CoreV1().PersistentVolumeClaims(pvc.Namespace)
    97  	res, err := api.Get(ctx, pvc.Name, metav1.GetOptions{})
    98  	if k8serrors.IsNotFound(err) {
    99  		return errors.NewNotFound(err, "k8s")
   100  	} else if err != nil {
   101  		return errors.Trace(err)
   102  	}
   103  	pvc.PersistentVolumeClaim = *res
   104  	return nil
   105  }
   106  
   107  // Delete removes the resource.
   108  func (pvc *PersistentVolumeClaim) Delete(ctx context.Context, client kubernetes.Interface) error {
   109  	api := client.CoreV1().PersistentVolumeClaims(pvc.Namespace)
   110  	logger.Infof("deleting PVC %s due to call to PersistentVolumeClaim.Delete", pvc.Name)
   111  	err := api.Delete(ctx, pvc.Name, metav1.DeleteOptions{
   112  		PropagationPolicy: k8sconstants.DefaultPropagationPolicy(),
   113  	})
   114  	if k8serrors.IsNotFound(err) {
   115  		return nil
   116  	} else if err != nil {
   117  		return errors.Trace(err)
   118  	}
   119  	return nil
   120  }
   121  
   122  // Events emitted by the resource.
   123  func (pvc *PersistentVolumeClaim) Events(ctx context.Context, client kubernetes.Interface) ([]corev1.Event, error) {
   124  	return ListEventsForObject(ctx, client, pvc.Namespace, pvc.Name, "PersistentVolumeClaim")
   125  }
   126  
   127  // ComputeStatus returns a juju status for the resource.
   128  func (pvc *PersistentVolumeClaim) ComputeStatus(ctx context.Context, client kubernetes.Interface, now time.Time) (string, status.Status, time.Time, error) {
   129  	if pvc.DeletionTimestamp != nil {
   130  		return "", status.Terminated, pvc.DeletionTimestamp.Time, nil
   131  	}
   132  	if pvc.Status.Phase == corev1.ClaimBound {
   133  		return string(pvc.Status.Phase), status.Active, now, nil
   134  	}
   135  	return string(pvc.Status.Phase), status.Waiting, now, nil
   136  }