...

Source file src/github.com/chaos-mesh/chaos-mesh/controllers/multicluster/remotechaosmonitor/controller.go

Documentation: github.com/chaos-mesh/chaos-mesh/controllers/multicluster/remotechaosmonitor

     1  // Copyright 2022 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package remotechaosmonitor
    17  
    18  import (
    19  	"context"
    20  	"reflect"
    21  
    22  	"github.com/go-logr/logr"
    23  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    24  	"k8s.io/client-go/util/retry"
    25  	ctrl "sigs.k8s.io/controller-runtime"
    26  	"sigs.k8s.io/controller-runtime/pkg/client"
    27  
    28  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    29  )
    30  
    31  type Reconciler struct {
    32  	clusterName string
    33  
    34  	obj v1alpha1.InnerObject
    35  
    36  	logger       logr.Logger
    37  	localClient  client.Client
    38  	remoteClient client.Client
    39  }
    40  
    41  func New(obj v1alpha1.InnerObject, manageClient client.Client, clusterName string, localClient client.Client, logger logr.Logger) *Reconciler {
    42  	return &Reconciler{
    43  		clusterName:  clusterName,
    44  		obj:          obj,
    45  		logger:       logger.WithName("remotechaos-monitor"),
    46  		localClient:  manageClient,
    47  		remoteClient: localClient,
    48  	}
    49  }
    50  
    51  func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    52  	r.logger.Info("reconcile chaos", "clusterName", r.clusterName, "namespace", req.Namespace, "name", req.Name)
    53  
    54  	shouldDelete := false
    55  	remoteObj := r.obj.DeepCopyObject().(v1alpha1.RemoteObject)
    56  	err := r.remoteClient.Get(ctx, req.NamespacedName, remoteObj)
    57  	if err != nil {
    58  		if apierrors.IsNotFound(err) {
    59  			r.logger.Info("chaos not found")
    60  
    61  			shouldDelete = true
    62  		} else {
    63  			// TODO: handle this error
    64  			r.logger.Error(err, "unable to get remote chaos")
    65  			return ctrl.Result{}, nil
    66  		}
    67  	}
    68  
    69  	localObj := r.obj.DeepCopyObject().(v1alpha1.RemoteObject)
    70  	err = r.localClient.Get(ctx, req.NamespacedName, localObj)
    71  	if err != nil {
    72  		if apierrors.IsNotFound(err) {
    73  			r.logger.Info("local chaos not found")
    74  
    75  			err = r.remoteClient.Delete(ctx, remoteObj)
    76  			if err != nil {
    77  				if apierrors.IsNotFound(err) {
    78  					r.logger.Info("remote chaos deleted")
    79  				} else {
    80  					// TODO: retry for some error
    81  					r.logger.Error(err, "unable to get remote chaos")
    82  				}
    83  			}
    84  
    85  			return ctrl.Result{}, nil
    86  		}
    87  
    88  		// TODO: handle this error
    89  		r.logger.Error(err, "unable to get local chaos")
    90  		return ctrl.Result{}, nil
    91  	}
    92  
    93  	if shouldDelete {
    94  		r.logger.Info("deleting local obj", "namespace", localObj.GetNamespace(), "name", localObj.GetName())
    95  		localObj.SetFinalizers([]string{})
    96  		err := r.localClient.Update(ctx, localObj)
    97  		if err != nil {
    98  			// TODO: retry
    99  			r.logger.Error(err, "fail to update localObj")
   100  			// it's expected to not return, as we could still try
   101  			// to remove this object
   102  		}
   103  
   104  		err = r.localClient.Delete(ctx, localObj)
   105  		if err != nil {
   106  			// TODO: retry
   107  			r.logger.Error(err, "fail to delete local object")
   108  		}
   109  
   110  		return ctrl.Result{}, nil
   111  	}
   112  
   113  	shouldUpdate := false
   114  	if !reflect.DeepEqual(localObj.GetFinalizers(), remoteObj.GetFinalizers()) {
   115  		r.logger.Info("setting new finalizers")
   116  		localObj.SetFinalizers(remoteObj.GetFinalizers())
   117  
   118  		shouldUpdate = true
   119  	}
   120  
   121  	// TODO: set the status
   122  	if !reflect.DeepEqual(localObj.GetStatus(), remoteObj.GetStatus()) {
   123  		r.logger.Info("setting new status", "local:", localObj.GetStatus(), "remote:", remoteObj.GetStatus())
   124  		shouldUpdate = true
   125  	}
   126  
   127  	if shouldUpdate {
   128  		retry.RetryOnConflict(retry.DefaultRetry, func() error {
   129  			localObj := r.obj.DeepCopyObject().(v1alpha1.RemoteObject)
   130  			err = r.localClient.Get(ctx, req.NamespacedName, localObj)
   131  			if err != nil {
   132  				return err
   133  			}
   134  
   135  			// TODO: also refresh the remote chaos object
   136  			localObj.SetFinalizers(remoteObj.GetFinalizers())
   137  			remoteObj.GetStatus().DeepCopyInto(localObj.GetStatus())
   138  			return r.localClient.Update(ctx, localObj)
   139  		})
   140  	}
   141  	return ctrl.Result{}, nil
   142  }
   143