github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/resources/service.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 "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 // Service extends the k8s service. 24 type Service struct { 25 corev1.Service 26 PatchType *types.PatchType 27 } 28 29 // NewService creates a new service resource. 30 func NewService(name string, namespace string, in *corev1.Service) *Service { 31 if in == nil { 32 in = &corev1.Service{} 33 } 34 in.SetName(name) 35 in.SetNamespace(namespace) 36 return &Service{Service: *in} 37 } 38 39 // Clone returns a copy of the resource. 40 func (s *Service) Clone() Resource { 41 clone := *s 42 return &clone 43 } 44 45 // ID returns a comparable ID for the Resource 46 func (s *Service) ID() ID { 47 return ID{"Service", s.Name, s.Namespace} 48 } 49 50 // Apply patches the resource change. 51 func (s *Service) Apply(ctx context.Context, client kubernetes.Interface) error { 52 api := client.CoreV1().Services(s.Namespace) 53 data, err := runtime.Encode(unstructured.UnstructuredJSONScheme, &s.Service) 54 if err != nil { 55 return errors.Trace(err) 56 } 57 patchStrategy := preferedPatchStrategy 58 if s.PatchType != nil { 59 patchStrategy = *s.PatchType 60 } 61 res, err := api.Patch(ctx, s.Name, patchStrategy, data, metav1.PatchOptions{ 62 FieldManager: JujuFieldManager, 63 }) 64 if k8serrors.IsNotFound(err) { 65 res, err = api.Create(ctx, &s.Service, metav1.CreateOptions{ 66 FieldManager: JujuFieldManager, 67 }) 68 } 69 if k8serrors.IsConflict(err) { 70 return errors.Annotatef(errConflict, "service %q", s.Name) 71 } 72 if err != nil { 73 return errors.Trace(err) 74 } 75 s.Service = *res 76 return nil 77 } 78 79 // Get refreshes the resource. 80 func (s *Service) Get(ctx context.Context, client kubernetes.Interface) error { 81 api := client.CoreV1().Services(s.Namespace) 82 res, err := api.Get(ctx, s.Name, metav1.GetOptions{}) 83 if k8serrors.IsNotFound(err) { 84 return errors.NewNotFound(err, "k8s") 85 } else if err != nil { 86 return errors.Trace(err) 87 } 88 s.Service = *res 89 return nil 90 } 91 92 // Delete removes the resource. 93 func (s *Service) Delete(ctx context.Context, client kubernetes.Interface) error { 94 api := client.CoreV1().Services(s.Namespace) 95 err := api.Delete(ctx, s.Name, metav1.DeleteOptions{ 96 PropagationPolicy: k8sconstants.DefaultPropagationPolicy(), 97 }) 98 if k8serrors.IsNotFound(err) { 99 return nil 100 } else if err != nil { 101 return errors.Trace(err) 102 } 103 return nil 104 } 105 106 // Events emitted by the resource. 107 func (s *Service) Events(ctx context.Context, client kubernetes.Interface) ([]corev1.Event, error) { 108 return ListEventsForObject(ctx, client, s.Namespace, s.Name, "Service") 109 } 110 111 // ComputeStatus returns a juju status for the resource. 112 func (s *Service) ComputeStatus(ctx context.Context, client kubernetes.Interface, now time.Time) (string, status.Status, time.Time, error) { 113 if s.DeletionTimestamp != nil { 114 return "", status.Terminated, s.DeletionTimestamp.Time, nil 115 } 116 return "", status.Active, s.CreationTimestamp.Time, nil 117 }