Skip to content

Commit f6b5e87

Browse files
committed
Generate predictable IPs for bind stateful set
Generate and manage predictable IPs for each member of the bind statefulset and store in it's own predictable IPs config map. The reason it needs to be it's own map is that we do not want to cause minidns to restart if a scaling change occurs on mind - nor do we want minidns scale changes to affect bind pods.
1 parent c62d6a9 commit f6b5e87

File tree

3 files changed

+130
-76
lines changed

3 files changed

+130
-76
lines changed

controllers/designate_controller.go

Lines changed: 122 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ func (r *DesignateReconciler) reconcileNormal(ctx context.Context, instance *des
714714
}
715715
Log.Info("Deployment API task reconciled")
716716

717+
// Handle Mdns predictable IPs configmap
717718
nad, err := nad.GetNADWithName(ctx, helper, instance.Spec.DesignateNetworkAttachment, instance.Namespace)
718719
if err != nil {
719720
return ctrl.Result{}, err
@@ -724,31 +725,6 @@ func (r *DesignateReconciler) reconcileNormal(ctx context.Context, instance *des
724725
return ctrl.Result{}, err
725726
}
726727

727-
nodeConfigMap := &corev1.ConfigMap{
728-
ObjectMeta: metav1.ObjectMeta{
729-
Name: designate.MdnsPredIPConfigMap,
730-
Namespace: instance.GetNamespace(),
731-
Labels: labels.GetLabels(instance, labels.GetGroupLabel(instance.ObjectMeta.Name), map[string]string{}),
732-
},
733-
Data: make(map[string]string),
734-
}
735-
736-
// Look for existing config map and if exists, read existing data and match
737-
// against nodes.
738-
foundMap := &corev1.ConfigMap{}
739-
err = helper.GetClient().Get(ctx, types.NamespacedName{Name: designate.MdnsPredIPConfigMap, Namespace: instance.GetNamespace()},
740-
foundMap)
741-
if err != nil {
742-
if k8s_errors.IsNotFound(err) {
743-
Log.Info(fmt.Sprintf("Ip map %s doesn't exist, creating.", designate.MdnsPredIPConfigMap))
744-
} else {
745-
return ctrl.Result{}, err
746-
}
747-
} else {
748-
Log.Info("Retrieved existing map, updating..")
749-
nodeConfigMap.Data = foundMap.Data
750-
}
751-
752728
//
753729
// Predictable IPs.
754730
//
@@ -760,6 +736,28 @@ func (r *DesignateReconciler) reconcileNormal(ctx context.Context, instance *des
760736
if err != nil {
761737
return ctrl.Result{}, err
762738
}
739+
740+
// Fetch allocated ips from Mdns and Bind config maps and store them in allocatedIPs
741+
mdnsLabels := labels.GetLabels(instance, labels.GetGroupLabel(instance.ObjectMeta.Name), map[string]string{})
742+
mdnsConfigMap, err := r.handleConfigMap(ctx, helper, instance, designate.MdnsPredIPConfigMap, mdnsLabels)
743+
if err != nil {
744+
return ctrl.Result{}, err
745+
}
746+
747+
bindLabels := labels.GetLabels(instance, labels.GetGroupLabel(instance.ObjectMeta.Name), map[string]string{})
748+
bindConfigMap, err := r.handleConfigMap(ctx, helper, instance, designate.BindPredIPConfigMap, bindLabels)
749+
if err != nil {
750+
return ctrl.Result{}, err
751+
}
752+
753+
allocatedIPs := make(map[string]bool)
754+
for _, predIP := range bindConfigMap.Data {
755+
allocatedIPs[predIP] = true
756+
}
757+
for _, predIP := range mdnsConfigMap.Data {
758+
allocatedIPs[predIP] = true
759+
}
760+
763761
// Get a list of the nodes in the cluster
764762

765763
// TODO(oschwart):
@@ -772,54 +770,51 @@ func (r *DesignateReconciler) reconcileNormal(ctx context.Context, instance *des
772770
if err != nil {
773771
return ctrl.Result{}, err
774772
}
775-
updatedMap := make(map[string]string)
776-
allocatedIPs := make(map[string]bool)
777-
var predictableIPsRequired []string
778773

779-
// First scan existing allocations so we can keep existing allocations.
780-
// Keeping track of what's required and what already exists. If a node is
781-
// removed from the cluster, it's IPs will not be added to the allocated
782-
// list and are effectively recycled.
774+
var nodeNames []string
783775
for _, node := range nodes.Items {
784-
nodeName := fmt.Sprintf("mdns_%s", node.Name)
785-
if ipValue, ok := nodeConfigMap.Data[nodeName]; ok {
786-
updatedMap[nodeName] = ipValue
787-
allocatedIPs[ipValue] = true
788-
Log.Info(fmt.Sprintf("%s has IP mapping %s: %s", node.Name, nodeName, ipValue))
789-
} else {
790-
predictableIPsRequired = append(predictableIPsRequired, nodeName)
791-
}
776+
nodeNames = append(nodeNames, fmt.Sprintf("mdns_%s", node.Name))
792777
}
793-
// Get new IPs using the range from predictableIPParmas minus the
794-
// allocatedIPs captured above.
795-
Log.Info(fmt.Sprintf("Allocating %d predictable IPs", len(predictableIPsRequired)))
796-
for _, nodeName := range predictableIPsRequired {
797-
nodeIP, err := designate.GetNextIP(predictableIPParams, allocatedIPs)
798-
if err != nil {
799-
// An error here is really unexpected- it means either we have
800-
// messed up the allocatedIPs list or the range we are assuming is
801-
// too small for the number of mdns pod.
802-
return ctrl.Result{}, err
803-
}
804-
updatedMap[nodeName] = nodeIP
778+
779+
updatedMap, allocatedIPs, err := r.allocatePredictableIPs(ctx, predictableIPParams, nodeNames, mdnsConfigMap.Data, allocatedIPs)
780+
if err != nil {
781+
return ctrl.Result{}, err
805782
}
806783

807-
mapLabels := labels.GetLabels(instance, labels.GetGroupLabel(instance.ObjectMeta.Name), map[string]string{})
808-
_, err = controllerutil.CreateOrPatch(ctx, helper.GetClient(), nodeConfigMap, func() error {
809-
nodeConfigMap.Labels = util.MergeStringMaps(nodeConfigMap.Labels, mapLabels)
810-
nodeConfigMap.Data = updatedMap
811-
err := controllerutil.SetControllerReference(instance, nodeConfigMap, helper.GetScheme())
812-
if err != nil {
813-
return err
814-
}
815-
return nil
784+
_, err = controllerutil.CreateOrPatch(ctx, helper.GetClient(), mdnsConfigMap, func() error {
785+
mdnsConfigMap.Labels = util.MergeStringMaps(mdnsConfigMap.Labels, mdnsLabels)
786+
mdnsConfigMap.Data = updatedMap
787+
return controllerutil.SetControllerReference(instance, mdnsConfigMap, helper.GetScheme())
816788
})
817789

818790
if err != nil {
819791
Log.Info("Unable to create config map for mdns ips...")
820792
return ctrl.Result{}, err
821793
}
822794

795+
// Handle Bind predictable IPs configmap
796+
bindReplicaCount := int(*instance.Spec.DesignateBackendbind9.Replicas)
797+
var bindNames []string
798+
for i := 0; i < bindReplicaCount; i++ {
799+
bindNames = append(bindNames, fmt.Sprintf("bind_address_%d", i))
800+
}
801+
802+
updatedBindMap, _, err := r.allocatePredictableIPs(ctx, predictableIPParams, bindNames, bindConfigMap.Data, allocatedIPs)
803+
if err != nil {
804+
return ctrl.Result{}, err
805+
}
806+
807+
_, err = controllerutil.CreateOrPatch(ctx, helper.GetClient(), bindConfigMap, func() error {
808+
bindConfigMap.Labels = util.MergeStringMaps(bindConfigMap.Labels, bindLabels)
809+
bindConfigMap.Data = updatedBindMap
810+
return controllerutil.SetControllerReference(instance, bindConfigMap, helper.GetScheme())
811+
})
812+
813+
if err != nil {
814+
Log.Info("Unable to create config map for bind ips...")
815+
return ctrl.Result{}, err
816+
}
817+
823818
// deploy designate-central
824819
designateCentral, op, err := r.centralDeploymentCreateOrUpdate(ctx, instance)
825820
if err != nil {
@@ -1082,6 +1077,72 @@ func (r *DesignateReconciler) reconcileNormal(ctx context.Context, instance *des
10821077
return ctrl.Result{}, nil
10831078
}
10841079

1080+
func (r *DesignateReconciler) handleConfigMap(ctx context.Context, helper *helper.Helper, instance *designatev1beta1.Designate, configMapName string, labels map[string]string) (*corev1.ConfigMap, error) {
1081+
Log := r.GetLogger(ctx)
1082+
1083+
nodeConfigMap := &corev1.ConfigMap{
1084+
ObjectMeta: metav1.ObjectMeta{
1085+
Name: configMapName,
1086+
Namespace: instance.GetNamespace(),
1087+
Labels: labels,
1088+
},
1089+
Data: make(map[string]string),
1090+
}
1091+
1092+
// Look for existing config map and if exists, read existing data and match
1093+
// against nodes.
1094+
foundMap := &corev1.ConfigMap{}
1095+
err := helper.GetClient().Get(ctx, types.NamespacedName{Name: configMapName, Namespace: instance.GetNamespace()}, foundMap)
1096+
if err != nil {
1097+
if k8s_errors.IsNotFound(err) {
1098+
Log.Info(fmt.Sprintf("Ip map %s doesn't exist, creating.", configMapName))
1099+
} else {
1100+
return nil, err
1101+
}
1102+
} else {
1103+
Log.Info("Retrieved existing map, updating..")
1104+
nodeConfigMap.Data = foundMap.Data
1105+
}
1106+
1107+
return nodeConfigMap, nil
1108+
}
1109+
1110+
func (r *DesignateReconciler) allocatePredictableIPs(ctx context.Context, predictableIPParams *designate.NADIpam, ipHolders []string, existingMap map[string]string, allocatedIPs map[string]bool) (map[string]string, map[string]bool, error) {
1111+
Log := r.GetLogger(ctx)
1112+
1113+
updatedMap := make(map[string]string)
1114+
var predictableIPsRequired []string
1115+
1116+
// First scan existing allocations so we can keep existing allocations.
1117+
// Keeping track of what's required and what already exists. If a node is
1118+
// removed from the cluster, it's IPs will not be added to the allocated
1119+
// list and are effectively recycled.
1120+
for _, ipHolder := range ipHolders {
1121+
if ipValue, ok := existingMap[ipHolder]; ok {
1122+
updatedMap[ipHolder] = ipValue
1123+
Log.Info(fmt.Sprintf("%s has IP mapping: %s", ipHolder, ipValue))
1124+
} else {
1125+
predictableIPsRequired = append(predictableIPsRequired, ipHolder)
1126+
}
1127+
}
1128+
1129+
// Get new IPs using the range from predictableIPParmas minus the
1130+
// allocatedIPs captured above.
1131+
Log.Info(fmt.Sprintf("Allocating %d predictable IPs", len(predictableIPsRequired)))
1132+
for _, nodeName := range predictableIPsRequired {
1133+
ipAddress, err := designate.GetNextIP(predictableIPParams, allocatedIPs)
1134+
if err != nil {
1135+
// An error here is really unexpected- it means either we have
1136+
// messed up the allocatedIPs list or the range we are assuming is
1137+
// too small for the number of mdns pod.
1138+
return nil, nil, err
1139+
}
1140+
updatedMap[nodeName] = ipAddress
1141+
}
1142+
1143+
return updatedMap, allocatedIPs, nil
1144+
}
1145+
10851146
func (r *DesignateReconciler) reconcileUpdate(ctx context.Context, instance *designatev1beta1.Designate) (ctrl.Result, error) {
10861147
Log := r.GetLogger(ctx)
10871148

pkg/designate/bind_ctrl_network.go

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,12 @@ func GetPredictableIPAM(networkParameters *NetworkParameters) (*NADIpam, error)
3636
return predParams, nil
3737
}
3838

39-
// GetNextIP picks the next available IP from the range defined by a NADIpam,
40-
// skipping ones that are already used appear as keys in the currentValues map.
41-
func GetNextIP(predParams *NADIpam, currentValues map[string]bool) (string, error) {
42-
candidateAddress := predParams.RangeStart
43-
for alloced := true; alloced; {
44-
45-
if _, ok := currentValues[candidateAddress.String()]; ok {
46-
if candidateAddress == predParams.RangeEnd {
47-
return "", fmt.Errorf("predictable IPs: out of available addresses")
48-
}
49-
candidateAddress = candidateAddress.Next()
50-
} else {
51-
alloced = false
39+
func GetNextIP(predParams *NADIpam, allocatedIPs map[string]bool) (string, error) {
40+
for candidateAddress := predParams.RangeStart; candidateAddress != predParams.RangeEnd; candidateAddress = candidateAddress.Next() {
41+
if !allocatedIPs[candidateAddress.String()] {
42+
allocatedIPs[candidateAddress.String()] = true
43+
return candidateAddress.String(), nil
5244
}
5345
}
54-
currentValues[candidateAddress.String()] = true
55-
return candidateAddress.String(), nil
46+
return "", fmt.Errorf("predictable IPs: out of available addresses")
5647
}

pkg/designate/const.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@ const (
4040
DesignateRndcKey = "rndc-key"
4141

4242
MdnsPredIPConfigMap = "designate-mdns-ip-map"
43+
44+
BindPredIPConfigMap = "designate-bind-ip-map"
4345
)

0 commit comments

Comments
 (0)