-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from tomp21/refactor/reconcilers
Refactor/reconcilers
- Loading branch information
Showing
14 changed files
with
621 additions
and
587 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Empty file.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package reconcilers | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"math/rand/v2" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
|
||
cachev1alpha1 "github.com/tomp21/yazio-challenge/api/v1alpha1" | ||
"github.com/tomp21/yazio-challenge/internal/util" | ||
) | ||
|
||
const ( | ||
passwordSpecialChars = "!@#$%^&*()_+-=[]{};':,./?~" | ||
passwordLetters = "abcdefghijklmnopqrstuvwxyz" | ||
passwordNumbers = "0123456789" | ||
passwordLength = 12 | ||
) | ||
|
||
var PasswordSecretKey = "redis-password" | ||
|
||
type SecretReconciler struct { | ||
client.Client | ||
scheme *runtime.Scheme | ||
} | ||
|
||
func NewSecretReconciler(client client.Client, scheme *runtime.Scheme) *SecretReconciler { | ||
return &SecretReconciler{ | ||
Client: client, | ||
scheme: scheme, | ||
} | ||
} | ||
|
||
// Known issue: if the secret was edited and the redis-secret field no longer exist, but the secret itself is there, we are not fixing it | ||
func (r *SecretReconciler) Reconcile(ctx context.Context, redis *cachev1alpha1.Redis) error { | ||
secret := &corev1.Secret{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: redis.Name, | ||
Namespace: redis.Namespace, | ||
Labels: util.GetLabels(redis, nil), | ||
}, | ||
} | ||
namespacedName := types.NamespacedName{ | ||
Name: redis.Name, | ||
Namespace: redis.Namespace, | ||
} | ||
password := generateSecureRedisPassword() | ||
err := r.Get(ctx, namespacedName, secret) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
secret.StringData = map[string]string{PasswordSecretKey: password} | ||
controllerutil.SetControllerReference(redis, secret, r.scheme) | ||
return r.Create(ctx, secret) | ||
} | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// This code is quite ugly, but does the job | ||
func generateSecureRedisPassword() string { | ||
var password []byte | ||
//We get an amount of letters that will be uppercase, which at max will be passwordLength/2, then we iterate pulling random letters until we get that amount | ||
// Using IntN()+1 we ensure the amount is not 0 | ||
upperCaseChars := rand.IntN(passwordLength/2) + 1 | ||
for len(password) < upperCaseChars { | ||
password = append(password, passwordLetters[rand.IntN(len(passwordLetters)-1)]) | ||
} | ||
// We set this letters to uppercase and continue pulling at least 1 char of each string of symbols | ||
password = bytes.ToUpper(password) | ||
password = append(password, passwordSpecialChars[rand.IntN(len(passwordSpecialChars)-2)]+1) | ||
password = append(password, passwordLetters[rand.IntN(len(passwordLetters)-2)]+1) | ||
password = append(password, passwordNumbers[rand.IntN(len(passwordNumbers)-2)]+1) | ||
allchars := passwordSpecialChars + passwordLetters + passwordNumbers | ||
// In the end, we keep pulling random characters from a string containing all symbols in order to get the length defined | ||
for len(password) < passwordLength { | ||
password = append(password, allchars[rand.IntN(len(allchars)-1)]) | ||
} | ||
// shuffle them around | ||
rand.Shuffle(len(password), func(i, j int) { | ||
password[i], password[j] = password[j], password[i] | ||
}) | ||
return string(password) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package reconcilers | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func Test_generateSecret(t *testing.T) { | ||
password := generateSecureRedisPassword() | ||
|
||
if len(password) != passwordLength { | ||
t.Fatalf("Password length is not the expected one") | ||
} | ||
var succeed, specialChar, lowerCaseLetter, upperCaseLetter, number bool | ||
for _, rune := range password { | ||
char := string(rune) | ||
if strings.Contains(passwordSpecialChars, char) { | ||
specialChar = true | ||
} | ||
if strings.Contains(passwordLetters, char) { | ||
lowerCaseLetter = true | ||
} | ||
if strings.Contains(passwordNumbers, char) { | ||
number = true | ||
} | ||
if strings.Contains(passwordLetters, strings.ToLower(char)) { | ||
upperCaseLetter = true | ||
} | ||
succeed = specialChar && lowerCaseLetter && number && upperCaseLetter | ||
} | ||
if !succeed { | ||
t.Fatalf("Password %s did not contain all required types of characters", password) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package reconcilers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
cachev1alpha1 "github.com/tomp21/yazio-challenge/api/v1alpha1" | ||
"github.com/tomp21/yazio-challenge/internal/util" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/util/intstr" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
) | ||
|
||
const ( | ||
RedisPort = 6379 | ||
RedisPortName = "redis" | ||
) | ||
|
||
type ServiceReconciler struct { | ||
client *client.Client | ||
scheme *runtime.Scheme | ||
} | ||
|
||
func NewServiceReconciler(client *client.Client, scheme *runtime.Scheme) *ServiceReconciler { | ||
return &ServiceReconciler{ | ||
client: client, | ||
scheme: scheme, | ||
} | ||
} | ||
|
||
func (r *ServiceReconciler) Reconcile(ctx context.Context, redis *cachev1alpha1.Redis) error { | ||
//master svc | ||
masterSvcName := fmt.Sprintf("%s-master", redis.Name) | ||
err := r.createOrUpdateService(ctx, masterSvcName, redis) | ||
if err != nil { | ||
return err | ||
} | ||
//replicas svc | ||
replicaSvcName := fmt.Sprintf("%s-replica", redis.Name) | ||
err = r.createOrUpdateService(ctx, replicaSvcName, redis) | ||
if err != nil { | ||
return err | ||
} | ||
headlessSvcName := fmt.Sprintf("%s-headless", redis.Name) | ||
err = r.createOrUpdateService(ctx, headlessSvcName, redis) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (r *ServiceReconciler) createOrUpdateService(ctx context.Context, svcName string, redis *cachev1alpha1.Redis) error { | ||
labels := util.GetLabels(redis, util.MasterLabels) | ||
svc := generateService(labels, svcName, redis.Namespace) | ||
|
||
_, err := controllerutil.CreateOrUpdate(ctx, *r.client, svc, func() error { | ||
// we generate the service again to override any change that might've been done to the live resource | ||
svc = generateService(labels, svcName, redis.Namespace) | ||
svc.ObjectMeta.SetLabels(labels) | ||
return controllerutil.SetControllerReference(redis, svc, r.scheme) | ||
}) | ||
return err | ||
} | ||
|
||
func generateService(labels map[string]string, name string, namespace string) *corev1.Service { | ||
return &corev1.Service{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
Namespace: namespace, | ||
Labels: labels, | ||
}, | ||
Spec: corev1.ServiceSpec{ | ||
Type: "ClusterIP", | ||
Ports: []corev1.ServicePort{ | ||
{ | ||
Name: "tcp-redis", | ||
Port: RedisPort, | ||
TargetPort: intstr.FromString(RedisPortName), | ||
}, | ||
}, | ||
Selector: labels, | ||
}, | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
internal/controller/reconcilers/serviceaccount_reconciler.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package reconcilers | ||
|
||
import ( | ||
"context" | ||
cachev1alpha1 "github.com/tomp21/yazio-challenge/api/v1alpha1" | ||
"github.com/tomp21/yazio-challenge/internal/util" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
) | ||
|
||
type ServiceAccountReconciler struct { | ||
client *client.Client | ||
scheme *runtime.Scheme | ||
} | ||
|
||
func NewServiceAccountReconciler(client *client.Client, scheme *runtime.Scheme) *ServiceAccountReconciler { | ||
return &ServiceAccountReconciler{ | ||
client: client, | ||
scheme: scheme, | ||
} | ||
} | ||
|
||
func (r *ServiceAccountReconciler) Reconcile(ctx context.Context, redis *cachev1alpha1.Redis) error { | ||
|
||
sa := &corev1.ServiceAccount{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: redis.Name, | ||
Namespace: redis.Namespace, | ||
}, | ||
} | ||
_, err := controllerutil.CreateOrUpdate(ctx, *r.client, sa, func() error { | ||
sa.GetObjectMeta().SetLabels(util.GetLabels(redis, nil)) | ||
return controllerutil.SetControllerReference(redis, sa, r.scheme) | ||
}) | ||
return err | ||
} |
Oops, something went wrong.