From ebd12238e6add8cb0df822e32a750c625d8a5f1d Mon Sep 17 00:00:00 2001 From: Seth Malaki Date: Wed, 20 May 2026 09:19:29 +0100 Subject: [PATCH 1/2] Fill HEP policy recommendation docs gaps: selector syntax and status lifecycle Backfill two release-blocking gaps surfaced in EV-6623 against the HEP policy recommendation docs merged in #2658. hostEndpointSpec.selector had no Calico selector operator reference. Add a "Scope recommendations to specific hosts" section on the HEP page with a worked example and a common-pattern table, plus a "Selectors" section on the PolicyRecommendationScope reference page rendering the existing partial that was imported but unused. The policyrecommendation.tigera.io/status annotation lifecycle (Learning -> Stabilizing -> Stable) was undocumented. Add a "Track recommendation readiness" section on the HEP page with kubectl one-liners and a tip to wait for Stable before enforcing, and a paired "Annotations on generated recommendations" / "Recommendation status lifecycle" pair on the reference page that documents the full annotation family and the transitions driven by lastUpdated, interval, and stabilizationPeriod. Refs EV-6623. --- .../hep-policy-recommendations.mdx | 86 +++++++++++++++++++ .../resources/policyrecommendations.mdx | 47 +++++++++- 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx b/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx index 02873e2dcc..fb4cd7f882 100644 --- a/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx +++ b/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx @@ -66,8 +66,10 @@ to the staged and enforced global network policies in that tier. - [Enable host-policy recommendations](#enable-host-policy-recommendations) - [View recommended policies](#view-recommended-policies) +- [Scope recommendations to specific hosts](#scope-recommendations-to-specific-hosts) - [Tune global settings](#tune-global-settings) - [Manage the life cycle of recommendations](#manage-the-life-cycle-of-recommendations) +- [Track recommendation readiness](#track-recommendation-readiness) - [Confirm a recommendation is matching real traffic](#confirm-a-recommendation-is-matching-real-traffic) - [Disable host-policy recommendations](#disable-host-policy-recommendations) @@ -114,6 +116,40 @@ you can set — `Learn`, `Set`, or `Ignore` — tracked by the `projectcalico.org/spec.stagedAction` label and `spec.stagedAction` field. See [Manage the life cycle of recommendations](#manage-the-life-cycle-of-recommendations). +### Scope recommendations to specific hosts + +By default, every HostEndpoint in the cluster is eligible for +recommendations. To restrict the engine to a subset, set +`hostEndpointSpec.selector` to a Calico label-selector expression that +matches the HostEndpoint labels you want to cover. + +```bash +# Generate recommendations only for HostEndpoints labelled +# `environment=prod`. +kubectl patch policyrecommendationscope default --type=merge -p '{ + "spec": { + "hostEndpointSpec": { + "recommendationStatus": "Enabled", + "selector": "environment == '\''prod'\''" + } + } +}' +``` + +A few common patterns: + +| Goal | Expression | +| ------------------------------------------- | --------------------------------------------------------------------- | +| All HostEndpoints | `all()` (or omit `selector`) | +| Single label value | `role == 'edge'` | +| Any of several values | `role in { 'edge', 'gateway' }` | +| Label present, any value | `has(zone)` | +| Combined conditions | environment == 'prod' && !has(quarantined) | + +For the full operator reference — comparison, set membership, +substring, and boolean composition — see +[label selectors](../../reference/resources/policyrecommendations.mdx#selectors). + ### Tune global settings Two top-level fields on the @@ -283,6 +319,56 @@ kubectl delete globalnetworkpolicy.projectcalico.org On the next processing cycle, the engine creates a fresh staged recommendation in `Learn`. +### Track recommendation readiness + +In addition to the `stagedAction` lifecycle described above (which **you** +control), the engine reports its own view of each recommendation through +the `policyrecommendation.tigera.io/status` annotation on the staged +global network policy. Use it to know when a recommendation has settled +down enough to enforce. + +| Value | Meaning | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `Learning` | Engine is still actively adding or modifying rules from flow logs. This is the initial value and is reset whenever the engine changes the recommendation. | +| `Stabilizing` | Engine has not modified the recommendation for longer than `2 × interval`, but less than `stabilizationPeriod`. Rules look settled but the engine is still watching. | +| `Stable` | Engine has not modified the recommendation for longer than `stabilizationPeriod`. The recommendation is considered ready to enforce. | + +The status transitions are driven by the time since the engine last +modified the recommendation, not by elapsed time alone: + +- A host that suddenly sends new traffic mid-`Stabilizing` will be + knocked back to `Learning` while the engine incorporates the new + rules. +- The `stabilizationPeriod` and `interval` values in + [Tune global settings](#tune-global-settings) directly control how + quickly a recommendation can reach `Stable`. + +Read the annotation with `kubectl`: + +```bash +kubectl get stagedglobalnetworkpolicy.projectcalico.org \ + -o jsonpath='{.metadata.annotations.policyrecommendation\.tigera\.io/status}{"\n"}' +``` + +List the status of every host-policy recommendation at once: + +```bash +kubectl get stagedglobalnetworkpolicies.projectcalico.org \ + -l projectcalico.org/tier=hostendpoint-isolation \ + -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.policyrecommendation\.tigera\.io/status}{"\n"}{end}' +``` + +:::tip + +Wait for `Stable` before +[accepting](#activate-a-recommendation) and +[enforcing](#enforce-a-recommendation) a recommendation. Accepting a +recommendation while it is still `Learning` or `Stabilizing` pins the +current — possibly incomplete — set of rules and stops the engine from +refining it further. + +::: + ### Confirm a recommendation is matching real traffic Use `calicoctl get` with `--show-policy-activities` to check when the diff --git a/calico-enterprise/reference/resources/policyrecommendations.mdx b/calico-enterprise/reference/resources/policyrecommendations.mdx index 9601b93284..6db833d2ed 100644 --- a/calico-enterprise/reference/resources/policyrecommendations.mdx +++ b/calico-enterprise/reference/resources/policyrecommendations.mdx @@ -61,5 +61,50 @@ $ kubectl patch policyrecommendationscope default -p '{"spec":{"":" From 9bd89816a2dc7bab49447606c33c9a087c1b2d3b Mon Sep 17 00:00:00 2001 From: Seth Malaki Date: Wed, 20 May 2026 10:20:17 +0100 Subject: [PATCH 2/2] Address review feedback from @ctauchen and Copilot HEP page (hep-policy-recommendations.mdx): - Use plain "host endpoint" in generic prose; reserve `HostEndpoint` for the resource name (Chris). - Reword "matches the HostEndpoint labels you want to cover" to "matches the labels of the host endpoints you want to cover" (Chris). - Replace the inline kubectl patch that needed shell single-quote escapes (`'\''`) with a `--patch-file=/dev/stdin` heredoc carrying a YAML patch. Removes the escape question entirely (Chris). - Introduce the selector-pattern table with a descriptive sentence (Chris). - Rewrite the pattern-table "Goal" cells as imperatives that match the column header (Chris). - Replace "settled down enough to enforce" with "stopped changing long enough to be ready to enforce" (Chris). - Add an introductory sentence before the status-annotation table (Chris). - Tighten the Stabilizing row boundary from "but less than stabilizationPeriod" to "but no more than stabilizationPeriod" so it matches the source check `diff <= rec.stabilization` and the wording on the reference page (Copilot). - Replace "mid-Stabilizing will be knocked back" with "during a Stabilizing period returns to" (Chris). - Lowercase `Learning`/`Stabilizing` in the tip's prose so they read as states, not literals (Chris). Reference page (policyrecommendations.mdx): - Clarify that `lastUpdated` tracks the generated staged policy's spec, not the PolicyRecommendationScope spec (Copilot). - Apply the same clarification to the lifecycle intro that referenced "the spec" (Copilot). - Link the NamespaceSpec `selector` row to the new `#selectors` anchor so both selectors are reachable from the section that claims to document both (Copilot). Refs EV-6623. --- .../hep-policy-recommendations.mdx | 54 +++++++++---------- .../resources/policyrecommendations.mdx | 9 ++-- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx b/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx index fb4cd7f882..62816aac8b 100644 --- a/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx +++ b/calico-enterprise/network-policy/recommendations/hep-policy-recommendations.mdx @@ -118,33 +118,31 @@ See [Manage the life cycle of recommendations](#manage-the-life-cycle-of-recomme ### Scope recommendations to specific hosts -By default, every HostEndpoint in the cluster is eligible for +By default, every host endpoint in the cluster is eligible for recommendations. To restrict the engine to a subset, set `hostEndpointSpec.selector` to a Calico label-selector expression that -matches the HostEndpoint labels you want to cover. +matches the labels of the host endpoints you want to cover. ```bash -# Generate recommendations only for HostEndpoints labelled -# `environment=prod`. -kubectl patch policyrecommendationscope default --type=merge -p '{ - "spec": { - "hostEndpointSpec": { - "recommendationStatus": "Enabled", - "selector": "environment == '\''prod'\''" - } - } -}' +# Recommend policies only for host endpoints labelled environment=prod. +kubectl patch policyrecommendationscope default --type=merge --patch-file=/dev/stdin <<'EOF' +spec: + hostEndpointSpec: + recommendationStatus: Enabled + selector: environment == 'prod' +EOF ``` -A few common patterns: +This table shows common selector patterns for host endpoint policy +recommendations: -| Goal | Expression | -| ------------------------------------------- | --------------------------------------------------------------------- | -| All HostEndpoints | `all()` (or omit `selector`) | -| Single label value | `role == 'edge'` | -| Any of several values | `role in { 'edge', 'gateway' }` | -| Label present, any value | `has(zone)` | -| Combined conditions | environment == 'prod' && !has(quarantined) | +| Goal | Expression | +| ------------------------------------------------ | ---------------------------------------------------------------- | +| Match all host endpoints | `all()` (or omit `selector`) | +| Match a single label value | `role == 'edge'` | +| Match any of several values | `role in { 'edge', 'gateway' }` | +| Match host endpoints that carry a given label | `has(zone)` | +| Combine conditions with boolean operators | environment == 'prod' && !has(quarantined) | For the full operator reference — comparison, set membership, substring, and boolean composition — see @@ -324,21 +322,23 @@ recommendation in `Learn`. In addition to the `stagedAction` lifecycle described above (which **you** control), the engine reports its own view of each recommendation through the `policyrecommendation.tigera.io/status` annotation on the staged -global network policy. Use it to know when a recommendation has settled -down enough to enforce. +global network policy. Use it to know when a recommendation has stopped +changing long enough to be ready to enforce. + +This table describes the values the engine assigns to the +`policyrecommendation.tigera.io/status` annotation: | Value | Meaning | | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `Learning` | Engine is still actively adding or modifying rules from flow logs. This is the initial value and is reset whenever the engine changes the recommendation. | -| `Stabilizing` | Engine has not modified the recommendation for longer than `2 × interval`, but less than `stabilizationPeriod`. Rules look settled but the engine is still watching. | +| `Stabilizing` | Engine has not modified the recommendation for longer than `2 × interval`, but no more than `stabilizationPeriod`. Rules look settled but the engine is still watching. | | `Stable` | Engine has not modified the recommendation for longer than `stabilizationPeriod`. The recommendation is considered ready to enforce. | The status transitions are driven by the time since the engine last modified the recommendation, not by elapsed time alone: -- A host that suddenly sends new traffic mid-`Stabilizing` will be - knocked back to `Learning` while the engine incorporates the new - rules. +- A host that suddenly sends new traffic during a `Stabilizing` period + returns to `Learning` while the engine incorporates the new rules. - The `stabilizationPeriod` and `interval` values in [Tune global settings](#tune-global-settings) directly control how quickly a recommendation can reach `Stable`. @@ -363,7 +363,7 @@ kubectl get stagedglobalnetworkpolicies.projectcalico.org \ Wait for `Stable` before [accepting](#activate-a-recommendation) and [enforcing](#enforce-a-recommendation) a recommendation. Accepting a -recommendation while it is still `Learning` or `Stabilizing` pins the +recommendation while it is still learning or stabilizing pins the current — possibly incomplete — set of rules and stops the engine from refining it further. diff --git a/calico-enterprise/reference/resources/policyrecommendations.mdx b/calico-enterprise/reference/resources/policyrecommendations.mdx index 6db833d2ed..c8c8fb3290 100644 --- a/calico-enterprise/reference/resources/policyrecommendations.mdx +++ b/calico-enterprise/reference/resources/policyrecommendations.mdx @@ -52,7 +52,7 @@ $ kubectl patch policyrecommendationscope default -p '{"spec":{"":"