func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorInterface.Inspector) error {
	log := r.log
	start := time.Now()
	apiObject := r.context.GetAPIObject()
	status, _ := r.context.GetStatus()
	deploymentName := apiObject.GetName()
	owner := apiObject.AsOwner()
	spec := r.context.GetSpec()
	defer metrics.SetDuration(inspectServicesDurationGauges.WithLabelValues(deploymentName), start)
	counterMetric := inspectedServicesCounters.WithLabelValues(deploymentName)
	svcs := r.context.ServicesModInterface()
	reconcileRequired := k8sutil.NewReconcile(cachedStatus)
	if err := status.Members.ForeachServerGroup(func(group api.ServerGroup, list api.MemberStatusList) error {
		for _, m := range list {
			memberName := m.ArangoMemberName(r.context.GetAPIObject().GetName(), group)
			member, ok := cachedStatus.ArangoMember(memberName)
			if !ok {
				return errors.Newf("Member %s not found", memberName)
			}
			if s, ok := cachedStatus.Service(member.GetName()); !ok {
				s = &core.Service{
					ObjectMeta: metav1.ObjectMeta{
						Name:      member.GetName(),
						Namespace: member.GetNamespace(),
						OwnerReferences: []metav1.OwnerReference{
							member.AsOwner(),
						},
					},
					Spec: core.ServiceSpec{
						Type: core.ServiceTypeClusterIP,
						Ports: []core.ServicePort{
							{
								Name:       "server",
								Protocol:   "TCP",
								Port:       k8sutil.ArangoPort,
								TargetPort: intstr.IntOrString{IntVal: k8sutil.ArangoPort},
							},
						},
						PublishNotReadyAddresses: true,
						Selector:                 k8sutil.LabelsForMember(deploymentName, group.AsRole(), m.ID),
					},
				}
				err := k8sutil.RunWithTimeout(ctx, func(ctxChild context.Context) error {
					_, err := svcs.Create(ctxChild, s, metav1.CreateOptions{})
					return err
				})
				if err != nil {
					if !k8sutil.IsConflict(err) {
						return err
					}
				}
				reconcileRequired.Required()
				continue
			} else {
				spec := s.Spec.DeepCopy()
				spec.Type = core.ServiceTypeClusterIP
				spec.Ports = []core.ServicePort{
					{
						Name:       "server",
						Protocol:   "TCP",
						Port:       k8sutil.ArangoPort,
						TargetPort: intstr.IntOrString{IntVal: k8sutil.ArangoPort},
					},
				}
				spec.PublishNotReadyAddresses = true
				spec.Selector = k8sutil.LabelsForMember(deploymentName, group.AsRole(), m.ID)
				if !equality.Semantic.DeepDerivative(*spec, s.Spec) {
					s.Spec = *spec
					err := k8sutil.RunWithTimeout(ctx, func(ctxChild context.Context) error {
						_, err := svcs.Update(ctxChild, s, metav1.UpdateOptions{})
						return err
					})
					if err != nil {
						return err
					}
					reconcileRequired.Required()
					continue
				}
			}
		}
		return nil
	}); err != nil {
		return err
	}
	counterMetric.Inc()
	if _, exists := cachedStatus.Service(k8sutil.CreateHeadlessServiceName(deploymentName)); !exists {
		ctxChild, cancel := context.WithTimeout(ctx, k8sutil.GetRequestTimeout())
		defer cancel()
		svcName, newlyCreated, err := k8sutil.CreateHeadlessService(ctxChild, svcs, apiObject, owner)
		if err != nil {
			log.Debug().Err(err).Msg("Failed to create headless service")
			return errors.WithStack(err)
		}
		if newlyCreated {
			log.Debug().Str("service", svcName).Msg("Created headless service")
		}
	}
	single := spec.GetMode().HasSingleServers()
	counterMetric.Inc()
	if _, exists := cachedStatus.Service(k8sutil.CreateDatabaseClientServiceName(deploymentName)); !exists {
		ctxChild, cancel := context.WithTimeout(ctx, k8sutil.GetRequestTimeout())
		defer cancel()
		svcName, newlyCreated, err := k8sutil.CreateDatabaseClientService(ctxChild, svcs, apiObject, single, owner)
		if err != nil {
			log.Debug().Err(err).Msg("Failed to create database client service")
			return errors.WithStack(err)
		}
		if newlyCreated {
			log.Debug().Str("service", svcName).Msg("Created database client service")
		}
		{
			status, lastVersion := r.context.GetStatus()
			if status.ServiceName != svcName {
				status.ServiceName = svcName
				if err := r.context.UpdateStatus(ctx, status, lastVersion); err != nil {
					return errors.WithStack(err)
				}
			}
		}
	}
	eaServiceName := k8sutil.CreateDatabaseExternalAccessServiceName(deploymentName)
	role := "coordinator"
	if single {
		role = "single"
	}
	if err := r.ensureExternalAccessServices(ctx, cachedStatus, svcs, eaServiceName, role, "database", k8sutil.ArangoPort, false, spec.ExternalAccess, apiObject, log); err != nil {
		return errors.WithStack(err)
	}
	if spec.Sync.IsEnabled() {
		counterMetric.Inc()
		eaServiceName := k8sutil.CreateSyncMasterClientServiceName(deploymentName)
		role := "syncmaster"
		if err := r.ensureExternalAccessServices(ctx, cachedStatus, svcs, eaServiceName, role, "sync", k8sutil.ArangoSyncMasterPort, true, spec.Sync.ExternalAccess.ExternalAccessSpec, apiObject, log); err != nil {
			return errors.WithStack(err)
		}
		status, lastVersion := r.context.GetStatus()
		if status.SyncServiceName != eaServiceName {
			status.SyncServiceName = eaServiceName
			if err := r.context.UpdateStatus(ctx, status, lastVersion); err != nil {
				return errors.WithStack(err)
			}
		}
	}
	if spec.Metrics.IsEnabled() {
		ctxChild, cancel := context.WithTimeout(ctx, k8sutil.GetRequestTimeout())
		defer cancel()
		name, _, err := k8sutil.CreateExporterService(ctxChild, cachedStatus, svcs, apiObject, apiObject.AsOwner())
		if err != nil {
			log.Debug().Err(err).Msgf("Failed to create %s exporter service", name)
			return errors.WithStack(err)
		}
		status, lastVersion := r.context.GetStatus()
		if status.ExporterServiceName != name {
			status.ExporterServiceName = name
			if err := r.context.UpdateStatus(ctx, status, lastVersion); err != nil {
				return errors.WithStack(err)
			}
		}
	}
	return reconcileRequired.Reconcile(ctx)
}
EnsureServices creates all services needed to service the deployment
package resources
import (
	"context"
	"strings"
	"time"
	"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service"
	"k8s.io/apimachinery/pkg/api/equality"
	"k8s.io/apimachinery/pkg/util/intstr"
	"github.com/arangodb/kube-arangodb/pkg/util/errors"
	inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
	core "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
	"github.com/arangodb/kube-arangodb/pkg/metrics"
	"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
	"github.com/rs/zerolog"
)
var (
	inspectedServicesCounters     = metrics.MustRegisterCounterVec(metricsComponent, "inspected_services", "Number of Service inspections per deployment", metrics.DeploymentName)
	inspectServicesDurationGauges = metrics.MustRegisterGaugeVec(metricsComponent, "inspect_services_duration", "Amount of time taken by a single inspection of all Services for a deployment (in sec)", metrics.DeploymentName)
)