Skip to content

Labels & Filter Queries

This guide provides a comprehensive reference for SPOG's label system and GlassQL filter query language. Labels are the foundation of cluster organization, and filters enable you to select, group, and display clusters based on their labels.

What You'll Learn

  • How the label system works and how labels flow through SPOG
  • Best practices for designing label taxonomies
  • How to apply labels to clusters via Helm configuration
  • The complete GlassQL filter query syntax with all operators
  • Hands-on exercises using the quickstart deployment

Prerequisites

This guide assumes you have completed the Quickstart and have the three quickstart clusters running. All examples use these clusters to demonstrate filter behavior. For background on the overall system architecture, see the Architecture Overview.


The Label System

What Are Labels?

Labels are key-value pairs attached to clusters that describe their identity and organizational role. In SPOG, labels enable:

  • Multi-dimensional organization: Categorize clusters by region, environment, team, tier, or any custom dimension
  • Flexible filtering: Select clusters based on any combination of label values
  • Authorization boundaries: Grant access based on label matching (covered in the authorization guide)
  • Dynamic permissions: Combine with route parameters to create team-based dashboards that automatically filter by label values (see Dynamic Permission Arguments)
  • Custom taxonomies: Define labels that match your specific organizational structure

Label Syntax

Labels are specified in YAML as key-value pairs. Values can be a single string or an array of strings:

YAML
1
2
3
4
5
6
labels:
  region: "us-east"           # Single value
  environment: "production"   # Single value
  team:                        # Multiple values (cluster managed by multiple teams)
    - "platform"
    - "security"

Reserved Label Keys

The following keywords are reserved and should not be used as label keys:

Keyword Reason
and, or, not Boolean operators in GlassQL filter queries
in, like, contains Comparison operators in GlassQL
group, by Grouping keywords in GlassQL
cluster_id Special field representing the cluster identifier

Using these as label keys will generate runtime warnings and may cause unexpected behavior when filtering. For example, if you had a label and: "value", the query and = "value" would be ambiguous to the parser.

Reserved Keyword Detection

SPOG services will log warnings at startup if reserved keywords are detected in label configurations. While clusters will still function, filter queries involving these labels may not work as expected.

Multi-Valued Labels

Some organizational scenarios require a cluster to belong to multiple values for a single dimension. For example:

  • A cluster managed by multiple teams
  • A cluster serving multiple customers
  • A cluster spanning multiple availability zones

When filtering, multi-valued labels match if any of the values match the filter condition. For example, team = "security" will match a cluster with team: ["platform", "security"].

Labels Are Completely Arbitrary

SPOG doesn't enforce any specific label schema. The label keys and values shown in these examples (region, environment, team, etc.) are illustrative. You can define any labels that match your organizational structure.

How Labels Flow Through SPOG

Labels propagate through the system in the following way:

  1. Cluster Definition: Labels are defined in the Glass Instrumentation Helm values
  2. NATS Discovery: Clusters announce themselves with their labels to the control plane
  3. Backend Registry: The middleware service maintains a registry of all clusters and their labels
  4. Frontend Store: The UI fetches cluster data including labels for display and filtering
  5. Filter Evaluation: GlassQL queries match clusters based on their label values

Label Design Principles

Follow these principles when designing your label taxonomy:

1. Keep Labels Simple and Consistent

Use the same label keys across all clusters. This enables reliable filtering and grouping.

YAML
# Good: Consistent labels across clusters
labels:
  region: "us-east"
  environment: "production"
  team: "platform"

# Avoid: Inconsistent naming
labels:
  reg: "us-east"      # Abbreviated
  env: "prod"         # Abbreviated
  department: "plat"  # Different key name

2. Use Meaningful, Human-Readable Values

Label values appear in the UI and filter autocomplete. Make them descriptive.

YAML
1
2
3
4
5
6
7
8
9
# Good: Clear, readable values
labels:
  environment: "production"
  tier: "critical"

# Avoid: Cryptic abbreviations
labels:
  environment: "prd"
  tier: "t1"

3. Limit to 5-7 Dimensions

Too many labels create confusion. Focus on the dimensions that matter for filtering and access control.

4. Plan for Growth

Consider how your organization might evolve. Will you add new regions? New teams? Design labels that can accommodate growth.

5. Document Your Taxonomy

Maintain a reference document that defines each label key, its allowed values, and when to use each value.


Design Patterns

Single-Dimension Organization

Organize clusters by a single primary dimension, typically region or team:

YAML
1
2
3
4
5
6
7
# Region-based organization
labels:
  region: "us-east"

# Team-based organization
labels:
  team: "platform"

Use when: You have a simple infrastructure with one clear organizational axis.

Multi-Dimensional Hierarchy

Combine multiple dimensions for richer organization:

YAML
1
2
3
4
5
labels:
  region: "us-east"
  environment: "production"
  team: "platform"
  tier: "critical"

Use when: You need to filter by multiple criteria (e.g., "all production clusters in US regions owned by the platform team").

Team-Based Isolation

Organize clusters by team ownership with environment sub-classification:

YAML
1
2
3
4
5
6
7
8
9
# DevOps team production cluster
labels:
  team: "devops"
  environment: "production"

# Platform team staging cluster
labels:
  team: "platform"
  environment: "staging"

Use when: Teams have distinct ownership boundaries and need separate views of their infrastructure.

Multi-Valued Labels for Shared Ownership

When a cluster is managed by multiple teams or serves multiple purposes, use array values:

YAML
1
2
3
4
5
6
7
8
# Cluster managed by both platform and security teams
labels:
  region: "us-east"
  environment: "production"
  team:
    - "platform"
    - "security"
  tier: "critical"

This cluster will appear when filtering for either team:

  • team = "platform" → matches
  • team = "security" → matches
  • team in ("platform", "devops") → matches (platform is in the set)

Use when: Clusters have shared ownership, serve multiple customers, or span multiple availability zones. Multi-valued labels enable flexible filtering without duplicating cluster definitions.


Applying Labels

Via Helm Configuration

Labels are applied through the Glass Instrumentation Helm chart. Each cluster where you install glass-instrumentation gets its own values file specifying the cluster ID and labels:

YAML
1
2
3
4
5
6
7
8
# values-my-cluster.yaml
clusterId: "my-cluster"
labels:
  environment: "production"
  region: "us-east"
  role: "dns"
  team: "platform"
  tier: "critical"

To assign multiple values to a label, use YAML array syntax:

YAML
# values-shared-cluster.yaml
clusterId: "shared-cluster"
labels:
  environment: "production"
  region: "us-east"
  role: "dns"
  team:                        # Cluster managed by multiple teams
    - "platform"
    - "security"
  tier: "critical"

Both single-value strings and arrays are supported for any label. The Helm chart automatically formats them correctly for the discovery service.

Quickstart Cluster Labels

The quickstart deployment includes three clusters with the following labels:

quickstart-1 (US East Production, multi-team):

YAML
1
2
3
4
5
6
7
8
9
clusterId: "quickstart-1"
labels:
  environment: "production"
  region: "us-east"
  role: "dns"
  team:
    - "platform"
    - "security"
  tier: "critical"

Multi-Valued Team Label

Notice that quickstart-1 demonstrates multi-valued labels with team assigned to both "platform" and "security". This cluster will match filters for either team: team = "platform" or team = "security".

quickstart-2 (US West Production):

YAML
1
2
3
4
5
6
7
clusterId: "quickstart-2"
labels:
  environment: "production"
  region: "us-west"
  role: "dns"
  team: "platform"
  tier: "standard"

quickstart-3 (EU West Development):

YAML
1
2
3
4
5
6
7
clusterId: "quickstart-3"
labels:
  environment: "development"
  region: "eu-west"
  role: "dns"
  team: "infrastructure"
  tier: "standard"

This gives you a realistic multi-cluster environment for practicing filter queries:

Cluster region environment team tier
quickstart-1 us-east production platform, security critical
quickstart-2 us-west production platform standard
quickstart-3 eu-west development infrastructure standard

GlassQL Filter Query Language

GlassQL is SPOG's filter query language for selecting and grouping clusters based on their labels. It uses a SQL-like syntax that's intuitive for anyone familiar with database queries.

When to Use Filters

  • Interactive filtering: Type queries in the Glass UI filter input to narrow the cluster list
  • Dashboard widgets: Configure widgets to show specific cluster subsets
  • Programmatic selection: Use filters in API calls to target specific clusters

Query Anatomy

A GlassQL query consists of:

  1. Conditions: Label comparisons (e.g., region = "us-east")
  2. Logical operators: Combine conditions (and, or, not)
  3. Grouping clause (optional): Organize results (group by)
Text Only
[conditions] [group by labels]

Technical Specifications

Case Sensitivity: All label keys and values are case-sensitive. region = "US-East" will not match region: "us-east".

Quoting Requirements: String values containing spaces or special characters must be enclosed in double quotes:

Text Only
1
2
3
team = "dev ops"           # Required - contains space
description = "Primary cluster"  # Required - contains space
region = "us-east"         # Quotes optional but recommended

Reserved Keywords: The following are reserved and cannot be used as label keys without special handling: - and, or, not - in, like, contains - group, by - cluster_id (special field, not a label)


Comparison Operators

Equality: = and !=

Match exact label values:

Text Only
region = "us-east"
quickstart-1

Text Only
environment != "production"
quickstart-3

The equality operators perform exact string matching. Values are case-sensitive. For multi-valued labels, a cluster matches if any of its values equals the filter value.

Set Membership: in and not in

Match any value from a set:

Text Only
region in ("us-east", "us-west")
quickstart-1, quickstart-2

Exclude values from a set:

Text Only
tier not in ("experimental", "deprecated")
quickstart-1, quickstart-2, quickstart-3 (all match since none have those tiers)

The in operator is useful when you want to match multiple possible values for a label. For multi-valued labels, a cluster matches if any of its values is in the filter set.

Pattern Matching: like and not like

Match using glob patterns with * (any characters) and ? (single character):

Text Only
region like "us-*"
quickstart-1, quickstart-2

Text Only
cluster_id not like "*-3"
quickstart-1, quickstart-2

Pattern matching is useful for:

  • Matching regions by prefix: region like "us-*" (all US regions)
  • Matching clusters by naming convention: cluster_id like "prod-*"
  • Excluding test clusters: cluster_id not like "*-test"

Escaping Special Characters: If your label values contain literal * or ? characters, you cannot escape them in the current implementation. Consider using the contains operator or exact equality matching instead.

Substring Matching: contains and not contains

Check if a value contains a substring:

Text Only
team contains "plat"
quickstart-1, quickstart-2 (both have a team value containing "plat")

Text Only
region contains "west"
quickstart-2, quickstart-3

Numeric Comparison: <, >, <=, >=

Compare numeric label values:

Text Only
priority < 3
Text Only
replicas >= 2

Numeric operators parse label values as numbers. They're useful when you have labels like priority, replicas, or version that contain numeric values.

Non-Numeric Values

If a label value cannot be parsed as a number, the comparison will fail and the cluster will not match. For example, if priority = "high", then priority < 3 will not match that cluster. Ensure label values are numeric when using numeric comparison operators.


Logical Operators

AND: Both Conditions Must Match

Text Only
environment = "production" and team = "platform"
quickstart-1, quickstart-2

Both conditions must be true for a cluster to match.

OR: Either Condition Matches

Text Only
region = "us-east" or region = "eu-west"
quickstart-1, quickstart-3

Either condition can be true for a cluster to match.

NOT: Negate a Condition

Text Only
not (environment = "development")
quickstart-1, quickstart-2

Inverts the match result. Note the parentheses around the condition being negated.


Combining Conditions & Operator Precedence

When combining multiple operators, SPOG evaluates them in this order (highest precedence first):

  1. Parentheses ()
  2. not
  3. Comparison operators (=, !=, in, like, etc.)
  4. and
  5. or

Example: Without parentheses

Text Only
region = "us-east" or region = "us-west" and environment = "production"

Due to operator precedence, this evaluates as: region = "us-east" or (region = "us-west" and environment = "production")

Step-by-step evaluation for each cluster:

  • quickstart-1 (region: "us-east", environment: "production"):
  • First condition: region = "us-east"TRUE
  • OR operator: Since first condition is true, entire query is TRUE

  • quickstart-2 (region: "us-west", environment: "production"):

  • First condition: region = "us-east" → FALSE
  • Second condition: region = "us-west" → TRUE
  • Third condition: environment = "production" → TRUE
  • Second AND third: TRUE and TRUE → TRUE
  • OR operator: FALSE or TRUE → TRUE

  • quickstart-3 (region: "eu-west", environment: "development"):

  • First condition: region = "us-east" → FALSE
  • Second condition: region = "us-west" → FALSE
  • OR operator: FALSE or (FALSE and anything) → FALSE

Result: quickstart-1, quickstart-2

Example: With parentheses for clarity

Text Only
(region = "us-east" or region = "us-west") and environment = "production"

This ensures the OR is evaluated first, then the AND.

quickstart-1, quickstart-2 (both are in US regions AND are production)

Complex query example:

Text Only
(tier = "critical" and environment = "production") or team = "infrastructure"
quickstart-1 (critical + production), quickstart-3 (infrastructure team)

Use Parentheses for Clarity

Even when not strictly required, parentheses make your intent clear to future readers and prevent subtle bugs from precedence confusion.


Group By Clause

The group by clause organizes results into a hierarchical structure based on label values.

Basic Grouping

Text Only
environment = "production" group by region

Result structure:

JSON
1
2
3
4
{
  "us-east": ["quickstart-1"],
  "us-west": ["quickstart-2"]
}

Multi-Level Grouping

Text Only
team = "platform" group by region, environment

Result structure:

JSON
1
2
3
4
5
6
7
8
{
  "us-east": {
    "production": ["quickstart-1"]
  },
  "us-west": {
    "production": ["quickstart-2"]
  }
}

Filter Then Group

Apply conditions first, then organize the results:

Text Only
tier in ("critical", "standard") group by tier, team

Groups clusters first by tier, then by team within each tier.

Widget-Specific Grouping Behavior

Different UI widgets interpret the group by clause in different ways:

  • Tree widgets (like cc-state-tree-table): Display a hierarchical tree with each group level as a parent node
  • Flat list widgets: May ignore grouping or display groups as section headers
  • Chart widgets: Use groups as data series or categories

Consult the widget documentation to understand how it uses grouping information.


Cluster ID Field

The special cluster_id field lets you query by cluster identity. This is not a label, but a built-in field available for all clusters:

Text Only
cluster_id = "quickstart-1"
quickstart-1

Text Only
cluster_id in ("quickstart-1", "quickstart-3")
quickstart-1, quickstart-3

Text Only
cluster_id like "quickstart-*"
quickstart-1, quickstart-2, quickstart-3

The cluster_id field supports all string comparison operators (=, !=, in, not in, like, not like, contains, not contains).

Simple Filters: Implicit Substring Matching

When you enter a simple string without any operators, GlassQL automatically treats it as a substring search against cluster_id. This enables very concise filtering:

Text Only
us
→ Internally becomes cluster_id contains "us"

This means typing just us will match clusters like us-east-prod-001, dns-us-west, or any cluster with "us" anywhere in its ID.

Leveraging Hierarchical Cluster IDs

This behavior becomes powerful when you adopt a hierarchical naming convention for cluster IDs:

YAML
1
2
3
4
5
# Example hierarchical naming: {region}-{environment}-{service}-{instance}
clusterId: "us-east-prod-dns-001"
clusterId: "us-west-prod-dns-002"
clusterId: "eu-central-staging-dns-001"
clusterId: "ap-north-dev-dns-001"

With this naming scheme, simple filters become very effective:

Filter Matches Description
us us-east-prod-dns-001, us-west-prod-dns-002 All US clusters
prod us-east-prod-dns-001, us-west-prod-dns-002 All production clusters
us-east us-east-prod-dns-001 US East region only
staging eu-central-staging-dns-001 Staging environment
001 us-east-prod-dns-001, eu-central-staging-dns-001, ap-north-dev-dns-001 First instance of each

Combine with Labels

While hierarchical cluster IDs enable quick filtering, labels are still recommended for structured organization and access control. Use simple cluster ID filters for quick exploration, and explicit label queries for dashboards and authorization policies.


Quick Reference

Operator Description Example
= Exact match region = "us-east"
!= Not equal environment != "production"
in Value in set region in ("us-east", "us-west")
not in Value not in set tier not in ("experimental")
like Glob pattern match region like "us-*"
not like Pattern exclusion cluster_id not like "*-test"
contains Substring match team contains "plat"
not contains No substring name not contains "backup"
<, >, <=, >= Numeric comparison priority < 3
and Logical AND env = "prod" and team = "platform"
or Logical OR region = "us-east" or region = "eu-west"
not Logical NOT not (env = "development")
group by Hierarchical grouping ... group by region, environment

Hands-On Exercises

These exercises use the quickstart deployment. If you haven't completed the quickstart, do so first.

Exercise 1: Explore Labels in the UI

Open the Glass UI and examine the quickstart clusters.

Tasks:

  1. Click the filter input field and start typing a few letters (e.g., reg) to see autocomplete suggestions
  2. Note which label keys are available (region, environment, team, tier, role)
  3. Continue typing region = and observe the value suggestions
  4. Identify which cluster has the critical tier
  5. Click on a label value in the tree table (e.g., click "us-east" under a cluster's region) to automatically populate a filter query

Click Labels to Filter

You can click on label values displayed in the tree table to quickly create filter queries. Clicking a single value creates an equality filter (region = "us-east"). Selections are persistent—clicking additional label values adds them to the filter, creating a set membership query (region in ("us-east", "us-west")). Click a selected value again to deselect it.

Expected Results
  • Available labels: region, environment, role, team, tier, cluster_id
  • Region values: us-east, us-west, eu-west
  • The cluster with tier: "critical" is quickstart-1

Exercise 2: Practice Filter Queries

Test these queries in the Glass UI filter input. After each query, verify which clusters are displayed.

Task 1: Show only production clusters

Query: environment = "production"

Expected Result
  • quickstart-1 and quickstart-2 are shown
  • quickstart-3 is hidden (it's development)

Task 2: Show US-based clusters

Query: region in ("us-east", "us-west")

Expected Result
  • quickstart-1 and quickstart-2 are shown
  • quickstart-3 is hidden (it's eu-west)

Task 3: Combine conditions - production AND platform team

Query: environment = "production" and team = "platform"

Expected Result
  • quickstart-1 and quickstart-2 are shown
  • Both are production environment AND owned by platform team

Task 4: Pattern match - regions starting with "us"

Query: region like "us-*"

Expected Result
  • quickstart-1 and quickstart-2 are shown
  • Matches any region starting with "us"

Task 5: Complex query - critical OR infrastructure team

Query: tier = "critical" or team = "infrastructure"

Expected Result
  • quickstart-1 (critical tier) and quickstart-3 (infrastructure team) are shown
  • quickstart-2 is hidden (standard tier, platform team)

Task 6: Query multi-valued labels - security team

Query: team = "security"

Expected Result
  • quickstart-1 is shown (has team: ["platform", "security"])
  • quickstart-2 and quickstart-3 are hidden (neither has "security" in their team label)
  • This demonstrates how multi-valued labels match: a cluster matches if any of its values match the filter

Task 7: Quick filter using cluster_id shorthand

Query: quick

Expected Result
  • quickstart-1, quickstart-2, and quickstart-3 are all shown
  • This simple string is automatically interpreted as cluster_id contains "quick"
  • Try start-1 to match only quickstart-1, or 2 to match quickstart-2

Exercise 3: Add a Fourth Cluster

Extend the quickstart by adding a fourth cluster with new label values.

Step 1: Create the values file

Create quickstart-4.yaml:

YAML
1
2
3
4
5
6
7
clusterId: "quickstart-4"
labels:
  environment: "staging"
  region: "ap-north"
  role: "dns"
  team: "devops"
  tier: "standard"

Step 2: Deploy the cluster

Bash
# Create namespace
kubectl create namespace quickstart-4

# Create registry credentials (if using private registry)
kubectl create secret docker-registry registry-credentials \
  --docker-server=registry.open-xchange.com \
  --docker-username="$REGISTRY_USERNAME" \
  --docker-password="$REGISTRY_PASSWORD" \
  --namespace=quickstart-4

# Deploy PowerDNS
helm install quickstart-4 \
  oci://registry.open-xchange.com/cloudcontrol/powerdns \
  --version "3.1.13" \
  --namespace quickstart-4 \
  -f helm/3rd-party-examples/powerdns/examples/quickstart.yaml

# Deploy Glass Instrumentation
helm install glass-instrumentation \
  oci://registry.open-xchange.com/cc-glass/glass-instrumentation \
  --version "1.0.0" \
  --namespace quickstart-4 \
  -f quickstart-4.yaml

Step 3: Verify in the UI

After deployment, verify the new cluster appears:

Text Only
region = "ap-north"
Expected Result
  • quickstart-4 appears as the only cluster matching ap-north

Step 4: Test new filter combinations

Now you have a staging cluster. Test these queries:

Text Only
environment = "staging"
quickstart-4 only

Text Only
environment != "production"
quickstart-3 (development), quickstart-4 (staging)

Text Only
team = "devops"
quickstart-4 only

Step 5: Cleanup (Optional)

To remove the fourth cluster when you're done experimenting:

Bash
1
2
3
4
5
6
7
8
# Remove Glass Instrumentation
helm uninstall glass-instrumentation --namespace quickstart-4

# Remove PowerDNS
helm uninstall quickstart-4 --namespace quickstart-4

# Delete namespace
kubectl delete namespace quickstart-4

Best Practices & Troubleshooting

Best Practices

Label Naming Conventions

Guideline Good Example Avoid
Use lowercase environment: "production" Environment: "Production"
Use hyphens for multi-word values region: "us-east" region: "us east"
Be consistent across clusters All use environment Mix of env, environment, stage
Use full words environment env

Taxonomy Planning Checklist

Before deploying SPOG to production, document your label taxonomy:

  • List all label keys you'll use
  • Define allowed values for each key
  • Document which labels are required vs optional
  • Specify who owns/maintains each label
  • Plan how labels map to access control policies

Common Pitfalls to Avoid

  1. Inconsistent label keys: Using env in some clusters and environment in others
  2. Too many labels: Creating labels that aren't used for filtering or access control
  3. Changing labels frequently: Labels should be stable; frequent changes break filters
  4. Forgetting quotes: region = us-east fails; use region = "us-east"