blob: 73913100d839aa7e87eaa33c615ad9cde47c1d5f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package controllers
import (
"context"
"reflect"
"time"
"github.com/apache/lucene-solr-operator/controllers/util"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
solrv1beta1 "github.com/apache/lucene-solr-operator/api/v1beta1"
)
// SolrCollectionAliasReconciler reconciles a SolrCollectionAlias object
type SolrCollectionAliasReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
}
// +kubebuilder:rbac:groups=solr.apache.org,resources=solrcollectionaliases,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=solr.apache.org,resources=solrcollectionaliases/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=solr.apache.org,resources=solrcloud,verbs=get;list;watch
// +kubebuilder:rbac:groups=solr.apache.org,resources=solrcloud/status,verbs=get
func (r *SolrCollectionAliasReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
_ = context.Background()
_ = r.Log.WithValues("solrcollectionalias", req.NamespacedName)
alias := &solrv1beta1.SolrCollectionAlias{}
aliasFinalizer := "alias.finalizers.bloomberg.com"
err := r.Get(context.TODO(), req.NamespacedName, alias)
if err != nil {
if errors.IsNotFound(err) {
// Object not found, return. Created objects are automatically garbage collected.
// For additional cleanup logic use finalizers.
return reconcile.Result{}, nil
}
// Error reading the object - requeue the req.
return reconcile.Result{}, err
}
oldStatus := alias.Status.DeepCopy()
requeueOrNot := reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}
solrCloud := &solrv1beta1.SolrCloud{}
err = r.Get(context.TODO(), types.NamespacedName{Namespace: alias.Namespace, Name: alias.Spec.SolrCloud}, solrCloud)
if err != nil {
return reconcile.Result{}, err
}
aliasCreationStatus := reconcileSolrCollectionAlias(r, alias, solrCloud, alias.Name, alias.Spec.AliasType, alias.Spec.Collections)
if err != nil {
r.Log.Error(err, "Error while creating SolrCloud alias")
}
if alias.ObjectMeta.DeletionTimestamp.IsZero() {
// The object is not being deleted, so if it does not have our finalizer,
// then lets add the finalizer and update the object
if !util.ContainsString(alias.ObjectMeta.Finalizers, aliasFinalizer) {
alias.ObjectMeta.Finalizers = append(alias.ObjectMeta.Finalizers, aliasFinalizer)
if err := r.Update(context.Background(), alias); err != nil {
return reconcile.Result{}, err
}
}
} else {
if util.ContainsString(alias.ObjectMeta.Finalizers, aliasFinalizer) && aliasCreationStatus {
r.Log.Info("Deleting Solr collection alias", "cloud", alias.Spec.SolrCloud, "namespace", alias.Namespace, "Collection Name", alias.Name)
// our finalizer is present, along with the associated SolrCloud and alias lets delete alias
delete, err := util.DeleteCollectionAlias(solrCloud, alias.Name)
if err != nil {
r.Log.Error(err, "Failed to delete Solr collection")
return reconcile.Result{}, err
}
r.Log.Info("Deleted Solr collection", "cloud", alias.Spec.SolrCloud, "namespace", alias.Namespace, "Alias", alias.Name, "Deleted", delete)
}
// remove our finalizer from the list and update it.
alias.ObjectMeta.Finalizers = util.RemoveString(alias.ObjectMeta.Finalizers, aliasFinalizer)
if err := r.Update(context.Background(), alias); err != nil {
return reconcile.Result{}, err
}
}
if alias.Status.CreatedTime == nil {
now := metav1.Now()
alias.Status.CreatedTime = &now
alias.Status.Created = aliasCreationStatus
}
if !reflect.DeepEqual(oldStatus, alias.Status) {
r.Log.Info("Updating status for collection alias", "alias", alias, "namespace", alias.Namespace, "name", alias.Name)
err = r.Status().Update(context.TODO(), alias)
}
if aliasCreationStatus {
requeueOrNot = reconcile.Result{}
}
return requeueOrNot, nil
}
func reconcileSolrCollectionAlias(r *SolrCollectionAliasReconciler, alias *solrv1beta1.SolrCollectionAlias, cloud *solrv1beta1.SolrCloud, aliasName string, aliasType string, collections []string) (aliasCreationStatus bool) {
success, aliasCollections := util.CurrentCollectionAliasDetails(cloud, aliasName)
// If not created, or if alias status differs from spec requirements create alias
if !success || !reflect.DeepEqual(alias.Status.Collections, aliasCollections) {
r.Log.Info("Applying collection alias", "alias", alias)
err := util.CreateCollectionAlias(cloud, aliasName, aliasType, collections)
if err == nil {
alias.Status.Created = true
alias.Status.Collections = collections
return alias.Status.Created
}
}
return alias.Status.Created
}
func (r *SolrCollectionAliasReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&solrv1beta1.SolrCollectionAlias{}).
Complete(r)
}