Skip to content

Commit 47ad908

Browse files
committed
storageclusterpeer: implement logic for storageclusterpeer
Signed-off-by: Rewant Soni <[email protected]>
1 parent a9ab5a8 commit 47ad908

File tree

2 files changed

+158
-17
lines changed

2 files changed

+158
-17
lines changed

controllers/storagecluster/reconcile.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,17 @@ func (r *StorageClusterReconciler) reconcilePhases(
371371
// The object is marked for deletion
372372
instance.Status.Phase = statusutil.PhaseDeleting
373373

374+
storageClusterPeerList := ocsv1.StorageClusterList{}
375+
err := r.List(ctx, &storageClusterPeerList, client.InNamespace(instance.Namespace))
376+
if err != nil {
377+
return reconcile.Result{}, err
378+
}
379+
if len(storageClusterPeerList.Items) != 0 {
380+
err := fmt.Errorf("waiting for %v StorageClusterPeer attached to StorageCluster to be deleted before proceeding", len(storageClusterPeerList.Items))
381+
r.Log.Info(err.Error())
382+
return reconcile.Result{}, err
383+
}
384+
374385
if contains(instance.GetFinalizers(), storageClusterFinalizer) {
375386
if res, err := r.deleteResources(instance); err != nil {
376387
r.Log.Info("Uninstall in progress.", "Status", err)

controllers/storageclusterpeer/storageclusterpeer_controller.go

Lines changed: 147 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,176 @@ package storageclusterpeer
1818

1919
import (
2020
"context"
21+
"fmt"
22+
"time"
2123

24+
ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
25+
providerClient "github.com/red-hat-storage/ocs-operator/services/provider/api/v4/client"
26+
27+
"github.com/go-logr/logr"
28+
"google.golang.org/grpc/status"
29+
"k8s.io/apimachinery/pkg/api/errors"
2230
"k8s.io/apimachinery/pkg/runtime"
2331
ctrl "sigs.k8s.io/controller-runtime"
2432
"sigs.k8s.io/controller-runtime/pkg/client"
33+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2534
"sigs.k8s.io/controller-runtime/pkg/log"
35+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
36+
)
2637

27-
v1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
38+
const (
39+
storageClusterPeerFinalizer = "storageclusterpeer.ocs.openshift.io"
2840
)
2941

3042
// StorageClusterPeerReconciler reconciles a StorageClusterPeer object
3143
// nolint:revive
3244
type StorageClusterPeerReconciler struct {
3345
client.Client
3446
Scheme *runtime.Scheme
47+
48+
log logr.Logger
49+
ctx context.Context
50+
storageClusterPeer *ocsv1.StorageClusterPeer
51+
storageCluster *ocsv1.StorageCluster
52+
}
53+
54+
// SetupWithManager sets up the controller with the Manager.
55+
func (r *StorageClusterPeerReconciler) SetupWithManager(mgr ctrl.Manager) error {
56+
return ctrl.NewControllerManagedBy(mgr).
57+
For(&ocsv1.StorageClusterPeer{}).
58+
Complete(r)
3559
}
3660

3761
//+kubebuilder:rbac:groups=ocs.openshift.io,resources=storageclusterpeers,verbs=get;list;watch;create;update;patch;delete
3862
//+kubebuilder:rbac:groups=ocs.openshift.io,resources=storageclusterpeers/status,verbs=get;update;patch
3963
//+kubebuilder:rbac:groups=ocs.openshift.io,resources=storageclusterpeers/finalizers,verbs=update
64+
//+kubebuilder:rbac:groups=ocs.openshift.io,resources=storageclusters,verbs=get;list;watch
4065

4166
// Reconcile is part of the main kubernetes reconciliation loop which aims to
4267
// move the current state of the cluster closer to the desired state.
43-
// TODO(user): Modify the Reconcile function to compare the state specified by
44-
// the StorageClusterPeer object against the actual cluster state, and then
45-
// perform operations to make the cluster state reflect the state specified by
46-
// the user.
47-
//
48-
// For more details, check Reconcile and its Result here:
49-
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
50-
func (r *StorageClusterPeerReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) {
51-
_ = log.FromContext(ctx)
52-
53-
// TODO(user): your logic here
68+
func (r *StorageClusterPeerReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
69+
var err error
70+
r.ctx = ctx
71+
r.log = log.FromContext(ctx, "StorageClient", request)
72+
r.log.Info("Reconciling StorageClusterPeer.")
73+
74+
// Fetch StorageCluster(s)
75+
storageClusterList := &ocsv1.StorageClusterList{}
76+
err = r.list(storageClusterList, client.InNamespace(request.Namespace))
77+
if err != nil {
78+
r.log.Error(err, "StorageCluster for StorageClusterPeer found in the same namespace.")
79+
return ctrl.Result{}, err
80+
}
81+
82+
if len(storageClusterList.Items) != 1 {
83+
err := fmt.Errorf("invalid number of StorageCluster found")
84+
r.log.Error(err, "invalid number of StorageCluster(s) found, expected 1, found %v", len(storageClusterList.Items))
85+
return ctrl.Result{}, err
86+
}
87+
88+
r.storageCluster = &storageClusterList.Items[0]
89+
90+
// Fetch the StorageClusterPeer instance
91+
r.storageClusterPeer = &ocsv1.StorageClusterPeer{}
92+
r.storageClusterPeer.Name = request.Name
93+
r.storageClusterPeer.Namespace = request.Namespace
94+
95+
if err = r.get(r.storageClusterPeer); err != nil {
96+
if errors.IsNotFound(err) {
97+
r.log.Info("StorageClusterPeer resource not found. Ignoring since object must be deleted.")
98+
return reconcile.Result{}, nil
99+
}
100+
r.log.Error(err, "Failed to get StorageClusterPeer.")
101+
return reconcile.Result{}, err
102+
}
103+
104+
result, reconcileErr := r.reconcilePhases()
105+
106+
// Apply status changes to the StorageClient
107+
statusErr := r.Client.Status().Update(ctx, r.storageClusterPeer)
108+
if statusErr != nil {
109+
r.log.Error(statusErr, "Failed to update StorageClusterPeer status.")
110+
}
111+
112+
if reconcileErr != nil {
113+
err = reconcileErr
114+
} else if statusErr != nil {
115+
err = statusErr
116+
}
117+
118+
return result, err
119+
}
120+
121+
func (r *StorageClusterPeerReconciler) reconcilePhases() (ctrl.Result, error) {
122+
ocsClient, err := r.newExternalClusterClient()
123+
if err != nil {
124+
return reconcile.Result{}, err
125+
}
126+
defer ocsClient.Close()
127+
128+
// marked for deletion
129+
if !r.storageClusterPeer.GetDeletionTimestamp().IsZero() {
130+
//TODO: Removing PeerOCS Call
131+
132+
if controllerutil.RemoveFinalizer(r.storageClusterPeer, storageClusterPeerFinalizer) {
133+
r.log.Info("removing finalizer from StorageClusterPeer.", "StorageClusterPeer", r.storageClusterPeer.Name)
134+
if err := r.update(r.storageClusterPeer); err != nil {
135+
r.log.Info("Failed to remove finalizer from StorageClusterPeer", "StorageClusterPeer", r.storageClusterPeer.Name)
136+
return reconcile.Result{}, fmt.Errorf("failed to remove finalizer from StorageClient: %v", err)
137+
}
138+
}
139+
}
140+
141+
if controllerutil.AddFinalizer(r.storageClusterPeer, storageClusterPeerFinalizer) {
142+
r.log.Info("Finalizer not found for StorageClusterPeer. Adding finalizer.", "StorageClusterPeer", r.storageClusterPeer.Name)
143+
if err := r.update(r.storageClusterPeer); err != nil {
144+
return reconcile.Result{}, fmt.Errorf("failed to update StorageClusterPeer: %v", err)
145+
}
146+
}
147+
148+
if r.storageClusterPeer.Status.State != ocsv1.StorageClusterPeerRemoteStatePeered {
149+
return r.peerOCS(ocsClient)
150+
}
54151

55152
return ctrl.Result{}, nil
56153
}
57154

58-
// SetupWithManager sets up the controller with the Manager.
59-
func (r *StorageClusterPeerReconciler) SetupWithManager(mgr ctrl.Manager) error {
60-
return ctrl.NewControllerManagedBy(mgr).
61-
For(&v1.StorageClusterPeer{}).
62-
Complete(r)
155+
func (r *StorageClusterPeerReconciler) newExternalClusterClient() (*providerClient.OCSProviderClient, error) {
156+
157+
ocsProviderClient, err := providerClient.NewProviderClient(
158+
r.ctx, r.storageClusterPeer.Spec.ApiEndpoint, time.Second*10)
159+
if err != nil {
160+
return nil, fmt.Errorf("failed to create a new provider client: %v", err)
161+
}
162+
163+
return ocsProviderClient, nil
164+
}
165+
166+
func (r *StorageClusterPeerReconciler) peerOCS(ocsClient *providerClient.OCSProviderClient) (ctrl.Result, error) {
167+
r.storageClusterPeer.Status.State = ocsv1.StorageClusterPeerRemoteStatePeering
168+
response, err := ocsClient.PeerStorageCluster(r.ctx, r.storageClusterPeer.Spec.OnboardingToken, string(r.storageCluster.UID))
169+
if err != nil {
170+
r.log.Error(err, fmt.Sprintf("failed to Peer Storage Cluster, code: %v.", status.Code(err)))
171+
return ctrl.Result{}, err
172+
}
173+
if r.storageClusterPeer.Status.RemoteStorageClusterUID != response.StorageClusterUID {
174+
err := fmt.Errorf("falied to validate remote Storage Cluster UID against PeerOCS Response")
175+
r.log.Error(err, "failed to Peer Storage Cluster")
176+
return ctrl.Result{}, err
177+
}
178+
r.storageClusterPeer.Status.State = ocsv1.StorageClusterPeerRemoteStatePeered
179+
return ctrl.Result{}, nil
180+
}
181+
182+
func (r *StorageClusterPeerReconciler) get(obj client.Object) error {
183+
key := client.ObjectKeyFromObject(obj)
184+
return r.Client.Get(r.ctx, key, obj)
185+
}
186+
187+
func (r *StorageClusterPeerReconciler) list(obj client.ObjectList, listOptions ...client.ListOption) error {
188+
return r.Client.List(r.ctx, obj, listOptions...)
189+
}
190+
191+
func (r *StorageClusterPeerReconciler) update(obj client.Object, opts ...client.UpdateOption) error {
192+
return r.Client.Update(r.ctx, obj, opts...)
63193
}

0 commit comments

Comments
 (0)