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  }