in operator/pkg/controller/istiocontrolplane/istiocontrolplane_controller.go [222:386]
func (r *ReconcileIstioOperator) Reconcile(_ context.Context, request reconcile.Request) (reconcile.Result, error) {
scope.Info("Reconciling IstioOperator")
ns, iopName := request.Namespace, request.Name
reqNamespacedName := types.NamespacedName{
Name: request.Name,
Namespace: ns,
}
// declare read-only iop instance to create the reconciler
iop := &iopv1alpha1.IstioOperator{}
if err := r.client.Get(context.TODO(), reqNamespacedName, iop); err != nil {
if errors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
metrics.CRDeletionTotal.Increment()
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
scope.Warnf(errdict.OperatorFailedToGetObjectFromAPIServer, "error getting IstioOperator %s: %s", iopName, err)
metrics.CountCRFetchFail(errors.ReasonForError(err))
return reconcile.Result{}, err
}
if iop.Spec == nil {
iop.Spec = &v1alpha1.IstioOperatorSpec{Profile: name.DefaultProfileName}
}
operatorRevision, _ := os.LookupEnv("REVISION")
if operatorRevision != "" && operatorRevision != iop.Spec.Revision {
scope.Infof("Ignoring IstioOperator CR %s with revision %s, since operator revision is %s.", iopName, iop.Spec.Revision, operatorRevision)
return reconcile.Result{}, nil
}
if iop.Annotations != nil {
if ir := iop.Annotations[IgnoreReconcileAnnotation]; ir == "true" {
scope.Infof("Ignoring the IstioOperator CR %s because it is annotated to be ignored for reconcile ", iopName)
return reconcile.Result{}, nil
}
}
// for backward compatibility, the previous applied installed-state CR does not have the ignore reconcile annotation
// TODO(richardwxn): remove this check and rely on annotation check only
if strings.HasPrefix(iop.Name, name.InstalledSpecCRPrefix) {
scope.Infof("Ignoring the installed-state IstioOperator CR %s ", iopName)
return reconcile.Result{}, nil
}
var err error
iopMerged := &iopv1alpha1.IstioOperator{}
*iopMerged = *iop
// get the merged values in iop on top of the defaults for the profile given by iop.profile
iopMerged.Spec, err = mergeIOPSWithProfile(iopMerged)
if err != nil {
scope.Errorf(errdict.OperatorFailedToMergeUserIOP, "failed to merge base profile with user IstioOperator CR %s, %s", iopName, err)
return reconcile.Result{}, err
}
deleted := iop.GetDeletionTimestamp() != nil
finalizers := sets.NewString(iop.GetFinalizers()...)
if deleted {
if !finalizers.Has(finalizer) {
scope.Infof("IstioOperator %s deleted", iopName)
metrics.CRDeletionTotal.Increment()
return reconcile.Result{}, nil
}
scope.Infof("Deleting IstioOperator %s", iopName)
reconciler, err := helmreconciler.NewHelmReconciler(r.client, r.kubeClient, iopMerged, nil)
if err != nil {
return reconcile.Result{}, err
}
if err := reconciler.Delete(); err != nil {
scope.Errorf("Failed to delete resources with helm reconciler: %s.", err)
return reconcile.Result{}, err
}
finalizers.Delete(finalizer)
iop.SetFinalizers(finalizers.List())
finalizerError := r.client.Update(context.TODO(), iop)
for retryCount := 0; errors.IsConflict(finalizerError) && retryCount < finalizerMaxRetries; retryCount++ {
scope.Info("API server conflict during finalizer removal, retrying.")
_ = r.client.Get(context.TODO(), request.NamespacedName, iop)
finalizers = sets.NewString(iop.GetFinalizers()...)
finalizers.Delete(finalizer)
iop.SetFinalizers(finalizers.List())
finalizerError = r.client.Update(context.TODO(), iop)
}
if finalizerError != nil {
if errors.IsNotFound(finalizerError) {
scope.Infof("Did not remove finalizer from %s: the object was previously deleted.", iopName)
metrics.CRDeletionTotal.Increment()
return reconcile.Result{}, nil
} else if errors.IsConflict(finalizerError) {
scope.Infof("Could not remove finalizer from %s due to conflict. Operation will be retried in next reconcile attempt.", iopName)
return reconcile.Result{}, nil
}
scope.Errorf(errdict.OperatorFailedToRemoveFinalizer, "error removing finalizer: %s", finalizerError)
return reconcile.Result{}, finalizerError
}
return reconcile.Result{}, nil
} else if !finalizers.Has(finalizer) {
log.Infof("Adding finalizer %v to %v", finalizer, request)
finalizers.Insert(finalizer)
iop.SetFinalizers(finalizers.List())
err := r.client.Update(context.TODO(), iop)
if err != nil {
if errors.IsNotFound(err) {
scope.Infof("Could not add finalizer to %s: the object was deleted.", iopName)
metrics.CRDeletionTotal.Increment()
return reconcile.Result{}, nil
} else if errors.IsConflict(err) {
scope.Infof("Could not add finalizer to %s due to conflict. Operation will be retried in next reconcile attempt.", iopName)
return reconcile.Result{}, nil
}
scope.Errorf(errdict.OperatorFailedToAddFinalizer, "Failed to add finalizer to IstioOperator CR %s: %s", iopName, err)
return reconcile.Result{}, err
}
}
scope.Info("Updating IstioOperator")
val := iopMerged.Spec.Values.AsMap()
if _, ok := val["global"]; !ok {
val["global"] = make(map[string]interface{})
}
globalValues := val["global"].(map[string]interface{})
scope.Info("Detecting third-party JWT support")
var jwtPolicy util.JWTPolicy
if jwtPolicy, err = util.DetectSupportedJWTPolicy(r.kubeClient); err != nil {
// TODO(howardjohn): add to dictionary. When resolved, replace this sentence with Done or WontFix - if WontFix, add reason.
scope.Warnf("Failed to detect third-party JWT support: %v", err)
} else {
if jwtPolicy == util.FirstPartyJWT {
scope.Info("Detected that your cluster does not support third party JWT authentication. " +
"Falling back to less secure first party JWT. " +
"See " + url.ConfigureSAToken + " for details.")
}
globalValues["jwtPolicy"] = string(jwtPolicy)
}
err = util.ValidateIOPCAConfig(r.kubeClient, iopMerged)
if err != nil {
scope.Errorf(errdict.OperatorFailedToConfigure, "failed to apply IstioOperator resources. Error %s", err)
return reconcile.Result{}, err
}
helmReconcilerOptions := &helmreconciler.Options{
Log: clog.NewDefaultLogger(),
ProgressLog: progress.NewLog(),
}
if r.options != nil {
helmReconcilerOptions.Force = r.options.Force
}
reconciler, err := helmreconciler.NewHelmReconciler(r.client, r.kubeClient, iopMerged, helmReconcilerOptions)
if err != nil {
return reconcile.Result{}, err
}
if err := reconciler.SetStatusBegin(); err != nil {
return reconcile.Result{}, err
}
status, err := reconciler.Reconcile()
if err != nil {
scope.Errorf("Error during reconcile: %s", err)
}
if err := reconciler.SetStatusComplete(status); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{}, err
}