Skip to content

Commit

Permalink
[redis] add client helpers and add port consts
Browse files Browse the repository at this point in the history
  • Loading branch information
stuggi committed Apr 10, 2024
1 parent d0ab878 commit b667046
Show file tree
Hide file tree
Showing 15 changed files with 221 additions and 53 deletions.
15 changes: 15 additions & 0 deletions apis/bases/redis.openstack.org_redises.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ spec:
ContainerImage)
format: int64
type: integer
serverList:
description: ServerList - List of redis endpoints without inet(6)
prefix
items:
type: string
type: array
serverListWithInet:
description: ServerListWithInet - List of redis endpoints with inet(6)
prefix
items:
type: string
type: array
tlsSupport:
description: Whether TLS is supported by the redis instance
type: boolean
type: object
type: object
served: true
Expand Down
89 changes: 89 additions & 0 deletions apis/redis/v1beta1/redis_funcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2023.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta1

import (
"context"
"strings"

condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
"k8s.io/apimachinery/pkg/types"
)

// IsReady - returns true if service is ready to serve requests
func (instance Redis) IsReady() bool {
return instance.Status.Conditions.IsTrue(condition.ReadyCondition)
}

// RbacConditionsSet - set the conditions for the rbac object
func (instance Redis) RbacConditionsSet(c *condition.Condition) {
instance.Status.Conditions.Set(c)
}

// RbacNamespace - return the namespace
func (instance Redis) RbacNamespace() string {
return instance.Namespace
}

// RbacResourceName - return the name to be used for rbac objects (serviceaccount, role, rolebinding)
func (instance Redis) RbacResourceName() string {
return "redis-" + instance.Name
}

// SetupDefaults - initializes any CRD field defaults based on environment variables (the defaulting mechanism itself is implemented via webhooks)
func SetupDefaults() {
// Acquire environmental defaults and initialize Redis defaults with them
redisDefaults := RedisDefaults{
ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_INFRA_REDIS_IMAGE_URL_DEFAULT", RedisContainerImage),
}

SetupRedisDefaults(redisDefaults)
}

// GetRedisServerListString - return the redis servers as comma separated list
// to be used in OpenStack config.
func (instance *Redis) GetRedisServerListString() string {
return strings.Join(instance.Status.ServerList, ",")
}

// GetRedisTLSSupport - return the TLS support of the redis instance
func (instance *Redis) GetRedisTLSSupport() bool {
return instance.Status.TLSSupport
}

// GetRedisByName - gets the Redis instance
func GetRedisByName(
ctx context.Context,
h *helper.Helper,
name string,
namespace string,
) (*Redis, error) {
redis := &Redis{}
err := h.GetClient().Get(
ctx,
types.NamespacedName{
Name: name,
Namespace: namespace,
},
redis)
if err != nil {
return nil, err
}
return redis, err
}
41 changes: 10 additions & 31 deletions apis/redis/v1beta1/redis_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package v1beta1
import (
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
"github.com/openstack-k8s-operators/lib-common/modules/common/tls"
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -55,9 +54,19 @@ type RedisSpecCore struct {
type RedisStatus struct {
// Map of hashes to track input changes
Hash map[string]string `json:"hash,omitempty"`

// Conditions
Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"`

// ServerList - List of redis endpoints without inet(6) prefix
ServerList []string `json:"serverList,omitempty" optional:"true"`

// ServerListWithInet - List of redis endpoints with inet(6) prefix
ServerListWithInet []string `json:"serverListWithInet,omitempty" optional:"true"`

// Whether TLS is supported by the redis instance
TLSSupport bool `json:"tlsSupport,omitempty"`

// ObservedGeneration - the most recent generation observed for this
// service. If the observed generation is less than the spec generation,
// then the controller has not processed the latest changes injected by
Expand Down Expand Up @@ -90,33 +99,3 @@ type RedisList struct {
func init() {
SchemeBuilder.Register(&Redis{}, &RedisList{})
}

// IsReady - returns true if service is ready to serve requests
func (instance Redis) IsReady() bool {
return instance.Status.Conditions.IsTrue(condition.ReadyCondition)
}

// RbacConditionsSet - set the conditions for the rbac object
func (instance Redis) RbacConditionsSet(c *condition.Condition) {
instance.Status.Conditions.Set(c)
}

// RbacNamespace - return the namespace
func (instance Redis) RbacNamespace() string {
return instance.Namespace
}

// RbacResourceName - return the name to be used for rbac objects (serviceaccount, role, rolebinding)
func (instance Redis) RbacResourceName() string {
return "redis-" + instance.Name
}

// SetupDefaults - initializes any CRD field defaults based on environment variables (the defaulting mechanism itself is implemented via webhooks)
func SetupDefaults() {
// Acquire environmental defaults and initialize Redis defaults with them
redisDefaults := RedisDefaults{
ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_INFRA_REDIS_IMAGE_URL_DEFAULT", RedisContainerImage),
}

SetupRedisDefaults(redisDefaults)
}
10 changes: 10 additions & 0 deletions apis/redis/v1beta1/zz_generated.deepcopy.go

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

15 changes: 15 additions & 0 deletions config/crd/bases/redis.openstack.org_redises.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ spec:
ContainerImage)
format: int64
type: integer
serverList:
description: ServerList - List of redis endpoints without inet(6)
prefix
items:
type: string
type: array
serverListWithInet:
description: ServerListWithInet - List of redis endpoints with inet(6)
prefix
items:
type: string
type: array
tlsSupport:
description: Whether TLS is supported by the redis instance
type: boolean
type: object
type: object
served: true
Expand Down
37 changes: 36 additions & 1 deletion controllers/redis/redis_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct
if specTLS.Enabled() {
certHash, _, err = specTLS.GenericService.ValidateCertSecret(ctx, helper, instance.Namespace)
inputHashEnv["Cert"] = env.SetValue(certHash)
instance.Status.TLSSupport = true
}
if err == nil && specTLS.Ca.CaBundleSecretName != "" {
caName := types.NamespacedName{
Expand Down Expand Up @@ -311,8 +312,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct
condition.SeverityWarning,
condition.ExposeServiceReadyErrorMessage,
err.Error()))

return sres, serr
}
ipFamily := commonsvc.GetIPFamilies()[0]
serverList, serverListWithInet := r.GetServerLists(instance, ipFamily)
instance.Status.ServerList = serverList
instance.Status.ServerListWithInet = serverListWithInet

instance.Status.Conditions.MarkTrue(condition.ExposeServiceReadyCondition, condition.ExposeServiceReadyMessage)

//
Expand Down Expand Up @@ -347,7 +354,10 @@ func (r *Reconciler) generateConfigMaps(
instance *redisv1.Redis,
envVars *map[string]env.Setter,
) error {
templateParameters := make(map[string]interface{})
templateParameters := map[string]interface{}{
"redisPort": redis.RedisPort,
"sentinelPort": redis.SentinelPort,
}
customData := make(map[string]string)

cms := []util.Template{
Expand Down Expand Up @@ -455,3 +465,28 @@ func (r *Reconciler) findObjectsForSrc(ctx context.Context, src client.Object) [

return requests
}

// GetServerLists returns list of memcached server without/with inet prefix
func (r *Reconciler) GetServerLists(
instance *redisv1.Redis,
ipFamily corev1.IPFamily,
) ([]string, []string) {
var serverList []string
var serverListWithInet []string

prefix := "inet"
if ipFamily == corev1.IPv6Protocol {
prefix = "inet6"
}

for i := int32(0); i < *(instance.Spec.Replicas); i++ {
server := fmt.Sprintf("%s-%d.%s.%s.svc", instance.Name, i, instance.Name, instance.Namespace)
serverList = append(serverList, fmt.Sprintf("%s:%d", server, redis.RedisPort))

// python-memcached requires inet(6) prefix according to the IP version
// used by the memcached server.
serverListWithInet = append(serverListWithInet, fmt.Sprintf("%s:[%s]:%d", prefix, server, redis.RedisPort))
}

return serverList, serverListWithInet
}
25 changes: 25 additions & 0 deletions pkg/redis/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package redis

const (
// RedisPort -
RedisPort int32 = 6379
// SentinelPort -
SentinelPort int32 = 26379
// ClusterInternalDomain - cluster internal dns domain
ClusterInternalDomain = "cluster.local"
)
6 changes: 3 additions & 3 deletions pkg/redis/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ func Deployment(r *redisv1.Redis) *appsv1.Deployment {
}

livenessProbe.TCPSocket = &corev1.TCPSocketAction{
Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(6379)},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: RedisPort},
}
readinessProbe.TCPSocket = &corev1.TCPSocketAction{
Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(6379)},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: RedisPort},
}

deployment := &appsv1.Deployment{
Expand All @@ -58,7 +58,7 @@ func Deployment(r *redisv1.Redis) *appsv1.Deployment {
Image: r.Spec.ContainerImage,
Name: "redis",
Ports: []corev1.ContainerPort{{
ContainerPort: 6379,
ContainerPort: RedisPort,
Name: "redis",
}},
ReadinessProbe: readinessProbe,
Expand Down
6 changes: 3 additions & 3 deletions pkg/redis/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func Service(instance *redisv1.Redis) *corev1.Service {
},
Port: service.GenericServicePort{
Name: "redis",
Port: 6379,
Port: RedisPort,
Protocol: "TCP",
},
}
Expand All @@ -49,8 +49,8 @@ func HeadlessService(instance *redisv1.Redis) *corev1.Service {
common.OwnerSelector: instance.Name,
},
Ports: []corev1.ServicePort{
{Name: "redis", Protocol: "TCP", Port: 6379},
{Name: "sentinel", Protocol: "TCP", Port: 26379},
{Name: "redis", Protocol: "TCP", Port: RedisPort},
{Name: "sentinel", Protocol: "TCP", Port: SentinelPort},
},
ClusterIP: "None",
PublishNotReadyAddresses: true,
Expand Down
14 changes: 7 additions & 7 deletions pkg/redis/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ func StatefulSet(r *redisv1.Redis) *appsv1.StatefulSet {
}

livenessProbe.TCPSocket = &corev1.TCPSocketAction{
Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(6379)},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: RedisPort},
}
readinessProbe.TCPSocket = &corev1.TCPSocketAction{
Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(6379)},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: RedisPort},
}
sentinelLivenessProbe.TCPSocket = &corev1.TCPSocketAction{
Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(26379)},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: SentinelPort},
}
sentinelReadinessProbe.TCPSocket = &corev1.TCPSocketAction{
Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(26379)},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: SentinelPort},
}
name := r.Name + "-" + "redis"

Expand All @@ -67,7 +67,7 @@ func StatefulSet(r *redisv1.Redis) *appsv1.StatefulSet {
// https://github.com/kubernetes/dns/blob/master/docs/specification.md
// Headless services only publish dns entries that include cluster domain.
// For the time being, assume this is .cluster.local
Value: name + "." + r.GetNamespace() + ".svc.cluster.local",
Value: name + "." + r.GetNamespace() + ".svc." + ClusterInternalDomain,
}}

sts := &appsv1.StatefulSet{
Expand All @@ -94,7 +94,7 @@ func StatefulSet(r *redisv1.Redis) *appsv1.StatefulSet {
Env: commonEnvVars,
VolumeMounts: getRedisVolumeMounts(r),
Ports: []corev1.ContainerPort{{
ContainerPort: 6379,
ContainerPort: RedisPort,
Name: "redis",
}},
LivenessProbe: &corev1.Probe{
Expand Down Expand Up @@ -122,7 +122,7 @@ func StatefulSet(r *redisv1.Redis) *appsv1.StatefulSet {
}),
VolumeMounts: getSentinelVolumeMounts(r),
Ports: []corev1.ContainerPort{{
ContainerPort: 26379,
ContainerPort: SentinelPort,
Name: "sentinel",
}},
ReadinessProbe: sentinelReadinessProbe,
Expand Down
Loading

0 comments on commit b667046

Please sign in to comment.