Skip to content

Commit

Permalink
Implement Provider and Secret sync controllers
Browse files Browse the repository at this point in the history
Signed-off-by: Danil Grigorev <danil.grigorev@suse.com>
  • Loading branch information
Danil-Grigorev committed Dec 12, 2023
1 parent 1a8c005 commit 2f6d1d5
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 3 deletions.
7 changes: 4 additions & 3 deletions internal/controllers/capiprovider_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ import (

operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"

operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"

turtlesv1 "github.com/rancher-sandbox/rancher-turtles/api/v1alpha1"
"github.com/rancher-sandbox/rancher-turtles/internal/sync"
)
Expand Down Expand Up @@ -71,7 +69,10 @@ func (r *CAPIProviderReconciler) reconcileNormal(ctx context.Context, capiProvid
}

func (r *CAPIProviderReconciler) sync(ctx context.Context, capiProvider *turtlesv1.CAPIProvider) (_ ctrl.Result, err error) {
s := sync.List{}
s := sync.List{
sync.NewProviderSync(r.Client, capiProvider),
sync.NewSecretSync(r.Client, capiProvider),
}

if err := s.Sync(ctx); client.IgnoreNotFound(err) != nil {
return ctrl.Result{}, err
Expand Down
97 changes: 97 additions & 0 deletions internal/sync/provider_sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package sync

import (
"context"

"sigs.k8s.io/cluster-api/util/conditions"
"sigs.k8s.io/controller-runtime/pkg/client"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"

turtlesv1 "github.com/rancher-sandbox/rancher-turtles/api/v1alpha1"
)

// ProviderSync is a structure mirroring state of the CAPI Operator Provider object.
type ProviderSync struct {
*DefaultSynchronizer
}

// NewProviderSync creates a new mirror object.
func NewProviderSync(cl client.Client, capiProvider *turtlesv1.CAPIProvider) Sync {
return &ProviderSync{
DefaultSynchronizer: NewDefaultSynchronizer(cl, capiProvider, ProviderSync{}.Template(capiProvider)),
}
}

// Template returning the mirrored CAPI Operator manifest template.
func (ProviderSync) Template(capiProvider *turtlesv1.CAPIProvider) client.Object {
meta := metav1.ObjectMeta{
Name: string(capiProvider.Spec.Name),
Namespace: capiProvider.GetNamespace(),
}

switch capiProvider.Spec.Type {
case turtlesv1.Infrastructure:
return &operatorv1.InfrastructureProvider{ObjectMeta: meta}
case turtlesv1.Core:
return &operatorv1.CoreProvider{ObjectMeta: meta}
case turtlesv1.ControlPlane:
return &operatorv1.ControlPlaneProvider{ObjectMeta: meta}
case turtlesv1.Bootstrap:
return &operatorv1.BootstrapProvider{ObjectMeta: meta}
case turtlesv1.Addon:
return &operatorv1.AddonProvider{ObjectMeta: meta}
default:
}

return nil
}

// Sync updates the mirror object state from the upstream source object
// Direction of updates:
// Spec -> down
// up <- Status.
func (s *ProviderSync) Sync(_ context.Context) error {
s.SyncObjects()

return nil
}

// SyncObjects updates the Source CAPIProvider object and the destination provider object states.
// Direction of updates:
// Spec -> <Common>Provider
// CAPIProvider <- Status.
func (s *ProviderSync) SyncObjects() {
switch mirror := s.Destination.(type) {
case *operatorv1.InfrastructureProvider:
s.Source.Spec.ProviderSpec.DeepCopyInto(&mirror.Spec.ProviderSpec)
mirror.Status.ProviderStatus.DeepCopyInto(&s.Source.Status.ProviderStatus)
case *operatorv1.CoreProvider:
s.Source.Spec.ProviderSpec.DeepCopyInto(&mirror.Spec.ProviderSpec)
mirror.Status.ProviderStatus.DeepCopyInto(&s.Source.Status.ProviderStatus)
case *operatorv1.ControlPlaneProvider:
s.Source.Spec.ProviderSpec.DeepCopyInto(&mirror.Spec.ProviderSpec)
mirror.Status.ProviderStatus.DeepCopyInto(&s.Source.Status.ProviderStatus)
case *operatorv1.BootstrapProvider:
s.Source.Spec.ProviderSpec.DeepCopyInto(&mirror.Spec.ProviderSpec)
mirror.Status.ProviderStatus.DeepCopyInto(&s.Source.Status.ProviderStatus)
case *operatorv1.AddonProvider:
s.Source.Spec.ProviderSpec.DeepCopyInto(&mirror.Spec.ProviderSpec)
mirror.Status.ProviderStatus.DeepCopyInto(&s.Source.Status.ProviderStatus)
default:
}

s.syncStatus()
}

func (s *ProviderSync) syncStatus() {
switch {
case conditions.IsTrue(s.Source, operatorv1.ProviderInstalledCondition):
s.Source.Status.Phase = turtlesv1.Ready
case conditions.IsFalse(s.Source, operatorv1.PreflightCheckCondition):
s.Source.Status.Phase = turtlesv1.Failed
default:
s.Source.Status.Phase = turtlesv1.Provisioning
}
}
91 changes: 91 additions & 0 deletions internal/sync/secret_sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package sync

import (
"context"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

turtlesv1 "github.com/rancher-sandbox/rancher-turtles/api/v1alpha1"
)

// SecretSync is a structure mirroring variable secret state of the CAPI Operator Provider object.
type SecretSync struct {
*DefaultSynchronizer

Secret *corev1.Secret
}

// NewSecretSync creates a new secret object sync.
func NewSecretSync(cl client.Client, capiProvider *turtlesv1.CAPIProvider) Sync {
secret := SecretSync{}.GetSecret(capiProvider)

return &SecretSync{
DefaultSynchronizer: NewDefaultSynchronizer(cl, capiProvider, secret),
Secret: secret,
}
}

// GetSecret returning the mirrored secret resource template.
func (SecretSync) GetSecret(capiProvider *turtlesv1.CAPIProvider) *corev1.Secret {
meta := metav1.ObjectMeta{
Name: capiProvider.Name,
Namespace: capiProvider.Namespace,
}

if capiProvider.Spec.ConfigSecret != nil {
meta.Name = capiProvider.Spec.ConfigSecret.Name
}

return &corev1.Secret{ObjectMeta: meta}
}

// Template returning the mirrored secret resource template.
func (SecretSync) Template(capiProvider *turtlesv1.CAPIProvider) client.Object {
return SecretSync{}.GetSecret(capiProvider)
}

// Sync updates the mirror object state from the upstream source object
// Direction of updates:
// Spec -> down
// up <- Status.
func (s *SecretSync) Sync(_ context.Context) error {
s.SyncObjects()

return nil
}

// SyncObjects updates the Source CAPIProvider object and the environment secret state.
// Direction of updates:
// Spec.Features + Spec.Variables -> Status.Variables -> Secret.
func (s *SecretSync) SyncObjects() {
setVariables(s.DefaultSynchronizer.Source)
setFeatures(s.DefaultSynchronizer.Source)

s.Secret.StringData = s.DefaultSynchronizer.Source.Status.Variables
}

func setVariables(capiProvider *turtlesv1.CAPIProvider) {
if capiProvider.Spec.Variables != nil {
capiProvider.Status.Variables = capiProvider.Spec.Variables
}
}

func setFeatures(capiProvider *turtlesv1.CAPIProvider) {
value := "true"
features := capiProvider.Spec.Features
variables := capiProvider.Status.Variables

if features != nil {
if features.ClusterResourceSet {
variables["EXP_CLUSTER_RESOURCE_SET"] = value
}
if features.ClusterTopology {
variables["CLUSTER_TOPOLOGY"] = value
}
if features.MachinePool {
variables["EXP_MACHINE_POOL"] = value
}
}
}

0 comments on commit 2f6d1d5

Please sign in to comment.