blob: c8853a93ebe91a26f9c0a4b3d4edfedcb6b0113a [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"
"k8s.io/apimachinery/pkg/runtime"
"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/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"
)
// SolrCollectionReconciler reconciles a SolrCollection object
type SolrCollectionReconciler struct {
client.Client
scheme *runtime.Scheme
Log logr.Logger
}
// +kubebuilder:rbac:groups=solr.bloomberg.com,resources=solrcollections,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=solr.bloomberg.com,resources=solrcollections/status,verbs=get;update;patch
func (r *SolrCollectionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
_ = context.Background()
_ = r.Log.WithValues("solrcollection", req.NamespacedName)
// Fetch the SolrCollection collection
collection := &solrv1beta1.SolrCollection{}
collectionFinalizer := "collection.finalizers.bloomberg.com"
err := r.Get(context.TODO(), req.NamespacedName, collection)
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 := collection.Status.DeepCopy()
requeueOrNot := reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}
solrCloud, collectionCreationStatus, err := reconcileSolrCollection(r, collection, collection.Spec.NumShards, collection.Spec.ReplicationFactor, collection.Spec.AutoAddReplicas, collection.Spec.MaxShardsPerNode, collection.Spec.RouterName, collection.Spec.RouterField, collection.Spec.Shards, collection.Spec.CollectionConfigName, collection.Namespace)
if err != nil {
r.Log.Error(err, "Error while creating SolrCloud collection")
return reconcile.Result{}, err
}
if collection.Status.CreatedTime == nil {
now := metav1.Now()
collection.Status.CreatedTime = &now
}
if solrCloud != nil && collectionCreationStatus == false {
r.Log.Info("Collections update failed")
}
if collection.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(collection.ObjectMeta.Finalizers, collectionFinalizer) {
collection.ObjectMeta.Finalizers = append(collection.ObjectMeta.Finalizers, collectionFinalizer)
if err := r.Update(context.Background(), collection); err != nil {
return reconcile.Result{}, err
}
}
} else {
// The object is being deleted
if util.ContainsString(collection.ObjectMeta.Finalizers, collectionFinalizer) {
r.Log.Info("Deleting Solr collection", "cloud", collection.Spec.SolrCloud, "namespace", collection.Namespace, "Collection Name", collection.Name)
// our finalizer is present, so lets handle our external dependency
delete, err := util.DeleteCollection(collection.Spec.SolrCloud, collection.Name, collection.Namespace)
if err != nil {
r.Log.Error(err, "Failed to delete Solr collection")
return reconcile.Result{}, err
}
r.Log.Info("Deleted Solr collection", "cloud", collection.Spec.SolrCloud, "namespace", collection.Namespace, "Collection Name", collection.Name, "Deleted", delete)
}
// remove our finalizer from the list and update it.
collection.ObjectMeta.Finalizers = util.RemoveString(collection.ObjectMeta.Finalizers, collectionFinalizer)
if err := r.Update(context.Background(), collection); err != nil {
return reconcile.Result{}, err
}
}
if !reflect.DeepEqual(oldStatus, collection.Status) {
r.Log.Info("Updating status for solr-collection", "collection", collection, "namespace", collection.Namespace, "name", collection.Name)
err = r.Status().Update(context.TODO(), collection)
}
if collection.Status.InProgressCreation {
if util.CheckIfCollectionExists(collection.Spec.SolrCloud, collection.Spec.Collection, collection.Namespace) {
r.Log.Info("Collection exists, creation complete", "collection", collection, "namespace", collection.Namespace, "name", collection.Name)
collection.Status.InProgressCreation = false
requeueOrNot = reconcile.Result{}
} else {
r.Log.Info("Collection creation still in progress", "collection", collection, "namespace", collection.Namespace, "name", collection.Name)
requeueOrNot = reconcile.Result{Requeue: true}
}
}
if collection.Status.Created {
requeueOrNot = reconcile.Result{}
}
return requeueOrNot, nil
}
func reconcileSolrCollection(r *SolrCollectionReconciler, collection *solrv1beta1.SolrCollection, numShards int64, replicationFactor int64, autoAddReplicas bool, maxShardsPerNode int64, routerName solrv1beta1.CollectionRouterName, routerField string, shards string, collectionConfigName string, namespace string) (solrCloud *solrv1beta1.SolrCloud, collectionCreationStatus bool, err error) {
// Get the solrCloud that this collection is for.
solrCloud = &solrv1beta1.SolrCloud{}
if err = r.Get(context.TODO(), types.NamespacedName{Namespace: collection.Namespace, Name: collection.Spec.SolrCloud}, solrCloud); err != nil {
return nil, false, err
}
// If the collection has already been created already and requires modification
if collection.Status.Created {
modificationRequired, err := util.CheckIfCollectionModificationRequired(solrCloud.Name, collection.Name, replicationFactor, autoAddReplicas, maxShardsPerNode, collectionConfigName, namespace)
if err != nil {
return nil, false, err
}
if modificationRequired {
modify, err := util.ModifyCollection(solrCloud.Name, collection.Name, replicationFactor, autoAddReplicas, maxShardsPerNode, collectionConfigName, namespace)
if err != nil {
return nil, false, err
}
r.Log.Info("Modified Solr collection", "SolrCloud", collection.Spec.SolrCloud, "namespace", collection.Namespace, "Collection Name", collection.Name, "Modified", modify)
} else {
r.Log.Info("Modification on Solr collection not required", "SolrCloud", collection.Spec.SolrCloud, "namespace", collection.Namespace, "Collection Name", collection.Name, "Modified", nil)
}
}
// If the collection collection hasn't been created or is in progress, start it creation
if !collection.Status.Created && !collection.Status.InProgressCreation {
// Request the creation of collection by calling solr
collection.Status.InProgressCreation = true
create, err := util.CreateCollection(solrCloud.Name, collection.Name, numShards, replicationFactor, autoAddReplicas, maxShardsPerNode, routerName, routerField, shards, collectionConfigName, namespace)
if err != nil {
collection.Status.InProgressCreation = false
return nil, false, err
}
collection.Status.Created = create
collection.Status.InProgressCreation = false
}
err = r.Get(context.TODO(), types.NamespacedName{Namespace: collection.Namespace, Name: collection.Spec.SolrCloud}, solrCloud)
return solrCloud, collection.Status.Created, err
}
func (r *SolrCollectionReconciler) SetupWithManager(mgr ctrl.Manager) error {
return r.SetupWithManagerAndReconciler(mgr, r)
}
func (r *SolrCollectionReconciler) SetupWithManagerAndReconciler(mgr ctrl.Manager, reconciler reconcile.Reconciler) error {
ctrlBuilder := ctrl.NewControllerManagedBy(mgr).
For(&solrv1beta1.SolrCollection{})
r.scheme = mgr.GetScheme()
return ctrlBuilder.Complete(reconciler)
}