Skip to content

Commit

Permalink
Merge pull request #27 from janlauber/fix-multi-rollouts
Browse files Browse the repository at this point in the history
feat: Refactor Kubernetes manifests and controller code
  • Loading branch information
janlauber authored Apr 15, 2024
2 parents 50298ca + 28802e4 commit 4e4038f
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 151 deletions.
54 changes: 22 additions & 32 deletions controllers/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@ import (
oneclickiov1alpha1 "github.com/janlauber/one-click-operator/api/v1alpha1"
)

func (r *RolloutReconciler) reconcileDeployment(ctx context.Context, rollout *oneclickiov1alpha1.Rollout) error {
func (r *RolloutReconciler) reconcileDeployment(ctx context.Context, f *oneclickiov1alpha1.Rollout) error {
log := log.FromContext(ctx)

desiredDeployment := r.deploymentForRollout(ctx, rollout)
desiredDeployment := r.deploymentForRollout(ctx, f)

currentDeployment := &appsv1.Deployment{}
err := r.Get(ctx, types.NamespacedName{Name: rollout.Name, Namespace: rollout.Namespace}, currentDeployment)
err := r.Get(ctx, types.NamespacedName{Name: f.Name, Namespace: f.Namespace}, currentDeployment)
if err != nil && errors.IsNotFound(err) {
log.Info("Creating a new Deployment", "Deployment.Namespace", rollout.Namespace, "Deployment.Name", rollout.Name)
r.Recorder.Eventf(f, corev1.EventTypeNormal, "Creating", "Creating Deployment %s", f.Name)
return r.Create(ctx, desiredDeployment)
} else if err != nil {
log.Error(err, "Failed to get Deployment")
return err
}

// Compare the current Deployment with the Rollout spec
if needsUpdate(currentDeployment, rollout) {
if needsUpdate(currentDeployment, f) {
// Update the Deployment to align it with the Rollout spec
currentDeployment.Spec = desiredDeployment.Spec
err = r.Update(ctx, currentDeployment)
if err != nil {
log.Error(err, "Failed to update Deployment", "Deployment.Namespace", currentDeployment.Namespace, "Deployment.Name", currentDeployment.Name)
r.Recorder.Eventf(f, corev1.EventTypeWarning, "UpdateFailed", "Failed to update Deployment %s", f.Name)
return err
}
}
Expand All @@ -50,15 +50,18 @@ func (r *RolloutReconciler) reconcileDeployment(ctx context.Context, rollout *on
}

func (r *RolloutReconciler) deploymentForRollout(ctx context.Context, f *oneclickiov1alpha1.Rollout) *appsv1.Deployment {
log := log.FromContext(context.Background())
// the name of the namespace is the project name
labels := map[string]string{"rollout.one-click.dev/name": f.Name, "project.one-click.dev/name": f.Namespace}
labels := map[string]string{
"one-click.dev/projectId": f.Namespace,
"one-click.dev/deploymentId": f.Name,
}
replicas := int32(f.Spec.HorizontalScale.MinReplicas)

dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: f.Name,
Namespace: f.Namespace,
Labels: labels,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Expand All @@ -83,8 +86,7 @@ func (r *RolloutReconciler) deploymentForRollout(ctx context.Context, f *oneclic
corev1.ResourceMemory: resource.MustParse(f.Spec.Resources.Limits.Memory),
},
},
Ports: getContainerPorts(f.Spec.Interfaces),
Env: getEnvVars(f.Spec.Env),
Env: getEnvVars(f.Spec.Env),
}},
ServiceAccountName: f.Spec.ServiceAccountName,
},
Expand Down Expand Up @@ -150,8 +152,7 @@ func (r *RolloutReconciler) deploymentForRollout(ctx context.Context, f *oneclic
// Logic to create or get existing secret
secretName := f.Name + "-imagepullsecret"
if err := r.reconcileImagePullSecret(ctx, f, secretName); err != nil {
log.Error(err, "Failed to reconcile Image Pull Secret")
// Handle error, possibly return it
r.Recorder.Eventf(f, corev1.EventTypeWarning, "ImagePullSecretFailed", "Failed to reconcile Image Pull Secret %s", secretName)
}

// Attach the image pull secret to the deployment
Expand All @@ -166,8 +167,7 @@ func (r *RolloutReconciler) deploymentForRollout(ctx context.Context, f *oneclic
// Logic to create or get existing secret
secretName := f.Name + "-imagepullsecret"
if err := r.reconcileImagePullSecret(ctx, f, secretName); err != nil {
log.Error(err, "Failed to reconcile Image Pull Secret")
// Handle error, possibly return it
r.Recorder.Eventf(f, corev1.EventTypeWarning, "ImagePullSecretFailed", "Failed to reconcile Image Pull Secret %s", secretName)
}
}

Expand All @@ -177,15 +177,15 @@ func (r *RolloutReconciler) deploymentForRollout(ctx context.Context, f *oneclic
var volumeMounts []corev1.VolumeMount
for _, v := range f.Spec.Volumes {
volumes = append(volumes, corev1.Volume{
Name: v.Name,
Name: f.Name + "-" + v.Name,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: v.Name,
ClaimName: f.Name + "-" + v.Name,
},
},
})
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: v.Name,
Name: f.Name + "-" + v.Name,
MountPath: v.MountPath,
})
}
Expand All @@ -208,16 +208,6 @@ func (r *RolloutReconciler) deploymentForRollout(ctx context.Context, f *oneclic
return dep
}

func getContainerPorts(interfaces []oneclickiov1alpha1.InterfaceSpec) []corev1.ContainerPort {
var ports []corev1.ContainerPort
for _, i := range interfaces {
ports = append(ports, corev1.ContainerPort{
ContainerPort: i.Port,
})
}
return ports
}

func getEnvVars(envVars []oneclickiov1alpha1.EnvVar) []corev1.EnvVar {
var envs []corev1.EnvVar
for _, env := range envVars {
Expand Down Expand Up @@ -297,7 +287,7 @@ func needsUpdate(current *appsv1.Deployment, f *oneclickiov1alpha1.Rollout) bool
}

// Check volumes
if !volumesMatch(current.Spec.Template.Spec.Volumes, f.Spec.Volumes) {
if !volumesMatch(current.Spec.Template.Spec.Volumes, f.Spec.Volumes, f) {
return true
}

Expand All @@ -311,25 +301,25 @@ func needsUpdate(current *appsv1.Deployment, f *oneclickiov1alpha1.Rollout) bool
return false
}

func volumesMatch(currentVolumes []corev1.Volume, desiredVolumes []oneclickiov1alpha1.VolumeSpec) bool {
func volumesMatch(currentVolumes []corev1.Volume, desiredVolumes []oneclickiov1alpha1.VolumeSpec, f *oneclickiov1alpha1.Rollout) bool {
if len(currentVolumes) != len(desiredVolumes) {
return false
}

desiredVolumeMap := make(map[string]oneclickiov1alpha1.VolumeSpec)
for _, v := range desiredVolumes {
desiredVolumeMap[v.Name] = v
desiredVolumeMap[f.Name+"-"+v.Name] = v
}

for _, currentVolume := range currentVolumes {
volSpec, exists := desiredVolumeMap[currentVolume.Name]
volSpec, exists := desiredVolumeMap[f.Name+"-"+currentVolume.Name]
if !exists {
// Volume is present in Deployment but not in Rollout spec
return false
}

// Check PVC name
if currentVolume.VolumeSource.PersistentVolumeClaim.ClaimName != volSpec.Name {
if currentVolume.VolumeSource.PersistentVolumeClaim.ClaimName != f.Name+"-"+volSpec.Name {
return false
}
// Additional checks can be added here, such as PVC size, storage class, etc.
Expand Down
9 changes: 0 additions & 9 deletions controllers/hpa.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/log"
)

func (r *RolloutReconciler) reconcileHPA(ctx context.Context, f *oneclickiov1alpha1.Rollout) error {
log := log.FromContext(ctx)

// Construct the desired HPA object based on the Rollout specification
desiredHpa, err := r.hpaForRollout(f)
if err != nil {
log.Error(err, "Failed to construct HPA", "Namespace", f.Namespace, "Name", f.Name)
r.Recorder.Eventf(f, corev1.EventTypeWarning, "CreationFailed", "Failed to construct HPA %s", f.Name)
return err
}
Expand All @@ -29,29 +25,24 @@ func (r *RolloutReconciler) reconcileHPA(ctx context.Context, f *oneclickiov1alp
err = r.Get(ctx, types.NamespacedName{Name: f.Name, Namespace: f.Namespace}, foundHpa)
if err != nil && errors.IsNotFound(err) {
// If the HPA is not found, create a new one
log.Info("Creating a new HPA", "Namespace", desiredHpa.Namespace, "Name", desiredHpa.Name)
err = r.Create(ctx, desiredHpa)
if err != nil {
// Handle creation error
log.Error(err, "Failed to create HPA", "Namespace", desiredHpa.Namespace, "Name", desiredHpa.Name)
r.Recorder.Eventf(f, corev1.EventTypeWarning, "CreationFailed", "Failed to create HPA %s", f.Name)
return err
}
r.Recorder.Eventf(f, corev1.EventTypeNormal, "Created", "Created HPA %s", f.Name)
} else if err != nil {
// Handle other errors
log.Error(err, "Failed to get HPA", "Namespace", desiredHpa.Namespace, "Name", desiredHpa.Name)
r.Recorder.Eventf(f, corev1.EventTypeWarning, "GetFailed", "Failed to get HPA %s", f.Name)
return err
} else {
// If the HPA exists, check if it needs to be updated
if needsHpaUpdate(foundHpa, f) {
log.Info("Updating HPA", "Namespace", foundHpa.Namespace, "Name", foundHpa.Name)
updateHpa(foundHpa, f)
err = r.Update(ctx, foundHpa)
if err != nil {
// Handle update error
log.Error(err, "Failed to update HPA", "Namespace", foundHpa.Namespace, "Name", foundHpa.Name)
r.Recorder.Eventf(f, corev1.EventTypeWarning, "UpdateFailed", "Failed to update HPA %s", foundHpa.Name)
return err
}
Expand Down
Loading

0 comments on commit 4e4038f

Please sign in to comment.