Skip to content

Commit dae2b1a

Browse files
committed
Add optional cluster-name-suffix label support for remote clusters
- Remove ClusterNameSuffix field from Dashboard CRD spec - Add support for cluster-name-suffix label in remoteClusters clusterLabels - Suffix is only applied when label is set (opt-in behavior) - Update config.go to read suffix from resource labels - Simplify API by removing *WithSuffix functions - Update tests to use label-based approach - Update dashboard-shared.yaml to use cluster-name-suffix labels - Update README documentation with new configuration format This allows users to manually define custom suffixes per cluster (e.g., ' (ottawa)', ' [prod]') without template interpolation. If the label is not set, no suffix is added to service names.
1 parent ddcd63f commit dae2b1a

File tree

3 files changed

+190
-5
lines changed

3 files changed

+190
-5
lines changed

README.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -724,16 +724,33 @@ spec:
724724
- "api.example.com" # API endpoints
725725
```
726726

727-
**Automatic Cluster Tagging:**
728-
Services from remote clusters automatically get badge tags with the cluster name. Customize colors using the `cluster-tagstyle` label:
727+
**Cluster Name Suffix:**
728+
Append custom suffixes to service display names to distinguish items from different clusters. Configure using the `cluster-name-suffix` label in `clusterLabels`:
729+
730+
```yaml
731+
remoteClusters:
732+
- name: ottawa
733+
clusterLabels:
734+
cluster-name-suffix: " (ottawa)" # -> "Service Name (ottawa)"
735+
# Other formats:
736+
# " - ottawa" -> "Service Name - ottawa"
737+
# " [ottawa]" -> "Service Name [ottawa]"
738+
```
739+
740+
This suffix is only applied to items from **remote clusters**, not the local cluster. If the label is not set, no suffix is appended.
741+
742+
**Automatic Cluster Tagging (Optional):**
743+
Services from remote clusters can also get badge tags with the cluster name when `cluster-tagstyle` is set in `clusterLabels`. Available colors:
729744
- `is-danger` (red) - production
730745
- `is-warning` (yellow) - staging
731-
- `is-info` (blue, default) - development
732-
- `is-success` (green) - QA
746+
- `is-info` (blue) - development
747+
- `is-success` (green) - QA/testing
733748
- `is-light` (gray) - deprecated
734749

750+
**Important:** Tags are only added when `cluster-tagstyle` is explicitly configured. You can use both suffix and tags, or just one approach for cluster identification.
751+
735752
**Per-Cluster Domain Filtering:**
736-
Each cluster can have independent `domainFilters` to control which services are discovered. If not specified, inherits from the main `spec.domainFilters`.
753+
Each cluster can have independent `domainFilters` to control which services are discovered. If not specified for a remote cluster, no domain filtering is applied (all resources pass through). Dashboard-level `spec.domainFilters` only applies to the local cluster.
737754

738755
### Status Monitoring
739756

pkg/homer/cluster_tag_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,155 @@ func TestClusterTagNotOverriddenByAnnotations(t *testing.T) {
281281
t.Errorf("Expected manual tagstyle 'is-danger', got %q", tagstyle)
282282
}
283283
}
284+
285+
// TestClusterNameSuffix verifies that cluster name suffix is appended to item names from label
286+
func TestClusterNameSuffix(t *testing.T) {
287+
tests := []struct {
288+
name string
289+
clusterAnnot string
290+
clusterNameSuffix string // stored in label
291+
expectedNameSuffix string
292+
}{
293+
{
294+
name: "Remote cluster with suffix in parentheses",
295+
clusterAnnot: "ottawa",
296+
clusterNameSuffix: " (ottawa)",
297+
expectedNameSuffix: " (ottawa)",
298+
},
299+
{
300+
name: "Remote cluster with dash suffix",
301+
clusterAnnot: "production",
302+
clusterNameSuffix: " - production",
303+
expectedNameSuffix: " - production",
304+
},
305+
{
306+
name: "Remote cluster with bracket suffix",
307+
clusterAnnot: "staging",
308+
clusterNameSuffix: " [staging]",
309+
expectedNameSuffix: " [staging]",
310+
},
311+
{
312+
name: "Remote cluster without suffix label",
313+
clusterAnnot: "ottawa",
314+
clusterNameSuffix: "",
315+
},
316+
{
317+
name: "Local cluster with suffix label (should not apply)",
318+
clusterAnnot: "local",
319+
clusterNameSuffix: " (local)",
320+
},
321+
}
322+
323+
for _, tt := range tests {
324+
t.Run(tt.name, func(t *testing.T) {
325+
// Test with Ingress
326+
ingress := &networkingv1.Ingress{
327+
ObjectMeta: metav1.ObjectMeta{
328+
Name: "test-ingress",
329+
Namespace: "default",
330+
Annotations: map[string]string{},
331+
Labels: map[string]string{},
332+
},
333+
Spec: networkingv1.IngressSpec{
334+
Rules: []networkingv1.IngressRule{
335+
{Host: "test.example.com"},
336+
},
337+
},
338+
}
339+
340+
if tt.clusterAnnot != "" {
341+
ingress.ObjectMeta.Annotations["homer.rajsingh.info/cluster"] = tt.clusterAnnot
342+
}
343+
344+
if tt.clusterNameSuffix != "" {
345+
ingress.ObjectMeta.Labels["cluster-name-suffix"] = tt.clusterNameSuffix
346+
}
347+
348+
config := &HomerConfig{
349+
Title: "Test Dashboard",
350+
Header: true,
351+
}
352+
353+
UpdateHomerConfigIngress(config, *ingress, nil)
354+
355+
if len(config.Services) == 0 {
356+
t.Fatal("Expected at least one service")
357+
}
358+
359+
service := config.Services[0]
360+
if len(service.Items) == 0 {
361+
t.Fatal("Expected at least one item")
362+
}
363+
364+
item := service.Items[0]
365+
itemName := item.Parameters["name"]
366+
baseName := "test-ingress"
367+
368+
if tt.expectedNameSuffix != "" {
369+
expectedName := baseName + tt.expectedNameSuffix
370+
if itemName != expectedName {
371+
t.Errorf("Expected name %q, got %q", expectedName, itemName)
372+
}
373+
} else {
374+
// Should not have suffix
375+
if itemName != baseName {
376+
t.Errorf("Expected name %q without suffix, got %q", baseName, itemName)
377+
}
378+
}
379+
380+
// Test with HTTPRoute
381+
hostname := gatewayv1.Hostname("test.example.com")
382+
httproute := &gatewayv1.HTTPRoute{
383+
ObjectMeta: metav1.ObjectMeta{
384+
Name: "test-httproute",
385+
Namespace: "default",
386+
Annotations: map[string]string{},
387+
Labels: map[string]string{},
388+
},
389+
Spec: gatewayv1.HTTPRouteSpec{
390+
Hostnames: []gatewayv1.Hostname{hostname},
391+
},
392+
}
393+
394+
if tt.clusterAnnot != "" {
395+
httproute.ObjectMeta.Annotations["homer.rajsingh.info/cluster"] = tt.clusterAnnot
396+
}
397+
398+
if tt.clusterNameSuffix != "" {
399+
httproute.ObjectMeta.Labels["cluster-name-suffix"] = tt.clusterNameSuffix
400+
}
401+
402+
config2 := &HomerConfig{
403+
Title: "Test Dashboard",
404+
Header: true,
405+
}
406+
407+
UpdateHomerConfigHTTPRoute(config2, httproute, nil)
408+
409+
if len(config2.Services) == 0 {
410+
t.Fatal("Expected at least one service")
411+
}
412+
413+
service2 := config2.Services[0]
414+
if len(service2.Items) == 0 {
415+
t.Fatal("Expected at least one item")
416+
}
417+
418+
item2 := service2.Items[0]
419+
itemName2 := item2.Parameters["name"]
420+
baseName2 := "test-httproute"
421+
422+
if tt.expectedNameSuffix != "" {
423+
expectedName2 := baseName2 + tt.expectedNameSuffix
424+
if itemName2 != expectedName2 {
425+
t.Errorf("Expected HTTPRoute name %q, got %q", expectedName2, itemName2)
426+
}
427+
} else {
428+
// Should not have suffix
429+
if itemName2 != baseName2 {
430+
t.Errorf("Expected HTTPRoute name %q without suffix, got %q", baseName2, itemName2)
431+
}
432+
}
433+
})
434+
}
435+
}

pkg/homer/config.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,14 @@ func createIngressItem(ingress networkingv1.Ingress, host string, validRuleCount
11611161
if validRuleCount > 1 {
11621162
name = ingress.ObjectMeta.Name + "-" + host
11631163
}
1164+
1165+
// Append cluster name suffix from label if set (only for remote clusters)
1166+
if clusterName, ok := ingress.ObjectMeta.Annotations["homer.rajsingh.info/cluster"]; ok && clusterName != "" && clusterName != "local" {
1167+
if suffix, hasSuffix := ingress.ObjectMeta.Labels["cluster-name-suffix"]; hasSuffix && suffix != "" {
1168+
name = name + suffix
1169+
}
1170+
}
1171+
11641172
setItemParameter(&item, "name", name)
11651173
setItemParameter(&item, "logo", IngressIconURL)
11661174
setItemParameter(&item, "subtitle", host)
@@ -1276,6 +1284,14 @@ func updateHomerConfigWithHTTPRoutes(
12761284
if len(filteredHostnames) > 1 {
12771285
name = httproute.ObjectMeta.Name + "-" + hostStr
12781286
}
1287+
1288+
// Append cluster name suffix from label if set (only for remote clusters)
1289+
if clusterName, ok := httproute.ObjectMeta.Annotations["homer.rajsingh.info/cluster"]; ok && clusterName != "" && clusterName != "local" {
1290+
if suffix, hasSuffix := httproute.ObjectMeta.Labels["cluster-name-suffix"]; hasSuffix && suffix != "" {
1291+
name = name + suffix
1292+
}
1293+
}
1294+
12791295
setItemParameter(&item, "name", name)
12801296

12811297
// Set metadata for conflict detection

0 commit comments

Comments
 (0)