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 }