github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/resources/storageclass.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 storagev1 "k8s.io/api/storage/v1" 13 k8serrors "k8s.io/apimachinery/pkg/api/errors" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 16 "k8s.io/apimachinery/pkg/runtime" 17 types "k8s.io/apimachinery/pkg/types" 18 "k8s.io/client-go/kubernetes" 19 20 k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants" 21 "github.com/juju/juju/core/status" 22 ) 23 24 // StorageClass extends the k8s storageClass. 25 type StorageClass struct { 26 storagev1.StorageClass 27 } 28 29 // NewStorageClass creates a new storage class resource. 30 func NewStorageClass(name string, in *storagev1.StorageClass) *StorageClass { 31 if in == nil { 32 in = &storagev1.StorageClass{} 33 } 34 in.SetName(name) 35 return &StorageClass{*in} 36 } 37 38 // ListStorageClass returns a list of storage classes. 39 func ListStorageClass(ctx context.Context, client kubernetes.Interface, opts metav1.ListOptions) ([]StorageClass, error) { 40 api := client.StorageV1().StorageClasses() 41 var items []StorageClass 42 for { 43 res, err := api.List(ctx, opts) 44 if err != nil { 45 return nil, errors.Trace(err) 46 } 47 for _, v := range res.Items { 48 items = append(items, StorageClass{StorageClass: v}) 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 (sc *StorageClass) Clone() Resource { 60 clone := *sc 61 return &clone 62 } 63 64 // ID returns a comparable ID for the Resource 65 func (sc *StorageClass) ID() ID { 66 return ID{"StorageClass", sc.Name, sc.Namespace} 67 } 68 69 // Apply patches the resource change. 70 func (sc *StorageClass) Apply(ctx context.Context, client kubernetes.Interface) error { 71 api := client.StorageV1().StorageClasses() 72 data, err := runtime.Encode(unstructured.UnstructuredJSONScheme, &sc.StorageClass) 73 if err != nil { 74 return errors.Trace(err) 75 } 76 res, err := api.Patch(ctx, sc.Name, types.StrategicMergePatchType, data, metav1.PatchOptions{ 77 FieldManager: JujuFieldManager, 78 }) 79 if k8serrors.IsNotFound(err) { 80 res, err = api.Create(ctx, &sc.StorageClass, metav1.CreateOptions{ 81 FieldManager: JujuFieldManager, 82 }) 83 } 84 if k8serrors.IsConflict(err) { 85 return errors.Annotatef(errConflict, "storage class %q", sc.Name) 86 } 87 if err != nil { 88 return errors.Trace(err) 89 } 90 sc.StorageClass = *res 91 return nil 92 } 93 94 // Get refreshes the resource. 95 func (sc *StorageClass) Get(ctx context.Context, client kubernetes.Interface) error { 96 api := client.StorageV1().StorageClasses() 97 res, err := api.Get(ctx, sc.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 sc.StorageClass = *res 104 return nil 105 } 106 107 // Delete removes the resource. 108 func (sc *StorageClass) Delete(ctx context.Context, client kubernetes.Interface) error { 109 api := client.StorageV1().StorageClasses() 110 err := api.Delete(ctx, sc.Name, metav1.DeleteOptions{ 111 PropagationPolicy: k8sconstants.DefaultPropagationPolicy(), 112 }) 113 if k8serrors.IsNotFound(err) { 114 return nil 115 } else if err != nil { 116 return errors.Trace(err) 117 } 118 return nil 119 } 120 121 // Events emitted by the resource. 122 func (sc *StorageClass) Events(ctx context.Context, client kubernetes.Interface) ([]corev1.Event, error) { 123 return ListEventsForObject(ctx, client, "", sc.Name, "StorageClass") 124 } 125 126 // ComputeStatus returns a juju status for the resource. 127 func (sc *StorageClass) ComputeStatus(ctx context.Context, client kubernetes.Interface, now time.Time) (string, status.Status, time.Time, error) { 128 if sc.DeletionTimestamp != nil { 129 return "", status.Terminated, sc.DeletionTimestamp.Time, nil 130 } 131 return "", status.Active, sc.CreationTimestamp.Time, nil 132 }