github.com/spotahome/redis-operator@v1.2.4/service/k8s/service.go (about) 1 package k8s 2 3 import ( 4 "context" 5 6 corev1 "k8s.io/api/core/v1" 7 "k8s.io/apimachinery/pkg/api/errors" 8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 "k8s.io/client-go/kubernetes" 10 11 "github.com/spotahome/redis-operator/log" 12 "github.com/spotahome/redis-operator/metrics" 13 ) 14 15 // Service the ServiceAccount service that knows how to interact with k8s to manage them 16 type Service interface { 17 GetService(namespace string, name string) (*corev1.Service, error) 18 CreateService(namespace string, service *corev1.Service) error 19 CreateIfNotExistsService(namespace string, service *corev1.Service) error 20 UpdateService(namespace string, service *corev1.Service) error 21 CreateOrUpdateService(namespace string, service *corev1.Service) error 22 DeleteService(namespace string, name string) error 23 ListServices(namespace string) (*corev1.ServiceList, error) 24 } 25 26 // ServiceService is the service service implementation using API calls to kubernetes. 27 type ServiceService struct { 28 kubeClient kubernetes.Interface 29 logger log.Logger 30 metricsRecorder metrics.Recorder 31 } 32 33 // NewServiceService returns a new Service KubeService. 34 func NewServiceService(kubeClient kubernetes.Interface, logger log.Logger, metricsRecorder metrics.Recorder) *ServiceService { 35 logger = logger.With("service", "k8s.service") 36 return &ServiceService{ 37 kubeClient: kubeClient, 38 logger: logger, 39 metricsRecorder: metricsRecorder, 40 } 41 } 42 43 func (s *ServiceService) GetService(namespace string, name string) (*corev1.Service, error) { 44 service, err := s.kubeClient.CoreV1().Services(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 45 recordMetrics(namespace, "Service", name, "GET", err, s.metricsRecorder) 46 if err != nil { 47 return nil, err 48 } 49 return service, err 50 } 51 52 func (s *ServiceService) CreateService(namespace string, service *corev1.Service) error { 53 _, err := s.kubeClient.CoreV1().Services(namespace).Create(context.TODO(), service, metav1.CreateOptions{}) 54 recordMetrics(namespace, "Service", service.GetName(), "CREATE", err, s.metricsRecorder) 55 if err != nil { 56 return err 57 } 58 s.logger.WithField("namespace", namespace).WithField("serviceName", service.Name).Debugf("service created") 59 return nil 60 } 61 62 func (s *ServiceService) CreateIfNotExistsService(namespace string, service *corev1.Service) error { 63 if _, err := s.GetService(namespace, service.Name); err != nil { 64 // If no resource we need to create. 65 if errors.IsNotFound(err) { 66 return s.CreateService(namespace, service) 67 } 68 return err 69 } 70 return nil 71 } 72 73 func (s *ServiceService) UpdateService(namespace string, service *corev1.Service) error { 74 _, err := s.kubeClient.CoreV1().Services(namespace).Update(context.TODO(), service, metav1.UpdateOptions{}) 75 recordMetrics(namespace, "Service", service.GetName(), "UPDATE", err, s.metricsRecorder) 76 if err != nil { 77 return err 78 } 79 s.logger.WithField("namespace", namespace).WithField("serviceName", service.Name).Debugf("service updated") 80 return nil 81 } 82 func (s *ServiceService) CreateOrUpdateService(namespace string, service *corev1.Service) error { 83 storedService, err := s.GetService(namespace, service.Name) 84 if err != nil { 85 // If no resource we need to create. 86 if errors.IsNotFound(err) { 87 return s.CreateService(namespace, service) 88 } 89 log.Errorf("Error while updating service %v in %v namespace : %v", service.GetName(), namespace, err) 90 return err 91 } 92 93 // Already exists, need to Update. 94 // Set the correct resource version to ensure we are on the latest version. This way the only valid 95 // namespace is our spec(https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#concurrency-control-and-consistency), 96 // we will replace the current namespace state. 97 service.ResourceVersion = storedService.ResourceVersion 98 return s.UpdateService(namespace, service) 99 } 100 101 func (s *ServiceService) DeleteService(namespace string, name string) error { 102 propagation := metav1.DeletePropagationForeground 103 err := s.kubeClient.CoreV1().Services(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{PropagationPolicy: &propagation}) 104 recordMetrics(namespace, "Service", name, "DELETE", err, s.metricsRecorder) 105 return err 106 } 107 108 func (s *ServiceService) ListServices(namespace string) (*corev1.ServiceList, error) { 109 serviceList, err := s.kubeClient.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{}) 110 recordMetrics(namespace, "Service", metrics.NOT_APPLICABLE, "LIST", err, s.metricsRecorder) 111 return serviceList, err 112 }