Skip to content

Commit 630d87a

Browse files
authored
Fix Config Generation when Pod has no IP Address (#6)
When a Pod was already created, but doesn't had an IP address assigned yet, the configuration only contained the port number instead of the full address of the Pod. We are no checking that the Pod has an IP address assigned and if this is not the case we skip the Pod. We also improved the update logic of the generated secret with the Parca configuration. Therefor we are checking the the list of Pod IPs is not empty and not equal to the list of Pod IPs saved in the status field of the ParcaScrapeConfig CR. Only when the Pod IPs are not equal to the saved list of Pod IPs we will update the configuration. For all other cases we skip the update.
1 parent 1ea7d6d commit 630d87a

File tree

3 files changed

+48
-14
lines changed

3 files changed

+48
-14
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,10 @@ This Makefile target will invoke controller-gen to generate the CRD manifests at
114114
Deploy the CRD and run the operator locally with the default Kubernetes config file present at `$HOME/.kube/config`:
115115

116116
```sh
117-
export PARCA_OPERATOR_CONFIG=parca.yaml
118-
export PARCA_OPERATOR_CONFIG_NAME=parca-generated
119-
export PARCA_OPERATOR_CONFIG_NAMESPACE=parca
117+
export PARCA_SCRAPECONFIG_RECONCILIATION_INTERVAL=1m
118+
export PARCA_SCRAPECONFIG_BASE_CONFIG=parca.yaml
119+
export PARCA_SCRAPECONFIG_FINAL_CONFIG_NAME=parca-generated
120+
export PARCA_SCRAPECONFIG_FINAL_CONFIG_NAMESPACE=parca
120121
121122
make run
122123
```

controllers/parcascrapeconfig/parcascrapeconfig.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,26 @@ func SetScrapeConfig(scrapeConfig parcav1alpha1.ParcaScrapeConfig, pods []corev1
152152
container := getContainerName(scrapeConfig.Spec.Port, pods)
153153

154154
for _, pod := range pods {
155-
scrapeConfig.Spec.ScrapeConfig.StaticConfigs = append(scrapeConfig.Spec.ScrapeConfig.StaticConfigs, parcav1alpha1.StaticConfig{
156-
Targets: []string{fmt.Sprintf("%s:%d", pod.Status.PodIP, scrapeConfig.Spec.Port)},
157-
Labels: map[string]string{
158-
"name": scrapeConfig.Name,
159-
"namespace": scrapeConfig.Namespace,
160-
"pod": pod.Name,
161-
"container": container,
162-
"node": pod.Spec.NodeName,
163-
},
164-
})
155+
if pod.Status.PodIP != "" {
156+
scrapeConfig.Spec.ScrapeConfig.StaticConfigs = append(scrapeConfig.Spec.ScrapeConfig.StaticConfigs, parcav1alpha1.StaticConfig{
157+
Targets: []string{fmt.Sprintf("%s:%d", pod.Status.PodIP, scrapeConfig.Spec.Port)},
158+
Labels: map[string]string{
159+
"name": scrapeConfig.Name,
160+
"namespace": scrapeConfig.Namespace,
161+
"pod": pod.Name,
162+
"container": container,
163+
"node": pod.Spec.NodeName,
164+
},
165+
})
166+
167+
podIPs = append(podIPs, fmt.Sprintf("%s:%d", pod.Status.PodIP, scrapeConfig.Spec.Port))
168+
}
169+
}
165170

166-
podIPs = append(podIPs, fmt.Sprintf("%s:%d", pod.Status.PodIP, scrapeConfig.Spec.Port))
171+
// When there are not Pod IPs or the Pod IPs are equal to the existing Pod IPs saved in the status of the CR we can
172+
// return nil and don't need to update the final configuration.
173+
if len(podIPs) == 0 || testPodIPsEq(podIPs, scrapeConfig.Status.PodIPs) {
174+
return nil, nil
167175
}
168176

169177
for i := 0; i < len(finalConfig.ScrapeConfigs); i++ {
@@ -192,6 +200,23 @@ func getContainerName(port int32, pods []corev1.Pod) string {
192200
return "unknown"
193201
}
194202

203+
// testPodIPsEq tests if the provided slices of Pod IPs are equal. We can simply check the length of the slices and
204+
// then iterate over the slices and compare the values, because the Kubernetes API will return the Pods always in the
205+
// same order.
206+
func testPodIPsEq(a, b []string) bool {
207+
if len(a) != len(b) {
208+
return false
209+
}
210+
211+
for i := range a {
212+
if a[i] != b[i] {
213+
return false
214+
}
215+
}
216+
217+
return true
218+
}
219+
195220
// DeleteScrapeConfig deletes the scrape configuration for the provided ParcaScrapeConfig.
196221
func DeleteScrapeConfig(scrapeConfig parcav1alpha1.ParcaScrapeConfig) error {
197222
if scrapeConfig.Spec.ScrapeConfig.JobName == "" {

controllers/parcascrapeconfig_controller.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ func (r *ParcaScrapeConfigReconciler) Reconcile(ctx context.Context, req ctrl.Re
142142
return ctrl.Result{RequeueAfter: reconciliationInterval}, err
143143
}
144144

145+
// If the SetScrapeConfig function returns nil, we don't need to update the Parca configuration secret, because no
146+
// Pods with an IP where found or the Pods where not changed since the last reconciliation loop.
147+
if podIPs == nil {
148+
reqLogger.Info("ParcaScrapeConfig must not be updated.")
149+
r.updateConditions(ctx, parcaScrapeConfig, parcaScrapeConfigUpdated, "Parca Configuration must not be updated", metav1.ConditionTrue, parcaScrapeConfig.Status.PodIPs)
150+
return ctrl.Result{RequeueAfter: reconciliationInterval}, nil
151+
}
152+
145153
// When the Parca configuration was updated, we can update the Parca configuration secret to include the new scrape
146154
// configuration.
147155
finalConfig, err := parcascrapeconfig.GetConfig()

0 commit comments

Comments
 (0)