blob: 037ac7b41441eb8da4f0a4b54f08931ba3bd22bf [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 util
import (
solr "github.com/apache/solr-operator/api/v1beta1"
policyv1 "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
func GeneratePodDisruptionBudget(cloud *solr.SolrCloud, selector map[string]string) *policyv1.PodDisruptionBudget {
// For this PDB, we can use an intOrString maxUnavailable (whatever the user provides),
// because we are matching the labelSelector used by the statefulSet.
var maxUnavailable intstr.IntOrString
if cloud.Spec.UpdateStrategy.ManagedUpdateOptions.MaxPodsUnavailable != nil {
maxUnavailable = *cloud.Spec.UpdateStrategy.ManagedUpdateOptions.MaxPodsUnavailable
} else {
maxUnavailable = intstr.FromString(DefaultMaxPodsUnavailable)
}
return &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: cloud.StatefulSetName(),
Namespace: cloud.Namespace,
},
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: selector,
},
MaxUnavailable: &maxUnavailable,
},
}
}
/*
*
We cannot actually use the shard topology for PDBs, because Kubernetes does not currently support a pod
mapping to multiple PDBs. Since a Solr pod is sure to host replicas of multiple shards, then we would
have to create multiple PDBs that cover a single pod. Therefore we can only use the Cloud PDB defined in the method
above.
Whenever we can use this, when generating PDBs, we need to label them so that a list of all PDBs for a cloud can be found easily.
That way, when we have the list of PDBs to create/update, we will aslo know the list of PDBs that need to be deleted.
Kubernetes Documentation: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#arbitrary-controllers-and-selectors
*/
func createPodDisruptionBudgetForShard(cloud *solr.SolrCloud, collection string, shard string, nodes []string) policyv1.PodDisruptionBudget {
maxUnavailable, err := intstr.GetScaledValueFromIntOrPercent(
intstr.ValueOrDefault(cloud.Spec.UpdateStrategy.ManagedUpdateOptions.MaxShardReplicasUnavailable, intstr.FromInt(DefaultMaxShardReplicasUnavailable)),
len(nodes),
false)
if err != nil {
maxUnavailable = 1
}
// From the documentation above, Kubernetes will only accept an int minAvailable for PDBs that use custom pod selectors.
// Therefore, we cannot use the maxUnavailable straight from what the user provides.
minAvailable := intstr.FromInt(len(nodes) - maxUnavailable)
return policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: cloud.Name + "-" + collection + "-" + shard,
Namespace: cloud.Namespace,
},
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "statefulset.kubernetes.io/pod-name",
Operator: "In",
Values: nodes,
},
},
},
MinAvailable: &minAvailable,
},
}
}